diff --git a/.gitignore b/.gitignore index 667aaef..a71cd2b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -HELP.md target/ .mvn/wrapper/maven-wrapper.jar !**/src/main/**/target/ diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 592e44d..a2c022c 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -1,4 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1776256595415 + + + + + \ No newline at end of file diff --git a/HELP.md b/HELP.md deleted file mode 100644 index 8cb8c60..0000000 --- a/HELP.md +++ /dev/null @@ -1,18 +0,0 @@ -# Getting Started - -### Reference Documentation - -For further reference, please consider the following sections: - -* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html) -* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/3.5.14-SNAPSHOT/maven-plugin) -* [Create an OCI image](https://docs.spring.io/spring-boot/3.5.14-SNAPSHOT/maven-plugin/build-image.html) - -### Maven Parent overrides - -Due to Maven's design, elements are inherited from the parent POM to the project POM. -While most of the inheritance is fine, it also inherits unwanted elements like `` and `` from the -parent. -To prevent this, the project POM contains empty overrides for these elements. -If you manually switch to a different parent and actually want the inheritance, you need to remove those overrides. - diff --git a/pom.xml b/pom.xml index 6fe48a7..304dbcd 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,10 @@ org.springframework.boot spring-boot-starter-web + + org.apache.tomcat.embed + tomcat-embed-jasper + org.projectlombok @@ -126,4 +130,39 @@ + + + dev + + + + org.springframework.boot + spring-boot-maven-plugin + + + dev + + + + + + + + live + + + + org.springframework.boot + spring-boot-maven-plugin + + + live + + + + + + + + diff --git a/src/main/java/com/pandoli365/bibimbap/config/WebMvcConfig.java b/src/main/java/com/pandoli365/bibimbap/config/WebMvcConfig.java new file mode 100644 index 0000000..793e490 --- /dev/null +++ b/src/main/java/com/pandoli365/bibimbap/config/WebMvcConfig.java @@ -0,0 +1,14 @@ +package com.pandoli365.bibimbap.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebMvcConfig implements WebMvcConfigurer { + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/").setViewName("index"); + } +} diff --git a/src/main/java/com/pandoli365/bibimbap/game/GameCatalog.java b/src/main/java/com/pandoli365/bibimbap/game/GameCatalog.java new file mode 100644 index 0000000..c3dd4a2 --- /dev/null +++ b/src/main/java/com/pandoli365/bibimbap/game/GameCatalog.java @@ -0,0 +1,91 @@ +package com.pandoli365.bibimbap.game; + +/** + * 데모용 게임 메타데이터. DB 연동 시 저장소로 대체하면 됩니다. + */ +public final class GameCatalog { + + private GameCatalog() { + } + + public static final int COUNT = 20; + + public static final String[] NAMES = { + "별빛 정원", "던전 카페", "픽셀 레이서", "구름 위를 걷다", + "마지막 타임라인", "요리하는 용", "네온 시티", "작은 숲의 집", + "역전 재판인", "달무리 탐정", "코드 러너", "바다 노래", + "시간 상자", "불꽃 학원", "조용한 우주", "종이 비행기", + "거울 미로", "손끝 RPG", "노을 역", "꿈의 도서관" + }; + + public static final String[] CREATORS = { + "Studio Luna", "김민재", "PixelCat", "이하늘", + "Team Horizon", "별작업실", "NEON LAB", "숲그림", + "Court Games", "달무리", "dev.han", "wave.sound", + "BoxSoft", "학원제작소", "COSMOS", "PaperFly", + "mirror.inc", "손끝게임즈", "노을팀", "책벌레" + }; + + public static final int[] LIKE_COUNTS = { + 1284, 56, 8921, 234, + 1205, 445, 678, 9012, + 3400, 12, 567, 89, + 4456, 223, 7777, 156, + 990, 34, 2100, 888 + }; + + /** 제작자 한마디 (상세 페이지 하단) */ + public static final String[] CREATOR_NOTES = { + "밤하늘을 걸으며 힐링하고 싶어서 만들었습니다. 플레이 해 주셔서 감사합니다.", + "카페 던전은 사랑입니다. 버그 제보는 Git 이슈로 부탁드려요.", + "속도감 있는 레이싱! 컨트롤은 WASD, 모바일은 추후 지원 예정이에요.", + "구름 위를 걷는 기분을 WebGL로 담아봤습니다.", + "스토리에 집중했습니다. 엔딩까지 플레이해 주세요.", + "요리 도트에 진심입니다. 레시피 아이디어 환영합니다.", + "네온 사인이 마음에 드셨다면 별 하나 부탁드려요.", + "작은 집에서 시작하는 하루. 소소한 상호작용을 즐겨 주세요.", + "반전 스토리, 스포일러는 삼가 주세요!", + "추리는 끝이 없어요. 힌트는 커뮤니티에 올려 두었습니다.", + "코딩하듯 플레이하는 러너. PR도 환영합니다.", + "바다 소리를 들으며 플레이해 보세요. 이어폰 추천!", + "시간 루프가 헷갈리면 메모를 추천합니다.", + "학원물이지만 가볍게 즐겨 주세요.", + "우주는 넓고 할 일은 많습니다. 업데이트 예정이에요.", + "종이비행기처럼 가볍게 날아가 보세요.", + "거울 방향이 헷갈릴 수 있어요. 인내심을…", + "손끝으로 즐기는 턴제 RPG입니다.", + "노을이 지는 역에서 만나요.", + "책 속 세계로 오신 걸 환영합니다." + }; + + public static final String[] GIT_URLS = { + "https://github.com/example/starlight-garden", + "https://github.com/example/dungeon-cafe", + "https://github.com/example/pixel-racer", + "https://github.com/example/cloud-walk", + "https://github.com/example/last-timeline", + "https://github.com/example/cooking-dragon", + "https://github.com/example/neon-city", + "https://github.com/example/small-forest", + "https://github.com/example/court-game", + "https://github.com/example/moon-detective", + "https://github.com/example/code-runner", + "https://github.com/example/sea-song", + "https://github.com/example/time-box", + "https://github.com/example/flame-school", + "https://github.com/example/quiet-space", + "https://github.com/example/paper-plane", + "https://github.com/example/mirror-maze", + "https://github.com/example/fingertip-rpg", + "https://github.com/example/sunset-station", + "https://github.com/example/dream-library" + }; + + public static boolean isValidId(int id) { + return id >= 1 && id <= COUNT; + } + + public static int toIndex(int id) { + return id - 1; + } +} diff --git a/src/main/java/com/pandoli365/bibimbap/web/GameController.java b/src/main/java/com/pandoli365/bibimbap/web/GameController.java new file mode 100644 index 0000000..2020f3a --- /dev/null +++ b/src/main/java/com/pandoli365/bibimbap/web/GameController.java @@ -0,0 +1,38 @@ +package com.pandoli365.bibimbap.web; + +import com.pandoli365.bibimbap.game.GameCatalog; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; + +@Controller +public class GameController { + + /** + * Unity WebGL 빌드를 넣을 경로 예: /webgl/game-{id}/index.html + * 해당 폴더에 Build + TemplateData 를 두면 iframe 으로 로드됩니다. + */ + public static String webglUrlForGame(int gameId) { + return "/webgl/game-" + gameId + "/index.html"; + } + + @GetMapping("/game/{id}") + public String gameDetail(@PathVariable("id") int id, Model model) { + if (!GameCatalog.isValidId(id)) { + return "redirect:/"; + } + int idx = GameCatalog.toIndex(id); + model.addAttribute("gameId", id); + model.addAttribute("gameName", GameCatalog.NAMES[idx]); + model.addAttribute("creator", GameCatalog.CREATORS[idx]); + model.addAttribute("likeCount", GameCatalog.LIKE_COUNTS[idx]); + model.addAttribute("likeCountFormatted", String.format("%,d", GameCatalog.LIKE_COUNTS[idx])); + model.addAttribute("creatorNote", GameCatalog.CREATOR_NOTES[idx]); + model.addAttribute("gitUrl", GameCatalog.GIT_URLS[idx]); + /* 데모: 공통 플레이스홀더. 실제 빌드는 static/webgl/game-{id}/ 에 두고 아래 한 줄을 webglUrlForGame(id) 로 바꾸면 됩니다. */ + model.addAttribute("webglUrl", "/webgl/placeholder/index.html"); + model.addAttribute("webglDeployPath", webglUrlForGame(id)); + return "game-detail"; + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index cbec0c3..1863ff7 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,8 @@ spring.application.name=bibimbap + +# JSP 뷰 (루트에 두어 항상 로드되도록 함) +spring.mvc.view.prefix=/WEB-INF/views/ +spring.mvc.view.suffix=.jsp + +spring.profiles.active=dev +spring.config.import=optional:classpath:dev/application.properties diff --git a/src/main/resources/dev/application.properties b/src/main/resources/dev/application.properties index 1f4758f..f6a375e 100644 --- a/src/main/resources/dev/application.properties +++ b/src/main/resources/dev/application.properties @@ -6,7 +6,7 @@ spring.mvc.view.prefix=/WEB-INF/views/ spring.mvc.view.suffix=.jsp # common -spring.config.import=classpath:db.properties, classpath:common.properties +spring.config.import=classpath:dev/db.properties # IP server.address=0.0.0.0 diff --git a/src/main/resources/live/application.properties b/src/main/resources/live/application.properties index 1f4758f..5affd58 100644 --- a/src/main/resources/live/application.properties +++ b/src/main/resources/live/application.properties @@ -6,7 +6,7 @@ spring.mvc.view.prefix=/WEB-INF/views/ spring.mvc.view.suffix=.jsp # common -spring.config.import=classpath:db.properties, classpath:common.properties +spring.config.import=classpath:live/db.properties # IP server.address=0.0.0.0 diff --git a/src/main/resources/static/webgl/placeholder/index.html b/src/main/resources/static/webgl/placeholder/index.html new file mode 100644 index 0000000..f35bdb3 --- /dev/null +++ b/src/main/resources/static/webgl/placeholder/index.html @@ -0,0 +1,41 @@ + + + + + + WebGL placeholder + + + +
+ +

Unity WebGL 빌드 출력물(index.html, Build, TemplateData)을
+ src/main/resources/static/webgl/game-번호/ 에 넣고 상세 페이지에서 iframe 경로를 연결하세요.

+
+ + diff --git a/src/main/webapp/WEB-INF/views/footer.jsp b/src/main/webapp/WEB-INF/views/footer.jsp new file mode 100644 index 0000000..868dc66 --- /dev/null +++ b/src/main/webapp/WEB-INF/views/footer.jsp @@ -0,0 +1,93 @@ +<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %> + + diff --git a/src/main/webapp/WEB-INF/views/game-detail.jsp b/src/main/webapp/WEB-INF/views/game-detail.jsp new file mode 100644 index 0000000..ae85c29 --- /dev/null +++ b/src/main/webapp/WEB-INF/views/game-detail.jsp @@ -0,0 +1,900 @@ +<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %> + + + + + + + ${gameName} — bibimbap + + + + +
+ + + 목록으로 + + +
+

${gameName}

+
+
+
+ + 번호 +
+ #${gameId} +
+
+
+ + 제작자 +
+ ${creator} +
+ +
+
+ +
+
+ +

플레이

+ WebGL +
+
+
+ +
+
+

실제 Unity WebGL 빌드는 리소스 폴더에 두세요. 예: static${webglDeployPath}
+ 준비되면 GameController에서 webglUrl을 해당 경로(webglUrlForGame(id))로 바꾸면 됩니다.

+
+ +
+
+
+ +
+

제작자의 한마디

+

이 게임을 만들며 전하고 싶었던 이야기예요.

+
+
+
${creatorNote}
+ +
+ +
+
+ +
+

덧글

+

플레이 소감이나 버그 제보를 남겨 주세요.

+
+
+
+
+ + +
+ 최대 1,000자 + +
+
+
+ +
    +
    +
    +
    + + + + + diff --git a/src/main/webapp/WEB-INF/views/header.jsp b/src/main/webapp/WEB-INF/views/header.jsp new file mode 100644 index 0000000..ece1ca1 --- /dev/null +++ b/src/main/webapp/WEB-INF/views/header.jsp @@ -0,0 +1,173 @@ +<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %> + + + + diff --git a/src/main/webapp/WEB-INF/views/index.jsp b/src/main/webapp/WEB-INF/views/index.jsp new file mode 100644 index 0000000..cca345c --- /dev/null +++ b/src/main/webapp/WEB-INF/views/index.jsp @@ -0,0 +1,535 @@ +<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" language="java" %> +<%@ page import="com.pandoli365.bibimbap.game.GameCatalog" %> + + + + + + + bibimbap + + + + +
    +
    + + +
    + +
    + <%-- 카드 데이터: GameCatalog (DB 연동 시 교체) --%> + <% + String ctx = request.getContextPath(); + for (int i = 0; i < GameCatalog.COUNT; i++) { + int displayIndex = i + 1; + /* 썸네일 URL — DB 연동 시 null·빈 문자열이면 로고 폴백 */ + String thumbUrl = null; // 예: list.get(i).getThumbnailUrl() + boolean hasImage = thumbUrl != null && !thumbUrl.isBlank(); + %> + +
    + + <% if (hasImage) { %> + + <% } else { %> + + <% } %> +
    +
    +

    <%= GameCatalog.NAMES[i] %>

    +

    <%= GameCatalog.CREATORS[i] %>

    + +
    +
    + <% + } + %> +
    +
    + + + + diff --git a/src/main/webapp/WEB-INF/views/theme-init.jsp b/src/main/webapp/WEB-INF/views/theme-init.jsp new file mode 100644 index 0000000..259dc4b --- /dev/null +++ b/src/main/webapp/WEB-INF/views/theme-init.jsp @@ -0,0 +1,13 @@ +<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %> + diff --git a/src/main/webapp/images/logo.png b/src/main/webapp/images/logo.png new file mode 100644 index 0000000..348470c Binary files /dev/null and b/src/main/webapp/images/logo.png differ