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 0aef82f8..983f54d7 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 @@ -4,9 +4,12 @@ import com.bartlomiejpluta.base.api.game.camera.Camera; import com.bartlomiejpluta.base.api.game.entity.Entity; 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; public interface Context { + GameRunner getGameRunner(); + Screen getScreen(); Camera getCamera(); diff --git a/api/src/main/java/com/bartlomiejpluta/base/api/game/runner/GameRunner.java b/api/src/main/java/com/bartlomiejpluta/base/api/game/runner/GameRunner.java index 3d2bd6c0..55900a76 100644 --- a/api/src/main/java/com/bartlomiejpluta/base/api/game/runner/GameRunner.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/game/runner/GameRunner.java @@ -1,7 +1,13 @@ package com.bartlomiejpluta.base.api.game.runner; import com.bartlomiejpluta.base.api.game.context.Context; +import com.bartlomiejpluta.base.api.game.screen.Screen; +import com.bartlomiejpluta.base.api.internal.gc.Disposable; -public interface GameRunner { +public interface GameRunner extends Disposable { void init(Context context); + + void input(Screen screen); + + void update(float dt); } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/util/profiling/fps/LogFPSMonitor.java b/api/src/main/java/com/bartlomiejpluta/base/api/util/profiler/FPSProfiler.java similarity index 50% rename from engine/src/main/java/com/bartlomiejpluta/base/engine/util/profiling/fps/LogFPSMonitor.java rename to api/src/main/java/com/bartlomiejpluta/base/api/util/profiler/FPSProfiler.java index 9250a6ed..182a8295 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/util/profiling/fps/LogFPSMonitor.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/util/profiler/FPSProfiler.java @@ -1,7 +1,4 @@ -package com.bartlomiejpluta.base.engine.util.profiling.fps; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; +package com.bartlomiejpluta.base.api.util.profiler; import java.util.LinkedList; import java.util.List; @@ -12,16 +9,13 @@ import static java.util.function.Function.identity; import static java.util.stream.Collectors.counting; import static java.util.stream.Collectors.groupingBy; -@Slf4j -@Component -public class LogFPSMonitor implements FPSMonitor { +public class FPSProfiler { private static final int MOD = 30; private final List values = new LinkedList<>(); private float fpsAccumulator = 0; private int pointer = 0; private double fps = 0; - @Override public void update(float dt) { fpsAccumulator += dt; @@ -34,14 +28,13 @@ public class LogFPSMonitor implements FPSMonitor { } } - @Override - public void cleanUp() { - log.info("Min FPS: {}, max FPS: {}, avg FPS: {}", - values.stream().min(Double::compareTo).orElse(-1.0), - values.stream().max(Double::compareTo).orElse(-1.0), - totalAverage() + public void printResult() { + System.out.format("Min FPS: %f, max FPS: %f, avg FPS: %f", + values.stream().min(Double::compareTo).orElse(-1.0), + values.stream().max(Double::compareTo).orElse(-1.0), + totalAverage() ); - + printHistogram(); } @@ -51,13 +44,13 @@ public class LogFPSMonitor implements FPSMonitor { private void printHistogram() { values - .stream() - .mapToInt(Double::intValue) - .boxed() - .collect(groupingBy(identity(), counting())) - .entrySet() - .stream() - .sorted(comparingInt(Map.Entry::getKey)) - .forEach(e -> log.info("{} FPS: {}% ({} occurrences)", e.getKey(), e.getValue() * 100.0f / values.size(), e.getValue())); + .stream() + .mapToInt(Double::intValue) + .boxed() + .collect(groupingBy(identity(), counting())) + .entrySet() + .stream() + .sorted(comparingInt(Map.Entry::getKey)) + .forEach(e -> System.out.printf("%s FPS: %f%% (%d occurrences)", e.getKey(), e.getValue() * 100.0f / values.size(), e.getValue())); } } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/util/profiling/time/DefaultTimeProfilerService.java b/api/src/main/java/com/bartlomiejpluta/base/api/util/profiler/TimeProfiler.java similarity index 67% rename from engine/src/main/java/com/bartlomiejpluta/base/engine/util/profiling/time/DefaultTimeProfilerService.java rename to api/src/main/java/com/bartlomiejpluta/base/api/util/profiler/TimeProfiler.java index bbfeda61..f314b855 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/util/profiling/time/DefaultTimeProfilerService.java +++ b/api/src/main/java/com/bartlomiejpluta/base/api/util/profiler/TimeProfiler.java @@ -1,21 +1,14 @@ -package com.bartlomiejpluta.base.engine.util.profiling.time; - -import com.bartlomiejpluta.base.api.internal.gc.Cleanable; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; +package com.bartlomiejpluta.base.api.util.profiler; import java.text.DecimalFormat; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; -@Slf4j -@Component -public class DefaultTimeProfilerService implements TimeProfilerService, Cleanable { +public class TimeProfiler { private static final DecimalFormat DF = new DecimalFormat("0.00"); private final Map averages = new HashMap<>(); - @Override public void measure(String key, Runnable task) { var start = System.nanoTime(); task.run(); @@ -28,11 +21,10 @@ public class DefaultTimeProfilerService implements TimeProfilerService, Cleanabl } } - @Override - public void cleanUp() { + public void printResult() { averages.entrySet().stream() .sorted(Entry.comparingByValue().reversed()) - .forEachOrdered(entry -> log.info("[{}]: [{}ms] [{}us] [{}ns]", + .forEachOrdered(entry -> System.out.format("[%s]: [%sms] [%sus] [%sns]", entry.getKey(), DF.format(entry.getValue() / 1_000_000), DF.format(entry.getValue() / 1_000), diff --git a/editor/src/main/resources/java_templates/game_runner.ftl b/editor/src/main/resources/java_templates/game_runner.ftl index 30f77366..7b71cb14 100644 --- a/editor/src/main/resources/java_templates/game_runner.ftl +++ b/editor/src/main/resources/java_templates/game_runner.ftl @@ -1,7 +1,8 @@ package ${package}; -import com.bartlomiejpluta.base.api.game.runner.GameRunner; import com.bartlomiejpluta.base.api.game.context.Context; +import com.bartlomiejpluta.base.api.game.screen.Screen; +import com.bartlomiejpluta.base.api.game.runner.GameRunner; public class ${className} implements GameRunner { @@ -9,4 +10,19 @@ public class ${className} implements GameRunner { public void init(Context context) { throw new RuntimeException("Not implemented yet"); } + + @Override + public void input(Screen screen) { + + } + + @Override + public void update(float dt) { + + } + + @Override + public void dispose() { + // Do something after game loop is end + } } \ No newline at end of file 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 b191557c..afd8935d 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,24 +1,13 @@ package com.bartlomiejpluta.base.engine.logic; import com.bartlomiejpluta.base.api.game.camera.Camera; -import com.bartlomiejpluta.base.api.game.runner.GameRunner; import com.bartlomiejpluta.base.api.game.screen.Screen; -import com.bartlomiejpluta.base.engine.core.gl.object.texture.TextureManager; import com.bartlomiejpluta.base.engine.core.gl.render.Renderer; -import com.bartlomiejpluta.base.engine.project.loader.ClassLoader; 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.util.mesh.MeshManager; -import com.bartlomiejpluta.base.engine.util.profiling.fps.FPSMonitor; -import com.bartlomiejpluta.base.engine.util.profiling.time.TimeProfilerService; import com.bartlomiejpluta.base.engine.world.camera.DefaultCamera; -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.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; @@ -28,36 +17,18 @@ import org.springframework.stereotype.Component; @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class DefaultGameLogic implements GameLogic { private final Renderer renderer; - private final TileSetManager tileSetManager; - private final MeshManager meshManager; - private final TextureManager textureManager; - private final EntityManager entityManager; - private final ImageManager imageManager; - private final TimeProfilerService profiler; - private final FPSMonitor fpsMonitor; - private final MapManager mapManager; private final ProjectLoader projectLoader; - private final ClassLoader classLoader; - private final RenderableContext context; - private final Camera camera = new DefaultCamera(); - private Project project; - private GameRunner runner; - - @SneakyThrows @Override public void init(Screen screen) { log.info("Initializing game logic"); renderer.init(); - context.init(screen, camera); - project = projectLoader.loadProject(); - var runnerClass = classLoader.loadClass(project.getRunner()); - runner = runnerClass.getConstructor().newInstance(); + Project project = projectLoader.loadProject(); - runner.init(context); + context.init(screen, camera, project); } @Override @@ -68,7 +39,6 @@ public class DefaultGameLogic implements GameLogic { @Override public void update(float dt) { context.update(dt); - fpsMonitor.update(dt); } @Override diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/project/loader/DefaultProjectLoader.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/project/loader/DefaultProjectLoader.java index bae2e240..fb94cbd7 100644 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/project/loader/DefaultProjectLoader.java +++ b/engine/src/main/java/com/bartlomiejpluta/base/engine/project/loader/DefaultProjectLoader.java @@ -9,9 +9,11 @@ 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.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +@Slf4j @Component @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class DefaultProjectLoader implements ProjectLoader { @@ -25,6 +27,7 @@ public class DefaultProjectLoader implements ProjectLoader { @Override public Project loadProject() { + log.info("Loading project resources"); var resource = DefaultProjectLoader.class.getResourceAsStream(configuration.projectFile(configuration.getMainFile())); var project = projectDeserializer.deserialize(resource); project.getTileSetAssets().forEach(tileSetManager::registerAsset); 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/RenderableContext.java index 4f959dbb..889a0a15 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/RenderableContext.java @@ -6,6 +6,7 @@ import com.bartlomiejpluta.base.api.game.entity.Entity; import com.bartlomiejpluta.base.api.game.gui.base.GUI; 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; @@ -21,12 +22,14 @@ import com.bartlomiejpluta.base.engine.world.map.model.DefaultGameMap; import lombok.Getter; import lombok.RequiredArgsConstructor; 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 { @@ -38,17 +41,30 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana @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<>(); - @Getter - private Camera camera; - - public void init(Screen screen, Camera camera) { + @SneakyThrows + public void init(Screen screen, Camera camera, Project project) { + log.info("Initializing game context"); this.screen = screen; this.camera = camera; + this.project = project; + + var runnerClass = classLoader.loadClass(project.getRunner()); + gameRunner = runnerClass.getConstructor().newInstance(); + + gameRunner.init(this); } @SneakyThrows @@ -62,6 +78,7 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana @Override public Entity createEntity(String entitySetUid) { + log.info("Creating new entity with UID: [{}]", entitySetUid); return entityManager.createEntity(entitySetUid); } @@ -72,6 +89,7 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana @Override public GUI newGUI() { + log.info("Creating new GUI"); var gui = new NanoVGGUI(fontManager); guis.add(gui); gui.init(screen); @@ -79,6 +97,8 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana } public void input(Screen screen) { + gameRunner.input(screen); + if (mapHandler != null) { mapHandler.input(screen); } @@ -86,6 +106,8 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana @Override public void update(float dt) { + gameRunner.update(dt); + if (mapHandler != null) { mapHandler.update(this, map, dt); } @@ -112,6 +134,10 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana @Override public void cleanUp() { + log.info("Disposing game runner"); + gameRunner.dispose(); + + log.info("Disposing GUIs"); guis.forEach(GUI::dispose); } } diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/util/profiling/fps/FPSMonitor.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/util/profiling/fps/FPSMonitor.java deleted file mode 100644 index e20449a6..00000000 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/util/profiling/fps/FPSMonitor.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.bartlomiejpluta.base.engine.util.profiling.fps; - -import com.bartlomiejpluta.base.api.internal.gc.Cleanable; -import com.bartlomiejpluta.base.api.internal.logic.Updatable; - -public interface FPSMonitor extends Updatable, Cleanable { -} diff --git a/engine/src/main/java/com/bartlomiejpluta/base/engine/util/profiling/time/TimeProfilerService.java b/engine/src/main/java/com/bartlomiejpluta/base/engine/util/profiling/time/TimeProfilerService.java deleted file mode 100644 index 2308773a..00000000 --- a/engine/src/main/java/com/bartlomiejpluta/base/engine/util/profiling/time/TimeProfilerService.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.bartlomiejpluta.base.engine.util.profiling.time; - -public interface TimeProfilerService { - void measure(String key, Runnable task); -}