From 73de1f0985e20b4efab767a88c4817f1be6760b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Przemys=C5=82aw=20Pluta?= Date: Fri, 12 Mar 2021 15:05:04 +0100 Subject: [PATCH] Move the Context creation to the App engine starting point | change GLFW Window title to project name --- .../base/api/game/context/Context.java | 11 +++- .../com/bartlomiejpluta/base/engine/App.java | 23 ++++--- .../engine/core/engine/DefaultGameEngine.java | 65 +++++++++++-------- .../base/engine/core/engine/GameEngine.java | 4 +- .../base/engine/logic/DefaultGameLogic.java | 17 +++-- .../base/engine/logic/GameLogic.java | 3 +- .../engine/project/model/ContextManager.java | 7 ++ ...erableContext.java => DefaultContext.java} | 62 ++++++++++-------- .../project/model/DefaultContextManager.java | 65 +++++++++++++++++++ .../base/engine/thread/ThreadManager.java | 3 + .../base/engine/ui/ScreenManager.java | 3 + engine/src/main/resources/application.yml | 15 +---- 12 files changed, 187 insertions(+), 91 deletions(-) create mode 100644 engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/ContextManager.java rename engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/{RenderableContext.java => DefaultContext.java} (73%) create mode 100644 engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/DefaultContextManager.java diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/game/context/Context.java b/api/src/main/java/com/bartlomiejpluta/base/api/game/context/Context.java index 983f54d7..66a78022 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/game/context/Context.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/game/context/Context.java @@ -6,14 +6,19 @@ import com.bartlomiejpluta.base.api.game.gui.base.GUI; import com.bartlomiejpluta.base.api.game.image.Image; import com.bartlomiejpluta.base.api.game.runner.GameRunner; import com.bartlomiejpluta.base.api.game.screen.Screen; +import com.bartlomiejpluta.base.api.internal.gc.Disposable; +import com.bartlomiejpluta.base.api.internal.logic.Updatable; +import com.bartlomiejpluta.base.api.internal.render.Renderable; -public interface Context { +public interface Context extends Updatable, Renderable, Disposable { GameRunner getGameRunner(); Screen getScreen(); Camera getCamera(); + String getProjectName(); + void openMap(String mapUid); Entity createEntity(String entitySetUid); @@ -21,4 +26,8 @@ public interface Context { Image getImage(String imageUid); GUI newGUI(); + + void init(Screen screen, Camera camera); + + void input(Screen screen); } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/App.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/App.java index 57d4db7d..219c8a83 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/App.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/App.java @@ -4,6 +4,7 @@ package com.bartlomiejpluta.base.engine; import com.bartlomiejpluta.base.engine.core.engine.GameEngine; +import com.bartlomiejpluta.base.engine.project.model.ContextManager; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -16,15 +17,19 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication(scanBasePackages = "com.bartlomiejpluta.base") @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class App implements ApplicationRunner { - private final GameEngine gameEngine; + private final GameEngine gameEngine; + private final ContextManager contextManager; - @Override - public void run(ApplicationArguments args) { - log.info("Starting game engine"); - gameEngine.start(); - } + @Override + public void run(ApplicationArguments args) { + log.info("Creating context"); + var context = contextManager.createContext(); - public static void main(String[] args) { - SpringApplication.run(App.class, args); - } + log.info("Starting game engine"); + gameEngine.start(context); + } + + public static void main(String[] args) { + SpringApplication.run(App.class, args); + } } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/core/engine/DefaultGameEngine.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/core/engine/DefaultGameEngine.java index 2787c1fd..89b95b4a 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/core/engine/DefaultGameEngine.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/core/engine/DefaultGameEngine.java @@ -1,53 +1,38 @@ package com.bartlomiejpluta.base.engine.core.engine; +import com.bartlomiejpluta.base.api.game.context.Context; import com.bartlomiejpluta.base.api.game.screen.Screen; import com.bartlomiejpluta.base.engine.gc.OffHeapGarbageCollector; import com.bartlomiejpluta.base.engine.logic.GameLogic; import com.bartlomiejpluta.base.engine.thread.ThreadManager; import com.bartlomiejpluta.base.engine.time.ChronoMeter; import com.bartlomiejpluta.base.engine.ui.ScreenManager; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Slf4j @Component +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class DefaultGameEngine implements GameEngine { - private static final String THREAD_NAME = "Game Main Thread"; + private static final String THREAD_NAME = "engine"; private final ScreenManager screenManager; private final ThreadManager threadManager; private final GameLogic logic; private final OffHeapGarbageCollector garbageCollector; - private final Thread thread; - private final Screen screen; - private final ChronoMeter chrono; - private final int targetUps; + private final ChronoMeter chrono = new ChronoMeter(); + + private Thread thread; + private Screen screen; + private int targetUps; + + private Context context; private boolean running = false; - @Autowired - public DefaultGameEngine(ScreenManager screenManager, - ThreadManager threadManager, - GameLogic logic, - OffHeapGarbageCollector garbageCollector, - @Value("${app.window.title}") String title, - @Value("${app.window.width}") int width, - @Value("${app.window.height}") int height, - @Value("${app.core.targetUps}") int targetUps) { - this.screenManager = screenManager; - this.threadManager = threadManager; - this.logic = logic; - this.garbageCollector = garbageCollector; - - this.screen = screenManager.createScreen(title, width, height); - this.thread = threadManager.createThread(THREAD_NAME, this::run); - this.chrono = new ChronoMeter(); - this.targetUps = targetUps; - } - private void run() { try { init(); @@ -61,7 +46,7 @@ public class DefaultGameEngine implements GameEngine { log.info("Initializing game engine"); screen.init(); chrono.init(); - logic.init(screen); + logic.init(screen, context); } private void loop() { @@ -102,10 +87,34 @@ public class DefaultGameEngine implements GameEngine { private void cleanUp() { log.info("Performing off heap garbage collection"); garbageCollector.cleanUp(); + + log.info("Disposing context"); + context.dispose(); } @Override - public void start() { + public void start(Context context) { + this.context = context; + + this.screen = screenManager.createScreen(context.getProjectName(), WINDOW_WIDTH, WINDOW_HEIGHT); + this.thread = threadManager.createThread(THREAD_NAME, this::run); + + this.targetUps = TARGET_UPS; + + log.info("Starting [{}] thread", THREAD_NAME); thread.start(); } + + // TODO + // It is supposed to be moved to the Context so that + // user will be able to choose default window size, + // as well as further possibility to resize the window + // or forcing fullscreen mode. + // Until it's not implemented yet, the window width and height + // are hardcoded right here. + // + // The same applies for target UPS (updates per second) parameter. + private static final int WINDOW_WIDTH = 640; + private static final int WINDOW_HEIGHT = 480; + private static final int TARGET_UPS = 60; } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/core/engine/GameEngine.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/core/engine/GameEngine.java index 0a376fb3..634a0163 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/core/engine/GameEngine.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/core/engine/GameEngine.java @@ -1,5 +1,7 @@ package com.bartlomiejpluta.base.engine.core.engine; +import com.bartlomiejpluta.base.api.game.context.Context; + public interface GameEngine { - void start(); + void start(Context context); } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/logic/DefaultGameLogic.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/logic/DefaultGameLogic.java index afd8935d..d607e6b6 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/logic/DefaultGameLogic.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/logic/DefaultGameLogic.java @@ -1,11 +1,9 @@ package com.bartlomiejpluta.base.engine.logic; import com.bartlomiejpluta.base.api.game.camera.Camera; +import com.bartlomiejpluta.base.api.game.context.Context; import com.bartlomiejpluta.base.api.game.screen.Screen; import com.bartlomiejpluta.base.engine.core.gl.render.Renderer; -import com.bartlomiejpluta.base.engine.project.loader.ProjectLoader; -import com.bartlomiejpluta.base.engine.project.model.Project; -import com.bartlomiejpluta.base.engine.project.model.RenderableContext; import com.bartlomiejpluta.base.engine.world.camera.DefaultCamera; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -17,18 +15,19 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class DefaultGameLogic implements GameLogic { private final Renderer renderer; - private final ProjectLoader projectLoader; - private final RenderableContext context; private final Camera camera = new DefaultCamera(); + private Context context; + @Override - public void init(Screen screen) { + public void init(Screen screen, Context context) { + this.context = context; + log.info("Initializing game logic"); renderer.init(); - Project project = projectLoader.loadProject(); - - context.init(screen, camera, project); + log.info("Initializing game context"); + context.init(screen, camera); } @Override diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/logic/GameLogic.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/logic/GameLogic.java index 8ffdbee1..ac347fb9 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/logic/GameLogic.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/logic/GameLogic.java @@ -1,10 +1,11 @@ package com.bartlomiejpluta.base.engine.logic; +import com.bartlomiejpluta.base.api.game.context.Context; import com.bartlomiejpluta.base.api.game.screen.Screen; import com.bartlomiejpluta.base.api.internal.gc.Cleanable; public interface GameLogic extends Cleanable { - void init(Screen screen); + void init(Screen screen, Context context); void input(Screen screen); diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/ContextManager.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/ContextManager.java new file mode 100644 index 00000000..717d1313 --- /dev/null +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/ContextManager.java @@ -0,0 +1,7 @@ +package com.bartlomiejpluta.base.engine.project.model; + +import com.bartlomiejpluta.base.api.game.context.Context; + +public interface ContextManager { + Context createContext(); +} diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/RenderableContext.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/DefaultContext.java similarity index 73% rename from engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/RenderableContext.java rename to engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/DefaultContext.java index 889a0a15..792288a0 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/RenderableContext.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/DefaultContext.java @@ -8,68 +8,73 @@ import com.bartlomiejpluta.base.api.game.image.Image; import com.bartlomiejpluta.base.api.game.map.handler.MapHandler; import com.bartlomiejpluta.base.api.game.runner.GameRunner; import com.bartlomiejpluta.base.api.game.screen.Screen; -import com.bartlomiejpluta.base.api.internal.gc.Cleanable; -import com.bartlomiejpluta.base.api.internal.logic.Updatable; -import com.bartlomiejpluta.base.api.internal.render.Renderable; import com.bartlomiejpluta.base.api.internal.render.ShaderManager; +import com.bartlomiejpluta.base.engine.core.engine.GameEngine; import com.bartlomiejpluta.base.engine.gui.manager.FontManager; import com.bartlomiejpluta.base.engine.gui.render.NanoVGGUI; -import com.bartlomiejpluta.base.engine.project.loader.ClassLoader; import com.bartlomiejpluta.base.engine.world.entity.manager.EntityManager; import com.bartlomiejpluta.base.engine.world.image.manager.ImageManager; import com.bartlomiejpluta.base.engine.world.map.manager.MapManager; import com.bartlomiejpluta.base.engine.world.map.model.DefaultGameMap; +import lombok.Builder; import lombok.Getter; -import lombok.RequiredArgsConstructor; +import lombok.NonNull; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; import java.util.LinkedList; import java.util.List; @Slf4j -@Component -@RequiredArgsConstructor(onConstructor = @__(@Autowired)) -public class RenderableContext implements Context, Updatable, Renderable, Cleanable { +@Builder +public class DefaultContext implements Context { + + @NonNull + private final GameEngine engine; + + @NonNull private final EntityManager entityManager; + + @NonNull private final ImageManager imageManager; + + @NonNull private final MapManager mapManager; + + @NonNull private final FontManager fontManager; - private final ClassLoader classLoader; + + @Getter + @NonNull + private final GameRunner gameRunner; + + @Getter + @NonNull + private final String projectName; @Getter private Screen screen; - @Getter - private GameRunner gameRunner; - @Getter private Camera camera; - private Project project; private DefaultGameMap map; private MapHandler mapHandler; private final List guis = new LinkedList<>(); @SneakyThrows - public void init(Screen screen, Camera camera, Project project) { - log.info("Initializing game context"); + @Override + public void init(@NonNull Screen screen, @NonNull Camera camera) { this.screen = screen; this.camera = camera; - this.project = project; - - var runnerClass = classLoader.loadClass(project.getRunner()); - gameRunner = runnerClass.getConstructor().newInstance(); gameRunner.init(this); } @SneakyThrows @Override - public void openMap(String mapUid) { + public void openMap(@NonNull String mapUid) { map = mapManager.loadObject(mapUid); mapHandler = mapManager.loadHandler(this, mapUid); @@ -77,13 +82,13 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana } @Override - public Entity createEntity(String entitySetUid) { + public Entity createEntity(@NonNull String entitySetUid) { log.info("Creating new entity with UID: [{}]", entitySetUid); return entityManager.createEntity(entitySetUid); } @Override - public Image getImage(String imageUid) { + public Image getImage(@NonNull String imageUid) { return imageManager.loadObject(imageUid); } @@ -96,6 +101,7 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana return gui; } + @Override public void input(Screen screen) { gameRunner.input(screen); @@ -133,11 +139,11 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana } @Override - public void cleanUp() { - log.info("Disposing game runner"); - gameRunner.dispose(); - + public void dispose() { log.info("Disposing GUIs"); guis.forEach(GUI::dispose); + + log.info("Disposing game runner"); + gameRunner.dispose(); } } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/DefaultContextManager.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/DefaultContextManager.java new file mode 100644 index 00000000..3d1d489d --- /dev/null +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/project/model/DefaultContextManager.java @@ -0,0 +1,65 @@ +package com.bartlomiejpluta.base.engine.project.model; + +import com.bartlomiejpluta.base.api.game.context.Context; +import com.bartlomiejpluta.base.api.game.runner.GameRunner; +import com.bartlomiejpluta.base.engine.core.engine.GameEngine; +import com.bartlomiejpluta.base.engine.gui.manager.FontManager; +import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration; +import com.bartlomiejpluta.base.engine.project.loader.ClassLoader; +import com.bartlomiejpluta.base.engine.project.serial.ProjectDeserializer; +import com.bartlomiejpluta.base.engine.world.entity.manager.EntityManager; +import com.bartlomiejpluta.base.engine.world.entity.manager.EntitySetManager; +import com.bartlomiejpluta.base.engine.world.image.manager.ImageManager; +import com.bartlomiejpluta.base.engine.world.map.manager.MapManager; +import com.bartlomiejpluta.base.engine.world.tileset.manager.TileSetManager; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class DefaultContextManager implements ContextManager { + private final GameEngine engine; + private final ProjectConfiguration configuration; + private final ProjectDeserializer projectDeserializer; + private final TileSetManager tileSetManager; + private final MapManager mapManager; + private final ImageManager imageManager; + private final EntitySetManager entitySetManager; + private final FontManager fontManager; + private final EntityManager entityManager; + private final ClassLoader classLoader; + + @SneakyThrows + @Override + public Context createContext() { + log.info("Deserializing project file"); + var resource = DefaultContextManager.class.getResourceAsStream(configuration.projectFile(configuration.getMainFile())); + var project = projectDeserializer.deserialize(resource); + + log.info("Registering project assets"); + project.getTileSetAssets().forEach(tileSetManager::registerAsset); + project.getMapAssets().forEach(mapManager::registerAsset); + project.getImageAssets().forEach(imageManager::registerAsset); + project.getEntitySetAssets().forEach(entitySetManager::registerAsset); + project.getFontAssets().forEach(fontManager::registerAsset); + + log.info("Creating game runner instance"); + var runnerClass = classLoader.loadClass(project.getRunner()); + var gameRunner = runnerClass.getConstructor().newInstance(); + + log.info("Building context up"); + return DefaultContext.builder() + .engine(engine) + .entityManager(entityManager) + .imageManager(imageManager) + .mapManager(mapManager) + .fontManager(fontManager) + .gameRunner(gameRunner) + .projectName(project.getName()) + .build(); + } +} diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/thread/ThreadManager.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/thread/ThreadManager.java index d0d22fc3..21d54ab1 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/thread/ThreadManager.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/thread/ThreadManager.java @@ -1,10 +1,13 @@ package com.bartlomiejpluta.base.engine.thread; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +@Slf4j @Component public class ThreadManager { public Thread createThread(String name, Runnable runnable) { + log.info("Creating [{}] thread", name); return new Thread(runnable, name); } } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/ui/ScreenManager.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/ui/ScreenManager.java index ffe81c7f..b49bccfa 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/ui/ScreenManager.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/ui/ScreenManager.java @@ -1,11 +1,14 @@ package com.bartlomiejpluta.base.engine.ui; import com.bartlomiejpluta.base.api.game.screen.Screen; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; +@Slf4j @Component public class ScreenManager { public Screen createScreen(String title, int width, int height) { + log.info("Creating GLFW window ([{}], {}x{})", title, width, height); return GLFWScreen.create(title, width, height); } } diff --git a/engine/src/main/resources/application.yml b/engine/src/main/resources/application.yml index 2dde3582..1bc28fb6 100644 --- a/engine/src/main/resources/application.yml +++ b/engine/src/main/resources/application.yml @@ -1,12 +1,4 @@ app: - window: - title: "Simple Game" - width: 640 - height: 480 - - core: - targetUps: 50 # Updates per second - project: main-file: project.bep resource-path: /project @@ -23,9 +15,4 @@ app: down: 0 left: 1 right: 2 - up: 3 - - -logging: - level: - com.bartlomiejpluta.base.core.profiling.time.aspect.ExecutionTimeAspect: DEBUG \ No newline at end of file + up: 3 \ No newline at end of file