Skip to content

Commit

Permalink
Remove SQLite JDBC
Browse files Browse the repository at this point in the history
  • Loading branch information
zbx1425 committed Jul 21, 2023
1 parent 1598a4f commit 33b7c78
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 240 deletions.
5 changes: 0 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,6 @@ subprojects {
officialMojangMappings()
parchment("org.parchmentmc.data:parchment-${minecraft_version}:${parchment_version}@zip")
}

implementation 'org.xerial:sqlite-jdbc:3.42.0.0'
if (!rootProject.properties.containsKey("noShadowSqlite")) {
shadowCommon 'org.xerial:sqlite-jdbc:3.42.0.0'
}
}
}

Expand Down
20 changes: 7 additions & 13 deletions common/src/main/java/cn/zbx1425/worldcomment/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,26 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;
import java.io.IOException;

public class Main {

public static final String MOD_ID = "worldcomment";

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

public static Database DATABASE;

public static final RegistryObject<Item> ITEM_COMMENT_TOOL = new RegistryObject<>(CommentToolItem::new);

public static void init(RegistriesWrapper registries) {
registries.registerItem("comment_tool", ITEM_COMMENT_TOOL, CreativeModeTabs.TOOLS_AND_UTILITIES);

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);
DATABASE = new Database(server);
DATABASE.load();
} catch (IOException e) {
LOGGER.error("Failed to open data storage", e);
throw new RuntimeException(e);
}
});
Expand Down
99 changes: 58 additions & 41 deletions common/src/main/java/cn/zbx1425/worldcomment/data/CommentEntry.java
Original file line number Diff line number Diff line change
@@ -1,73 +1,90 @@
package cn.zbx1425.worldcomment.data;

import io.netty.buffer.Unpooled;
import net.minecraft.core.BlockPos;
import net.minecraft.core.UUIDUtil;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.ChunkPos;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.UUID;

public class CommentEntry {

public static int REGION_SHIFT = 2;

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

public CommentEntry(CommentTable table, ResultSet result) throws SQLException {
int iota = 0;
id = result.getLong(++iota);
timestamp = result.getLong(++iota);
deleted = result.getBoolean(++iota);
level = 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);
public long fileOffset;

public CommentEntry(Player initiator, BlockPos placedAt, int messageType, String message, String imageUrl) {
id = Database.SNOWFLAKE.nextId();
timestamp = System.currentTimeMillis();
level = initiator.level().dimension().location();
location = placedAt;
region = new ChunkPos(location.getX() >> REGION_SHIFT, location.getZ() >> REGION_SHIFT);
this.initiator = initiator.getGameProfile().getId();
initiatorName = initiator.getGameProfile().getName();
this.messageType = messageType;
this.message = message;
deleted = false;
this.imageUrl = imageUrl;
}

public CommentEntry(ResourceLocation level, FriendlyByteBuf src) {
fileOffset = src.readerIndex();
id = src.readLong();
timestamp = src.readLong();
this.level = level;
location = src.readBlockPos();
region = new ChunkPos(location.getX() >> REGION_SHIFT, location.getZ() >> REGION_SHIFT);
initiator = src.readUUID();
initiatorName = src.readUtf();
messageType = src.readInt();
message = src.readUtf();
deleted = src.readBoolean();
imageUrl = src.readUtf();
src.skipBytes(16 - (src.readerIndex() % 16));
}

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

public void insertTo(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) id = Database.SNOWFLAKE.nextId();
params.setLong(++iota, id);
params.setLong(++iota, timestamp);
params.setBoolean(++iota, deleted);
params.setInt(++iota, table.db.dimensions.getDimensionId(level));
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);
});
public void writeBuffer(FriendlyByteBuf dst) {
dst.writeLong(id);
dst.writeLong(timestamp);
dst.writeBlockPos(location);
dst.writeUUID(initiator);
dst.writeUtf(initiatorName);
dst.writeInt(messageType);
dst.writeUtf(message);
dst.writeBoolean(deleted);
dst.writeUtf(imageUrl);
dst.writeZero(16 - (dst.writerIndex() % 16));
}

public void writeFileStream(FileOutputStream oStream) throws IOException {
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer(256));
writeBuffer(buf);
fileOffset = oStream.getChannel().position();
oStream.write(buf.array(), 0, buf.writerIndex());
}

}
111 changes: 59 additions & 52 deletions common/src/main/java/cn/zbx1425/worldcomment/data/CommentTable.java
Original file line number Diff line number Diff line change
@@ -1,75 +1,82 @@
package cn.zbx1425.worldcomment.data;

import io.netty.buffer.Unpooled;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;

import java.sql.ResultSet;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
import java.util.stream.Stream;

public class CommentTable {

public final Database db;
public int maxId;

Map<ResourceLocation, Long2ObjectMap<List<CommentEntry>>> regionIndex = new HashMap<>();
Map<UUID, List<CommentEntry>> playerIndex = new HashMap<>();

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

public void init() throws SQLException {
db.execute("""
CREATE TABLE IF NOT EXISTS comments (
id INTEGER PRIMARY KEY,
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 load() throws IOException {
Files.createDirectories(db.basePath.resolve("regions"));
for (Level level : db.server.getAllLevels()) {
ResourceLocation dimension = level.dimension().location();
Path levelPath = getLevelPath(dimension);
Files.createDirectory(levelPath);
regionIndex.put(dimension, new Long2ObjectOpenHashMap<>());
try (Stream<Path> files = Files.list(levelPath)) {
for (Path file : files.toList()) {
long region = Long.parseUnsignedLong(file.getFileName().toString().substring(1, 9), 16);
List<CommentEntry> regionEntries = new ArrayList<>();
regionIndex.get(dimension).put(region, regionEntries);

public List<CommentEntry> queryInRegion(ResourceLocation level, ChunkPos region) throws SQLException {
ArrayList<CommentEntry> entries = new ArrayList<>();
try (ResultSet result = db.executeQuery(
"SELECT * FROM comments WHERE level = ? AND region = ?", params -> {
params.setInt(1, db.dimensions.getDimensionId(level));
params.setLong(2, region.toLong());
}
)) {
while (result.next()) {
entries.add(new CommentEntry(this, result));
byte[] fileContent = Files.readAllBytes(file);
FriendlyByteBuf src = new FriendlyByteBuf(Unpooled.wrappedBuffer(fileContent));
while (src.readerIndex() < fileContent.length - 1) {
CommentEntry entry = new CommentEntry(dimension, src);
regionEntries.add(entry);
playerIndex.computeIfAbsent(entry.initiator, ignored -> new ArrayList<>())
.add(entry);
}
}
}
}
return entries;
}

public List<CommentEntry> queryInTime(long from) throws SQLException {
ArrayList<CommentEntry> entries = new ArrayList<>();
try (ResultSet result = db.executeQuery(
"SELECT * FROM comments WHERE timestamp > ?", params -> {
params.setLong(1, from);
}
)) {
while (result.next()) {
entries.add(new CommentEntry(this, result));
}
private Path getLevelPath(ResourceLocation dimension) {
return db.basePath.resolve("regions")
.resolve(dimension.getNamespace() + "+" + dimension.getPath());
}

private Path getLevelRegionPath(ResourceLocation dimension, ChunkPos region) {
return db.basePath.resolve("regions")
.resolve(dimension.getNamespace() + "+" + dimension.getPath())
.resolve("r" + Long.toHexString(region.toLong()) + ".bin");
}

public List<CommentEntry> queryInRegion(ResourceLocation level, ChunkPos region) throws SQLException {
return regionIndex.get(level).get(region.toLong());
}

public void insert(CommentEntry newEntry) throws IOException {
Path targetFile = getLevelRegionPath(newEntry.level, newEntry.region);
try (FileOutputStream oStream = new FileOutputStream(targetFile.toFile(), true)) {
newEntry.writeFileStream(oStream);
}
return entries;
regionIndex.get(newEntry.level)
.computeIfAbsent(newEntry.region.toLong(), ignored -> new ArrayList<>())
.add(newEntry);
playerIndex.computeIfAbsent(newEntry.initiator, ignored -> new ArrayList<>())
.add(newEntry);
}
}
Loading

0 comments on commit 33b7c78

Please sign in to comment.