Move the Context creation to the App engine starting point | change GLFW Window title to project name

This commit is contained in:
2021-03-12 15:05:04 +01:00
parent cafad00389
commit 73de1f0985
12 changed files with 187 additions and 91 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,7 @@
package com.bartlomiejpluta.base.engine.project.model;
import com.bartlomiejpluta.base.api.game.context.Context;
public interface ContextManager {
Context createContext();
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
@@ -24,8 +16,3 @@ app:
left: 1
right: 2
up: 3
logging:
level:
com.bartlomiejpluta.base.core.profiling.time.aspect.ExecutionTimeAspect: DEBUG