Skip to content

Commit

Permalink
Add database models
Browse files Browse the repository at this point in the history
  • Loading branch information
zbx1425 committed Jul 20, 2023
1 parent ace07a7 commit c810cb4
Show file tree
Hide file tree
Showing 9 changed files with 316 additions and 7 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
build:
strategy:
matrix:
minecraft: [ 1.19.2, 1.20.1 ]
minecraft: [ 1.20.1 ]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ checkouts

# OpenBVE images
*.bmp
/test.sqlite

# manifold
build.properties
Expand Down
9 changes: 7 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ if (localProperties.containsKey("MC_VERSION")) {
Integer.toString(Integer.parseInt(notDotted.substring(1, 3))) + "." +
Integer.toString(Integer.parseInt(notDotted.substring(3, 5)))
minecraft_version = dotted
System.out.println(minecraft_version)
} else {
minecraft_version = rootProject.properties.containsKey("buildVersion") ? rootProject.properties.get("buildVersion") : default_minecraft_version
}
Expand Down Expand Up @@ -68,14 +67,20 @@ subprojects {
silentMojangMappingsLicense()
}

configurations {
shadowCommon
}

dependencies {
annotationProcessor 'systems.manifold:manifold-preprocessor:2023.1.10'
minecraft "com.mojang:minecraft:${minecraft_version}"
mappings parchment_not_avail ? loom.officialMojangMappings() : loom.layered() {
officialMojangMappings()
parchment("org.parchmentmc.data:parchment-${minecraft_version}:${parchment_version}@zip")
}
implementation files("../checkouts/mtr-common.jar")

implementation 'org.xerial:sqlite-jdbc:3.42.0.0'
shadowCommon 'org.xerial:sqlite-jdbc:3.42.0.0'
}
}

Expand Down
26 changes: 22 additions & 4 deletions common/src/main/java/cn/zbx1425/worldcomment/Main.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
package cn.zbx1425.worldcomment;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import cn.zbx1425.worldcomment.data.Database;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;

public class Main {

public static final String MOD_ID = "worldcomment";

public static final Logger LOGGER = LogManager.getLogger("Subnoteica");
public static final Logger LOGGER = LoggerFactory.getLogger("Subnoteica");

public static void init() {

ServerPlatform.registerServerStartingEvent(server -> {
try {
Database.loadDatabase(server);
} catch (SQLException e) {
LOGGER.error("Failed to open database", e);
throw new RuntimeException(e);
}
});
ServerPlatform.registerServerStoppingEvent(server -> {
try {
Database.INSTANCE.close();
} catch (SQLException e) {
LOGGER.error("Failed to close database", e);
throw new RuntimeException(e);
}
});
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package cn.zbx1425.worldcomment.data;

import net.minecraft.core.BlockPos;
import net.minecraft.core.UUIDUtil;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.ChunkPos;

import java.nio.ByteBuffer;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.UUID;

public class CommentEntry {

public int id;
public long timestamp;
public boolean deleted;
public ResourceLocation dimension;
public ChunkPos region;
public BlockPos location;
public UUID initiator;
public String initiatorName;
public int messageType;
public String message;
public String imageUrl;

public CommentEntry(CommentTable table, ResultSet result) throws SQLException {
int iota = 0;
id = result.getInt(++iota);
timestamp = result.getLong(++iota);
deleted = result.getBoolean(++iota);
dimension = table.db.dimensions.getDimensionById(result.getInt(++iota));
region = new ChunkPos(result.getLong(++iota));
location = new BlockPos(result.getInt(++iota), result.getInt(++iota), result.getInt(++iota));
initiator = uuidFromByteArray(result.getBytes(++iota));
initiatorName = result.getString(++iota);
messageType = result.getInt(++iota);
message = result.getString(++iota);
imageUrl = result.getString(++iota);
}

private static UUID uuidFromByteArray(byte[] bytes) {
ByteBuffer bb = ByteBuffer.wrap(bytes);
return new UUID(bb.getLong(), bb.getLong());
}

public void insertOrUpdate(CommentTable table) throws SQLException {
table.db.execute("""
INSERT OR REPLACE INTO comments (
id, timestamp, deleted, level, region, locationX, locationY, locationZ, initiator, initiatorName, messageType, message, imageUrl
) VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
);
""", params -> {
int iota = 0;
if (id == 0) {
params.setNull(++iota, Types.INTEGER);
} else {
params.setInt(++iota, id);
}
params.setLong(++iota, timestamp);
params.setBoolean(++iota, deleted);
params.setInt(++iota, table.db.dimensions.getDimensionId(dimension));
params.setLong(++iota, region.toLong());
params.setInt(++iota, location.getX());
params.setInt(++iota, location.getY());
params.setInt(++iota, location.getZ());
params.setBytes(++iota, UUIDUtil.uuidToByteArray(initiator));
params.setString(++iota, initiatorName);
params.setInt(++iota, messageType);
params.setString(++iota, message);
params.setString(++iota, imageUrl);
});
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package cn.zbx1425.worldcomment.data;

import java.sql.ResultSet;
import java.sql.SQLException;

public class CommentTable {

public final Database db;
public int maxId;

public CommentTable(Database db) {
this.db = db;
}

public void init() throws SQLException {
db.execute("""
CREATE TABLE IF NOT EXISTS comments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp INTEGER,
deleted INTEGER,
level INTEGER,
region INTEGER,
locationX INTEGER,
locationY INTEGER,
locationZ INTEGER,
initiator BLOB,
initiatorName TEXT,
messageType INTEGER,
message TEXT,
imageUrl TEXT
);
CREATE INDEX IF NOT EXISTS regionIndex ON comments (
level,
region
);
CREATE INDEX IF NOT EXISTS timestampIndex ON comments (
timestamp
);
""");
}

public void fetchMaxId() throws SQLException {
try (ResultSet result = db.executeQuery("SELECT id FROM comments ORDER BY id DESC LIMIT 1;")) {
if (!result.next()) {
maxId = 0;
} else {
maxId = result.getInt(1);
}
}
}
}
77 changes: 77 additions & 0 deletions common/src/main/java/cn/zbx1425/worldcomment/data/Database.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package cn.zbx1425.worldcomment.data;

import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.storage.LevelResource;

import java.nio.file.Path;
import java.sql.*;
import java.util.HashMap;
import java.util.function.Consumer;

public class Database {

public static Database INSTANCE;

private final Connection dbConn;

public final CommentTable comments;

public final DimensionTable dimensions;

public Database(Path dbPath) throws SQLException {
dbConn = DriverManager.getConnection("jdbc:sqlite:" + dbPath);
comments = new CommentTable(this);
dimensions = new DimensionTable(this);
init();
}

public static void loadDatabase(MinecraftServer server) throws SQLException {
INSTANCE = new Database(
Path.of(server.getWorldPath(LevelResource.ROOT).toString(), "world-comment.db")
);
}

public void close() throws SQLException {
for (PreparedStatement stmt : preparedStatements.values()) {
stmt.close();
}
preparedStatements.clear();
dbConn.close();
}

private void init() throws SQLException {
comments.init();
dimensions.init();
}

private final HashMap<String, PreparedStatement> preparedStatements = new HashMap<>();

public void execute(String command) throws SQLException {
prepareStatement(command).execute();
}

public void execute(String command, StatementConsumer params) throws SQLException {
PreparedStatement stmt = prepareStatement(command);
params.accept(stmt);
stmt.execute();
}

public ResultSet executeQuery(String command) throws SQLException {
return prepareStatement(command).executeQuery();
}

public ResultSet executeQuery(String command, StatementConsumer params) throws SQLException {
PreparedStatement stmt = prepareStatement(command);
params.accept(stmt);
return stmt.executeQuery();
}

private PreparedStatement prepareStatement(String command) throws SQLException {
PreparedStatement stmt = preparedStatements.get(command);
if (stmt == null) {
stmt = dbConn.prepareStatement(command);
preparedStatements.put(command, stmt);
}
return stmt;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package cn.zbx1425.worldcomment.data;

import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectList;
import net.minecraft.resources.ResourceLocation;

import java.sql.ResultSet;
import java.sql.SQLException;

public class DimensionTable {

public Database db;

public Object2IntMap<ResourceLocation> dimensionMap = new Object2IntOpenHashMap<>();
public ObjectList<ResourceLocation> idMap = new ObjectArrayList<>();

public DimensionTable(Database db) {
this.db = db;
}

public void init() throws SQLException {
db.execute("""
CREATE TABLE IF NOT EXISTS dimensions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
resourceLocation TEXT
);
""");
dimensionMap.clear();
try (ResultSet result = db.executeQuery("SELECT * FROM dimensions;")) {
while (result.next()) {
ResourceLocation name = new ResourceLocation(result.getString(2));
int id = result.getInt(1);
dimensionMap.put(name, id);
idMap.size(Math.max(idMap.size(), id));
idMap.set(id - 1, name);
}
}
}

public int getMaxId() throws SQLException {
try (ResultSet result = db.executeQuery("SELECT id FROM dimensions ORDER BY id DESC LIMIT 1;")) {
if (!result.next()) {
return 0;
} else {
return result.getInt(1);
}
}
}

public ResourceLocation getDimensionById(int id) {
return idMap.get(id - 1);
}

public int getDimensionId(ResourceLocation dimension) throws SQLException {
if (!dimensionMap.containsKey(dimension)) {
db.execute("INSERT INTO dimensions (resourceLocation) VALUES (?);", params -> {
params.setString(1, dimension.toString());
});
int newId = getMaxId();
dimensionMap.put(dimension, newId);
idMap.size(Math.max(idMap.size(), newId));
idMap.set(newId - 1, dimension);
return newId;
} else {
return dimensionMap.getInt(dimension);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package cn.zbx1425.worldcomment.data;

import java.sql.PreparedStatement;
import java.sql.SQLException;

@FunctionalInterface
public interface StatementConsumer {

void accept(PreparedStatement stmt) throws SQLException;
}

0 comments on commit c810cb4

Please sign in to comment.