Refactor Context and GameRunner

This commit is contained in:
2021-03-11 20:06:46 +01:00
parent 7c6824284a
commit 03a9253ca3
10 changed files with 82 additions and 85 deletions

View File

@@ -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.<GameRunner>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

View File

@@ -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);

View File

@@ -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<GUI> 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.<GameRunner>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);
}
}

View File

@@ -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 {
}

View File

@@ -1,63 +0,0 @@
package com.bartlomiejpluta.base.engine.util.profiling.fps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import static java.util.Comparator.comparingInt;
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 {
private static final int MOD = 30;
private final List<Double> values = new LinkedList<>();
private float fpsAccumulator = 0;
private int pointer = 0;
private double fps = 0;
@Override
public void update(float dt) {
fpsAccumulator += dt;
if (++pointer % MOD == 0) {
fps = pointer / fpsAccumulator;
fpsAccumulator = 0;
pointer = 0;
values.add(fps);
}
}
@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()
);
printHistogram();
}
private double totalAverage() {
return values.stream().reduce(0.0, Double::sum) / values.size();
}
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()));
}
}

View File

@@ -1,42 +0,0 @@
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;
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 {
private static final DecimalFormat DF = new DecimalFormat("0.00");
private final Map<String, Double> averages = new HashMap<>();
@Override
public void measure(String key, Runnable task) {
var start = System.nanoTime();
task.run();
var time = System.nanoTime() - start;
if (!averages.containsKey(key)) {
averages.put(key, time * 1.0);
} else {
averages.put(key, (averages.get(key) + time) / 2.0);
}
}
@Override
public void cleanUp() {
averages.entrySet().stream()
.sorted(Entry.<String, Double>comparingByValue().reversed())
.forEachOrdered(entry -> log.info("[{}]: [{}ms] [{}us] [{}ns]",
entry.getKey(),
DF.format(entry.getValue() / 1_000_000),
DF.format(entry.getValue() / 1_000),
DF.format(entry.getValue())
));
}
}

View File

@@ -1,5 +0,0 @@
package com.bartlomiejpluta.base.engine.util.profiling.time;
public interface TimeProfilerService {
void measure(String key, Runnable task);
}