Enable database support in :engine
This commit is contained in:
@@ -12,6 +12,11 @@ import com.bartlomiejpluta.base.api.screen.Screen;
|
|||||||
import com.bartlomiejpluta.base.internal.gc.Disposable;
|
import com.bartlomiejpluta.base.internal.gc.Disposable;
|
||||||
import com.bartlomiejpluta.base.internal.logic.Updatable;
|
import com.bartlomiejpluta.base.internal.logic.Updatable;
|
||||||
import com.bartlomiejpluta.base.internal.render.Renderable;
|
import com.bartlomiejpluta.base.internal.render.Renderable;
|
||||||
|
import com.bartlomiejpluta.base.util.lambda.UncheckedConsumer;
|
||||||
|
import com.bartlomiejpluta.base.util.lambda.UncheckedFunction;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
public interface Context extends Updatable, Renderable, Disposable {
|
public interface Context extends Updatable, Renderable, Disposable {
|
||||||
GameRunner getGameRunner();
|
GameRunner getGameRunner();
|
||||||
@@ -38,6 +43,10 @@ public interface Context extends Updatable, Renderable, Disposable {
|
|||||||
|
|
||||||
Sound createSound(String soundUid);
|
Sound createSound(String soundUid);
|
||||||
|
|
||||||
|
void withDatabase(UncheckedConsumer<Connection, SQLException> consumer);
|
||||||
|
|
||||||
|
<T> T withDatabase(UncheckedFunction<Connection, T, SQLException> extractor);
|
||||||
|
|
||||||
void disposeSound(Sound sound);
|
void disposeSound(Sound sound);
|
||||||
|
|
||||||
void playSound(String soundUid);
|
void playSound(String soundUid);
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.bartlomiejpluta.base.util.lambda;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface UncheckedConsumer<T, E extends Throwable> {
|
||||||
|
|
||||||
|
void accept(T t) throws E;
|
||||||
|
|
||||||
|
default UncheckedConsumer<T, E> andThen(UncheckedConsumer<? super T, ? extends E> after) {
|
||||||
|
Objects.requireNonNull(after);
|
||||||
|
return (T t) -> {
|
||||||
|
accept(t);
|
||||||
|
after.accept(t);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.bartlomiejpluta.base.util.lambda;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface UncheckedFunction<T, R, E extends Throwable> {
|
||||||
|
|
||||||
|
R apply(T t) throws E;
|
||||||
|
|
||||||
|
default <V> UncheckedFunction<V, R, E> compose(UncheckedFunction<? super V, ? extends T, ? extends E> before) {
|
||||||
|
Objects.requireNonNull(before);
|
||||||
|
return (V v) -> apply(before.apply(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
default <V> UncheckedFunction<T, V, E> andThen(UncheckedFunction<? super R, ? extends V, ? extends E> after) {
|
||||||
|
Objects.requireNonNull(after);
|
||||||
|
return (T t) -> after.apply(apply(t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static <T, E extends Throwable> UncheckedFunction<T, T, E> identity() {
|
||||||
|
return t -> t;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,6 +48,8 @@ dependencies {
|
|||||||
implementation 'org.springframework.boot:spring-boot-starter'
|
implementation 'org.springframework.boot:spring-boot-starter'
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-freemarker'
|
implementation 'org.springframework.boot:spring-boot-starter-freemarker'
|
||||||
implementation "org.slf4j:jul-to-slf4j:${slf4jVersion}"
|
implementation "org.slf4j:jul-to-slf4j:${slf4jVersion}"
|
||||||
|
|
||||||
|
// Database
|
||||||
implementation "com.h2database:h2:${h2Version}"
|
implementation "com.h2database:h2:${h2Version}"
|
||||||
implementation "com.zaxxer:HikariCP:${hikariVersion}"
|
implementation "com.zaxxer:HikariCP:${hikariVersion}"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ class DataSource(dbFile: File) {
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
config.jdbcUrl = "jdbc:h2:file:${dbFile.absolutePath.replace("\\", "/")}"
|
config.jdbcUrl = "jdbc:h2:file:${dbFile.absolutePath.replace("\\", "/")}"
|
||||||
config.username = "root"
|
|
||||||
config.password = ""
|
|
||||||
source = HikariDataSource(config)
|
source = HikariDataSource(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,10 @@ dependencies {
|
|||||||
|
|
||||||
// This dependency is used by the application.
|
// This dependency is used by the application.
|
||||||
implementation "org.joml:joml:${jomlVersion}"
|
implementation "org.joml:joml:${jomlVersion}"
|
||||||
|
|
||||||
|
// Database
|
||||||
|
implementation "com.h2database:h2:${h2Version}"
|
||||||
|
implementation "com.zaxxer:HikariCP:${hikariVersion}"
|
||||||
}
|
}
|
||||||
|
|
||||||
application {
|
application {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.bartlomiejpluta.base.api.runner.GameRunner;
|
|||||||
import com.bartlomiejpluta.base.engine.audio.manager.SoundManager;
|
import com.bartlomiejpluta.base.engine.audio.manager.SoundManager;
|
||||||
import com.bartlomiejpluta.base.engine.context.model.DefaultContext;
|
import com.bartlomiejpluta.base.engine.context.model.DefaultContext;
|
||||||
import com.bartlomiejpluta.base.engine.core.engine.GameEngine;
|
import com.bartlomiejpluta.base.engine.core.engine.GameEngine;
|
||||||
|
import com.bartlomiejpluta.base.engine.database.service.DatabaseService;
|
||||||
import com.bartlomiejpluta.base.engine.gui.manager.FontManager;
|
import com.bartlomiejpluta.base.engine.gui.manager.FontManager;
|
||||||
import com.bartlomiejpluta.base.engine.gui.manager.WidgetDefinitionManager;
|
import com.bartlomiejpluta.base.engine.gui.manager.WidgetDefinitionManager;
|
||||||
import com.bartlomiejpluta.base.engine.gui.xml.inflater.Inflater;
|
import com.bartlomiejpluta.base.engine.gui.xml.inflater.Inflater;
|
||||||
@@ -41,6 +42,7 @@ public class DefaultContextManager implements ContextManager {
|
|||||||
private final Inflater inflater;
|
private final Inflater inflater;
|
||||||
private final WidgetDefinitionManager widgetDefinitionManager;
|
private final WidgetDefinitionManager widgetDefinitionManager;
|
||||||
private final SoundManager soundManager;
|
private final SoundManager soundManager;
|
||||||
|
private final DatabaseService databaseService;
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
@Override
|
@Override
|
||||||
@@ -74,6 +76,7 @@ public class DefaultContextManager implements ContextManager {
|
|||||||
.inflater(inflater)
|
.inflater(inflater)
|
||||||
.widgetDefinitionManager(widgetDefinitionManager)
|
.widgetDefinitionManager(widgetDefinitionManager)
|
||||||
.soundManager(soundManager)
|
.soundManager(soundManager)
|
||||||
|
.databaseService(databaseService)
|
||||||
.gameRunner(gameRunner)
|
.gameRunner(gameRunner)
|
||||||
.projectName(project.getName())
|
.projectName(project.getName())
|
||||||
.build();
|
.build();
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import com.bartlomiejpluta.base.api.runner.GameRunner;
|
|||||||
import com.bartlomiejpluta.base.api.screen.Screen;
|
import com.bartlomiejpluta.base.api.screen.Screen;
|
||||||
import com.bartlomiejpluta.base.engine.audio.manager.SoundManager;
|
import com.bartlomiejpluta.base.engine.audio.manager.SoundManager;
|
||||||
import com.bartlomiejpluta.base.engine.core.engine.GameEngine;
|
import com.bartlomiejpluta.base.engine.core.engine.GameEngine;
|
||||||
|
import com.bartlomiejpluta.base.engine.database.service.DatabaseService;
|
||||||
import com.bartlomiejpluta.base.engine.gui.manager.FontManager;
|
import com.bartlomiejpluta.base.engine.gui.manager.FontManager;
|
||||||
import com.bartlomiejpluta.base.engine.gui.manager.WidgetDefinitionManager;
|
import com.bartlomiejpluta.base.engine.gui.manager.WidgetDefinitionManager;
|
||||||
import com.bartlomiejpluta.base.engine.gui.render.NanoVGGUI;
|
import com.bartlomiejpluta.base.engine.gui.render.NanoVGGUI;
|
||||||
@@ -23,12 +24,16 @@ 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.map.model.DefaultGameMap;
|
import com.bartlomiejpluta.base.engine.world.map.model.DefaultGameMap;
|
||||||
import com.bartlomiejpluta.base.internal.render.ShaderManager;
|
import com.bartlomiejpluta.base.internal.render.ShaderManager;
|
||||||
|
import com.bartlomiejpluta.base.util.lambda.UncheckedConsumer;
|
||||||
|
import com.bartlomiejpluta.base.util.lambda.UncheckedFunction;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -63,6 +68,9 @@ public class DefaultContext implements Context {
|
|||||||
@NonNull
|
@NonNull
|
||||||
private final SoundManager soundManager;
|
private final SoundManager soundManager;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private final DatabaseService databaseService;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@NonNull
|
@NonNull
|
||||||
private final GameRunner gameRunner;
|
private final GameRunner gameRunner;
|
||||||
@@ -145,6 +153,25 @@ public class DefaultContext implements Context {
|
|||||||
return soundManager.loadObject(soundUid);
|
return soundManager.loadObject(soundUid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void withDatabase(UncheckedConsumer<Connection, SQLException> consumer) {
|
||||||
|
try (var connection = databaseService.getConnection()) {
|
||||||
|
consumer.accept(connection);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error("SQL Error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T withDatabase(UncheckedFunction<Connection, T, SQLException> extractor) {
|
||||||
|
try (var connection = databaseService.getConnection()) {
|
||||||
|
return extractor.apply(connection);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
log.error("SQL Error", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disposeSound(Sound sound) {
|
public void disposeSound(Sound sound) {
|
||||||
soundManager.disposeSound(sound);
|
soundManager.disposeSound(sound);
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.bartlomiejpluta.base.engine.database.service;
|
||||||
|
|
||||||
|
import com.bartlomiejpluta.base.engine.common.init.Initializable;
|
||||||
|
import com.bartlomiejpluta.base.internal.gc.Cleanable;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
|
||||||
|
public interface DatabaseService extends Initializable, Cleanable {
|
||||||
|
Connection getConnection();
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package com.bartlomiejpluta.base.engine.database.service;
|
||||||
|
|
||||||
|
import com.bartlomiejpluta.base.engine.project.config.ProjectConfiguration;
|
||||||
|
import com.bartlomiejpluta.base.engine.util.res.ResourcesManager;
|
||||||
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.h2.tools.RunScript;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.sql.Connection;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
|
public class H2DatabaseService implements DatabaseService {
|
||||||
|
private static final String CONNECTION_STRING = "jdbc:h2:mem:main";
|
||||||
|
private final ProjectConfiguration configuration;
|
||||||
|
private final ResourcesManager resourcesManager;
|
||||||
|
private HikariDataSource source;
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
@Override
|
||||||
|
public void init() {
|
||||||
|
log.info("Starting in-memory database");
|
||||||
|
HikariConfig config = new HikariConfig();
|
||||||
|
config.setJdbcUrl(CONNECTION_STRING);
|
||||||
|
this.source = new HikariDataSource(config);
|
||||||
|
|
||||||
|
log.info("Loading data into in-memory database");
|
||||||
|
var data = resourcesManager.loadResourceAsStream(configuration.getDatabaseScriptFile());
|
||||||
|
RunScript.execute(getConnection(), new InputStreamReader(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
@Override
|
||||||
|
public Connection getConnection() {
|
||||||
|
return source.getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cleanUp() {
|
||||||
|
log.info("Closing in-memory database connection pool");
|
||||||
|
source.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ import java.nio.file.Path;
|
|||||||
public class ProjectConfiguration {
|
public class ProjectConfiguration {
|
||||||
private String mainFile;
|
private String mainFile;
|
||||||
private String resourcePath;
|
private String resourcePath;
|
||||||
|
private String databaseScriptFile;
|
||||||
|
|
||||||
public String projectFile(String... path) {
|
public String projectFile(String... path) {
|
||||||
return Path.of(resourcePath, path).toString().replaceAll("\\\\", "/");
|
return Path.of(resourcePath, path).toString().replaceAll("\\\\", "/");
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ app:
|
|||||||
project:
|
project:
|
||||||
main-file: project.bep
|
main-file: project.bep
|
||||||
resource-path: /project
|
resource-path: /project
|
||||||
|
database-script-file: /database/data.sql
|
||||||
|
|
||||||
sprite:
|
sprite:
|
||||||
entity:
|
entity:
|
||||||
|
|||||||
Reference in New Issue
Block a user