Refactor Context and GameRunner
This commit is contained in:
@@ -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.entity.Entity;
|
||||||
import com.bartlomiejpluta.base.api.game.gui.base.GUI;
|
import com.bartlomiejpluta.base.api.game.gui.base.GUI;
|
||||||
import com.bartlomiejpluta.base.api.game.image.Image;
|
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.game.screen.Screen;
|
||||||
|
|
||||||
public interface Context {
|
public interface Context {
|
||||||
|
GameRunner getGameRunner();
|
||||||
|
|
||||||
Screen getScreen();
|
Screen getScreen();
|
||||||
|
|
||||||
Camera getCamera();
|
Camera getCamera();
|
||||||
|
|||||||
@@ -1,7 +1,13 @@
|
|||||||
package com.bartlomiejpluta.base.api.game.runner;
|
package com.bartlomiejpluta.base.api.game.runner;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.api.game.context.Context;
|
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 init(Context context);
|
||||||
|
|
||||||
|
void input(Screen screen);
|
||||||
|
|
||||||
|
void update(float dt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
package com.bartlomiejpluta.base.engine.util.profiling.fps;
|
package com.bartlomiejpluta.base.api.util.profiler;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
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.counting;
|
||||||
import static java.util.stream.Collectors.groupingBy;
|
import static java.util.stream.Collectors.groupingBy;
|
||||||
|
|
||||||
@Slf4j
|
public class FPSProfiler {
|
||||||
@Component
|
|
||||||
public class LogFPSMonitor implements FPSMonitor {
|
|
||||||
private static final int MOD = 30;
|
private static final int MOD = 30;
|
||||||
private final List<Double> values = new LinkedList<>();
|
private final List<Double> values = new LinkedList<>();
|
||||||
private float fpsAccumulator = 0;
|
private float fpsAccumulator = 0;
|
||||||
private int pointer = 0;
|
private int pointer = 0;
|
||||||
private double fps = 0;
|
private double fps = 0;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update(float dt) {
|
public void update(float dt) {
|
||||||
fpsAccumulator += dt;
|
fpsAccumulator += dt;
|
||||||
|
|
||||||
@@ -34,12 +28,11 @@ public class LogFPSMonitor implements FPSMonitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void printResult() {
|
||||||
public void cleanUp() {
|
System.out.format("Min FPS: %f, max FPS: %f, avg FPS: %f",
|
||||||
log.info("Min FPS: {}, max FPS: {}, avg FPS: {}",
|
values.stream().min(Double::compareTo).orElse(-1.0),
|
||||||
values.stream().min(Double::compareTo).orElse(-1.0),
|
values.stream().max(Double::compareTo).orElse(-1.0),
|
||||||
values.stream().max(Double::compareTo).orElse(-1.0),
|
totalAverage()
|
||||||
totalAverage()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
printHistogram();
|
printHistogram();
|
||||||
@@ -51,13 +44,13 @@ public class LogFPSMonitor implements FPSMonitor {
|
|||||||
|
|
||||||
private void printHistogram() {
|
private void printHistogram() {
|
||||||
values
|
values
|
||||||
.stream()
|
.stream()
|
||||||
.mapToInt(Double::intValue)
|
.mapToInt(Double::intValue)
|
||||||
.boxed()
|
.boxed()
|
||||||
.collect(groupingBy(identity(), counting()))
|
.collect(groupingBy(identity(), counting()))
|
||||||
.entrySet()
|
.entrySet()
|
||||||
.stream()
|
.stream()
|
||||||
.sorted(comparingInt(Map.Entry::getKey))
|
.sorted(comparingInt(Map.Entry::getKey))
|
||||||
.forEach(e -> log.info("{} FPS: {}% ({} occurrences)", e.getKey(), e.getValue() * 100.0f / values.size(), e.getValue()));
|
.forEach(e -> System.out.printf("%s FPS: %f%% (%d occurrences)", e.getKey(), e.getValue() * 100.0f / values.size(), e.getValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,21 +1,14 @@
|
|||||||
package com.bartlomiejpluta.base.engine.util.profiling.time;
|
package com.bartlomiejpluta.base.api.util.profiler;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.api.internal.gc.Cleanable;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
@Slf4j
|
public class TimeProfiler {
|
||||||
@Component
|
|
||||||
public class DefaultTimeProfilerService implements TimeProfilerService, Cleanable {
|
|
||||||
private static final DecimalFormat DF = new DecimalFormat("0.00");
|
private static final DecimalFormat DF = new DecimalFormat("0.00");
|
||||||
private final Map<String, Double> averages = new HashMap<>();
|
private final Map<String, Double> averages = new HashMap<>();
|
||||||
|
|
||||||
@Override
|
|
||||||
public void measure(String key, Runnable task) {
|
public void measure(String key, Runnable task) {
|
||||||
var start = System.nanoTime();
|
var start = System.nanoTime();
|
||||||
task.run();
|
task.run();
|
||||||
@@ -28,11 +21,10 @@ public class DefaultTimeProfilerService implements TimeProfilerService, Cleanabl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public void printResult() {
|
||||||
public void cleanUp() {
|
|
||||||
averages.entrySet().stream()
|
averages.entrySet().stream()
|
||||||
.sorted(Entry.<String, Double>comparingByValue().reversed())
|
.sorted(Entry.<String, Double>comparingByValue().reversed())
|
||||||
.forEachOrdered(entry -> log.info("[{}]: [{}ms] [{}us] [{}ns]",
|
.forEachOrdered(entry -> System.out.format("[%s]: [%sms] [%sus] [%sns]",
|
||||||
entry.getKey(),
|
entry.getKey(),
|
||||||
DF.format(entry.getValue() / 1_000_000),
|
DF.format(entry.getValue() / 1_000_000),
|
||||||
DF.format(entry.getValue() / 1_000),
|
DF.format(entry.getValue() / 1_000),
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
package ${package};
|
package ${package};
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.api.game.runner.GameRunner;
|
|
||||||
import com.bartlomiejpluta.base.api.game.context.Context;
|
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 {
|
public class ${className} implements GameRunner {
|
||||||
|
|
||||||
@@ -9,4 +10,19 @@ public class ${className} implements GameRunner {
|
|||||||
public void init(Context context) {
|
public void init(Context context) {
|
||||||
throw new RuntimeException("Not implemented yet");
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,24 +1,13 @@
|
|||||||
package com.bartlomiejpluta.base.engine.logic;
|
package com.bartlomiejpluta.base.engine.logic;
|
||||||
|
|
||||||
import com.bartlomiejpluta.base.api.game.camera.Camera;
|
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.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.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.loader.ProjectLoader;
|
||||||
import com.bartlomiejpluta.base.engine.project.model.Project;
|
import com.bartlomiejpluta.base.engine.project.model.Project;
|
||||||
import com.bartlomiejpluta.base.engine.project.model.RenderableContext;
|
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.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.RequiredArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -28,36 +17,18 @@ import org.springframework.stereotype.Component;
|
|||||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
public class DefaultGameLogic implements GameLogic {
|
public class DefaultGameLogic implements GameLogic {
|
||||||
private final Renderer renderer;
|
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 ProjectLoader projectLoader;
|
||||||
private final ClassLoader classLoader;
|
|
||||||
|
|
||||||
private final RenderableContext context;
|
private final RenderableContext context;
|
||||||
|
|
||||||
private final Camera camera = new DefaultCamera();
|
private final Camera camera = new DefaultCamera();
|
||||||
|
|
||||||
private Project project;
|
|
||||||
private GameRunner runner;
|
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Screen screen) {
|
public void init(Screen screen) {
|
||||||
log.info("Initializing game logic");
|
log.info("Initializing game logic");
|
||||||
renderer.init();
|
renderer.init();
|
||||||
context.init(screen, camera);
|
|
||||||
|
|
||||||
project = projectLoader.loadProject();
|
Project project = projectLoader.loadProject();
|
||||||
var runnerClass = classLoader.<GameRunner>loadClass(project.getRunner());
|
|
||||||
runner = runnerClass.getConstructor().newInstance();
|
|
||||||
|
|
||||||
runner.init(context);
|
context.init(screen, camera, project);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -68,7 +39,6 @@ public class DefaultGameLogic implements GameLogic {
|
|||||||
@Override
|
@Override
|
||||||
public void update(float dt) {
|
public void update(float dt) {
|
||||||
context.update(dt);
|
context.update(dt);
|
||||||
fpsMonitor.update(dt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -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.map.manager.MapManager;
|
||||||
import com.bartlomiejpluta.base.engine.world.tileset.manager.TileSetManager;
|
import com.bartlomiejpluta.base.engine.world.tileset.manager.TileSetManager;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
public class DefaultProjectLoader implements ProjectLoader {
|
public class DefaultProjectLoader implements ProjectLoader {
|
||||||
@@ -25,6 +27,7 @@ public class DefaultProjectLoader implements ProjectLoader {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Project loadProject() {
|
public Project loadProject() {
|
||||||
|
log.info("Loading project resources");
|
||||||
var resource = DefaultProjectLoader.class.getResourceAsStream(configuration.projectFile(configuration.getMainFile()));
|
var resource = DefaultProjectLoader.class.getResourceAsStream(configuration.projectFile(configuration.getMainFile()));
|
||||||
var project = projectDeserializer.deserialize(resource);
|
var project = projectDeserializer.deserialize(resource);
|
||||||
project.getTileSetAssets().forEach(tileSetManager::registerAsset);
|
project.getTileSetAssets().forEach(tileSetManager::registerAsset);
|
||||||
|
|||||||
@@ -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.gui.base.GUI;
|
||||||
import com.bartlomiejpluta.base.api.game.image.Image;
|
import com.bartlomiejpluta.base.api.game.image.Image;
|
||||||
import com.bartlomiejpluta.base.api.game.map.handler.MapHandler;
|
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.game.screen.Screen;
|
||||||
import com.bartlomiejpluta.base.api.internal.gc.Cleanable;
|
import com.bartlomiejpluta.base.api.internal.gc.Cleanable;
|
||||||
import com.bartlomiejpluta.base.api.internal.logic.Updatable;
|
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.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
public class RenderableContext implements Context, Updatable, Renderable, Cleanable {
|
public class RenderableContext implements Context, Updatable, Renderable, Cleanable {
|
||||||
@@ -38,17 +41,30 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana
|
|||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private Screen screen;
|
private Screen screen;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private GameRunner gameRunner;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private Camera camera;
|
||||||
|
|
||||||
|
private Project project;
|
||||||
private DefaultGameMap map;
|
private DefaultGameMap map;
|
||||||
private MapHandler mapHandler;
|
private MapHandler mapHandler;
|
||||||
|
|
||||||
private final List<GUI> guis = new LinkedList<>();
|
private final List<GUI> guis = new LinkedList<>();
|
||||||
|
|
||||||
@Getter
|
@SneakyThrows
|
||||||
private Camera camera;
|
public void init(Screen screen, Camera camera, Project project) {
|
||||||
|
log.info("Initializing game context");
|
||||||
public void init(Screen screen, Camera camera) {
|
|
||||||
this.screen = screen;
|
this.screen = screen;
|
||||||
this.camera = camera;
|
this.camera = camera;
|
||||||
|
this.project = project;
|
||||||
|
|
||||||
|
var runnerClass = classLoader.<GameRunner>loadClass(project.getRunner());
|
||||||
|
gameRunner = runnerClass.getConstructor().newInstance();
|
||||||
|
|
||||||
|
gameRunner.init(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@@ -62,6 +78,7 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Entity createEntity(String entitySetUid) {
|
public Entity createEntity(String entitySetUid) {
|
||||||
|
log.info("Creating new entity with UID: [{}]", entitySetUid);
|
||||||
return entityManager.createEntity(entitySetUid);
|
return entityManager.createEntity(entitySetUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,6 +89,7 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GUI newGUI() {
|
public GUI newGUI() {
|
||||||
|
log.info("Creating new GUI");
|
||||||
var gui = new NanoVGGUI(fontManager);
|
var gui = new NanoVGGUI(fontManager);
|
||||||
guis.add(gui);
|
guis.add(gui);
|
||||||
gui.init(screen);
|
gui.init(screen);
|
||||||
@@ -79,6 +97,8 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void input(Screen screen) {
|
public void input(Screen screen) {
|
||||||
|
gameRunner.input(screen);
|
||||||
|
|
||||||
if (mapHandler != null) {
|
if (mapHandler != null) {
|
||||||
mapHandler.input(screen);
|
mapHandler.input(screen);
|
||||||
}
|
}
|
||||||
@@ -86,6 +106,8 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(float dt) {
|
public void update(float dt) {
|
||||||
|
gameRunner.update(dt);
|
||||||
|
|
||||||
if (mapHandler != null) {
|
if (mapHandler != null) {
|
||||||
mapHandler.update(this, map, dt);
|
mapHandler.update(this, map, dt);
|
||||||
}
|
}
|
||||||
@@ -112,6 +134,10 @@ public class RenderableContext implements Context, Updatable, Renderable, Cleana
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
|
log.info("Disposing game runner");
|
||||||
|
gameRunner.dispose();
|
||||||
|
|
||||||
|
log.info("Disposing GUIs");
|
||||||
guis.forEach(GUI::dispose);
|
guis.forEach(GUI::dispose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
|
||||||
}
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
package com.bartlomiejpluta.base.engine.util.profiling.time;
|
|
||||||
|
|
||||||
public interface TimeProfilerService {
|
|
||||||
void measure(String key, Runnable task);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user