Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
514d60d
Switch to Bun
Protonull Jun 10, 2025
62164a9
Switch to bun:sqlite
Protonull Jun 10, 2025
3e2db02
Fix server port compilation issue
Protonull Jun 10, 2025
b85a19f
Update BufWriter to use ArrayBufferSink
Protonull Jun 10, 2025
a63ce4d
Switch to Bun.listen()
Protonull Jun 10, 2025
ee41818
Fix type-import warnings
Protonull Jun 10, 2025
8c03847
Add compile-to-executable build script
Protonull Jun 10, 2025
037628e
Minor fixup of packet serialisation
Protonull Jun 10, 2025
29baa44
Move encryption and ciphers to crypto file
Protonull Jun 10, 2025
ffe097d
Update typescript version
Protonull Jun 10, 2025
e79d43c
Resolve ProtocolHandler cleanup todo
Protonull Jun 10, 2025
3c6e558
Consolidate packets into single file
Protonull Jun 10, 2025
0956769
Consolidate buffer helper classes into single file
Protonull Jun 10, 2025
d26820d
Run prettier
Protonull Jun 10, 2025
d75a4a4
Slight reorganisation
Protonull Jun 10, 2025
13b09aa
Switch handshake and auth to a state model
Protonull Jun 10, 2025
d429342
Switch to websockets
Protonull Jun 10, 2025
b0f377f
Drastically improve database performance
Protonull Jun 11, 2025
1810c87
Set max frame/payload length to max u16 value
Protonull Jun 11, 2025
e7e5700
Turns out where-in is WAY more efficient than where-and-or-chaining
Protonull Jun 11, 2025
26bae6b
Fix Zod dependency error
Protonull Jun 11, 2025
632bca3
Add gen prefixes to columns and add transactions
Protonull Jun 11, 2025
003df47
Add database migrations
Protonull Jun 11, 2025
71ba397
Update workflows
Protonull Jun 14, 2025
de077a4
Create database test
Protonull Jun 14, 2025
8de3cb4
Destaticify database connection
Protonull Jun 14, 2025
5261d2b
Fix websocket close handler
Protonull Jun 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 10 additions & 29 deletions .github/workflows/build-mod.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build Mod
name: "Build Mods"

on:
push:
Expand All @@ -7,39 +7,20 @@ on:
pull_request:
paths:
- "mod/**/*"
workflow_call:

jobs:
build:
runs-on: ubuntu-latest
runs-on: "ubuntu-latest"
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
- uses: "actions/checkout@v4"

- name: "Setting up JDK 17"
uses: "actions/setup-java@v4"
with:
java-version: "17"
distribution: "adopt"
- run: ./gradlew build
working-directory: ./mod

- name: Upload Forge Build
uses: actions/upload-artifact@v3
with:
name: Forge
path: mod/dist/*-forge.jar

- name: Upload Fabric Build
uses: actions/upload-artifact@v3
with:
name: Fabric
path: mod/dist/*-fabric.jar

- name: Release Tag
if: startsWith(github.ref, 'refs/tags/v')
uses: softprops/action-gh-release@v1
with:
prerelease: true
fail_on_unmatched_files: true
files: |
mod/dist/*.jar
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: "Building mods"
working-directory: "./mod"
run: "./gradlew build"
40 changes: 24 additions & 16 deletions .github/workflows/build-server.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build+Test Server
name: "Build+Test Server"

on:
push:
Expand All @@ -7,23 +7,31 @@ on:
pull_request:
paths:
- "server/**/*"
workflow_call:

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
version: ["lts/*", "latest"]
runs-on: "ubuntu-latest"
steps:
- uses: actions/checkout@v3
- name: Use latest Node.js LTS
uses: actions/setup-node@v3
- uses: "actions/checkout@v4"

- name: "Setting up Bun"
uses: oven-sh/setup-bun@v2
with:
node-version: ${{ matrix.version }}
# cache: "yarn"
- run: yarn
working-directory: ./server
- run: yarn build
working-directory: ./server
- run: yarn test
working-directory: ./server
bun-version: latest

- name: "Installing dependencies"
working-directory: "./server"
run: "bun install"

- name: "Checking types"
working-directory: "./server"
run: "bun run check:types"

- name: "Checking style"
working-directory: "./server"
run: "bun run check:style"

- name: "Running tests"
working-directory: "./server"
run: "bun run test"
35 changes: 35 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: "Publishing to release"

on:
release:
types:
- "published"

permissions:
contents: "write"

jobs:
release-mod:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v4"

- name: "Setting up JDK 17"
uses: "actions/setup-java@v4"
with:
java-version: "17"
distribution: "adopt"

- name: "Building mods"
working-directory: "./mod"
run: "./gradlew build"

- name: "Publishing mods"
working-directory: "./mod"
run: |
for file in $(find "dist/" -maxdepth 1 -type f -name "*.jar"); do
echo "Uploading $file"
gh release upload ${{ github.event.release.tag_name }} "$file" --clobber
done
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22 changes: 11 additions & 11 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# base is shared between build/test and deploy
FROM node:18-alpine AS base
# See options at: https://hub.docker.com/r/oven/bun
FROM oven/bun:latest AS base

WORKDIR /usr/src/app/

Expand All @@ -8,29 +9,28 @@ COPY ./server/package.json /usr/src/app/package.json

FROM base AS build

COPY ./server/yarn.lock /usr/src/app/yarn.lock
RUN yarn
COPY ./server/bun.lock /usr/src/app/bun.lock
COPY ./server/bunfig.toml /usr/src/app/bunfig.toml
RUN bun install

# copy source as late as possible, to reuse docker cache with node_modules
COPY ./server /usr/src/app
RUN yarn build

FROM build AS test
RUN yarn test

# final image only includes minimal files
FROM base AS deploy

COPY --from=build /usr/src/app/bun.lock /usr/src/app/bun.lock
COPY --from=build /usr/src/app/bunfig.toml /usr/src/app/bunfig.toml
COPY --from=build /usr/src/app/node_modules /usr/src/app/node_modules
COPY --from=build /usr/src/app/dist /usr/src/app/dist
COPY --from=build /usr/src/app/src /usr/src/app/src

ENV NODE_ENV=production
ENV HOST=0.0.0.0

#Mount your FS or volume or whatnot to this folder
RUN mkdir /data
# TODO: Fix env override of config data
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

did you ever fix the config thing we talked about? i forget the specifics but I remember there being some issue with it in docker.

ENV MAPSYNC_DATA_DIR=/data

EXPOSE 12312/tcp
# EXPOSE 12312/tcp

CMD [ "yarn", "start" ]
CMD [ "bun", "run", "start" ]
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,10 @@ You can control who has access to a Sync Server by editing its `allowed-users.tx
<summary>System Install</summary>
<br />

- install recent nodejs (~17)
- install [Bun](https://bun.sh/)
- clone code, `cd server`
- `npm install`
- `npm run build` -- this has to be run after every time the code is edited
- `npm run start`
- `bun install`
- `bun start`
- to stop, press Ctrl+C twice
</details>

Expand Down
3 changes: 3 additions & 0 deletions mod/common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ dependencies {
modCompileOnly("maven.modrinth:journeymap:5JbcGXLn")
// https://modrinth.com/mod/xaeros-minimap/version/23.6.2_Fabric_1.18.2 (23.6.2 fabric)
modCompileOnly("maven.modrinth:xaeros-minimap:Jwydpps9")

// https://github.com/TooTallNate/Java-WebSocket
compileOnly("org.java-websocket:Java-WebSocket:1.6.0")
}

tasks {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public void addCatchupChunks(List<CatchupChunk> catchupChunks) {
if (catchupChunks.isEmpty()) return;
var catchupDim = catchupChunks.get(0).dimension();
if (!dimensionState.dimension.equals(catchupDim)) {
logger.warn("Catchup chunks from wrong dimension " + catchupDim + ", expected " + dimensionState.dimension);
LOGGER.warn("Catchup chunks from wrong dimension " + catchupDim + ", expected " + dimensionState.dimension);
return;
}
synchronized (this.catchupChunks) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,23 @@
import gjum.minecraft.mapsync.common.config.ModConfig;
import gjum.minecraft.mapsync.common.config.ServerConfig;
import gjum.minecraft.mapsync.common.data.*;
import gjum.minecraft.mapsync.common.net.SyncAddress;
import gjum.minecraft.mapsync.common.net.SyncClient;
import gjum.minecraft.mapsync.common.net.packet.*;
import java.util.stream.Collectors;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.network.protocol.game.ClientboundLoginPacket;
import net.minecraft.network.protocol.game.ClientboundRespawnPacket;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;

import java.util.*;
import java.util.stream.Collectors;

import static gjum.minecraft.mapsync.common.Cartography.chunkTileFromLevel;

Expand All @@ -27,7 +29,7 @@ public abstract class MapSyncMod {

private static final Minecraft mc = Minecraft.getInstance();

public static final Logger logger = LogManager.getLogger(MapSyncMod.class);
public static final Logger LOGGER = LogManager.getLogger(MapSyncMod.class);

private static MapSyncMod INSTANCE;

Expand Down Expand Up @@ -123,30 +125,41 @@ public void handleRespawn(ClientboundRespawnPacket packet) {
if (syncServerAddresses.isEmpty()) return shutDownSyncClients();

// will be filled with clients that are still wanted (address) and are still connected
var existingClients = new HashMap<String, SyncClient>();
var existingClients = new HashMap<SyncAddress, SyncClient>();

for (SyncClient client : syncClients) {
if (client.isShutDown) continue;
for (final SyncClient client : this.syncClients) {
if (client.isShutDown) {
continue;
}
// avoid reconnecting to same sync server, to keep shared state (expensive to resync)
if (!client.gameAddress.equals(serverConfig.gameAddress)) {
debugLog("Disconnecting sync client; different game server");
if (!StringUtils.equals(client.gameAddress, serverConfig.gameAddress)) {
LOGGER.warn("Disconnecting sync client; different game server");
client.shutDown();
} else if (!syncServerAddresses.contains(client.address)) {
debugLog("Disconnecting sync client; different sync address");
}
else if (!syncServerAddresses.contains(client.syncAddress.toString())) {
LOGGER.warn("Disconnecting sync client; different sync address");
client.shutDown();
} else {
existingClients.put(client.address, client);
}
else {
existingClients.put(client.syncAddress, client);
}
}

syncClients = syncServerAddresses.stream().map(address -> {
var client = existingClients.get(address);
if (client == null) client = new SyncClient(address, serverConfig.gameAddress);
client.autoReconnect = true;
return client;
}).collect(Collectors.toList());

return syncClients;
this.syncClients = syncServerAddresses.stream()
.map(SyncAddress::of)
.filter(Objects::nonNull)
.distinct()
.map((address) -> {
SyncClient client = existingClients.get(address);
if (client == null) {
client = new SyncClient(address, serverConfig.gameAddress);
}
client.autoReconnect = true;
return client;
})
.collect(Collectors.toCollection(ArrayList::new));

return this.syncClients;
}

public List<SyncClient> shutDownSyncClients() {
Expand Down Expand Up @@ -214,11 +227,6 @@ public void handleMcChunkPartialChange(int cx, int cz) {
// TODO update ChunkTile in a second or so; remember dimension in case it changes til then
}

public void handleSyncServerEncryptionSuccess() {
debugLog("tcp encrypted");
// TODO tell server our current dimension
}

public void handleRegionTimestamps(ClientboundRegionTimestampsPacket packet, SyncClient client) {
DimensionState dimension = getDimensionState();
if (dimension == null) return;
Expand Down Expand Up @@ -258,7 +266,7 @@ public void handleSharedChunk(ChunkTile chunkTile) {
public void handleCatchupData(ClientboundChunkTimestampsResponsePacket packet) {
var dimensionState = getDimensionState();
if (dimensionState == null) return;
debugLog("received catchup: " + packet.chunks.size() + " " + packet.chunks.get(0).syncClient.address);
debugLog("received catchup: " + packet.chunks.size() + " " + packet.chunks.get(0).syncClient.syncAddress);
dimensionState.addCatchupChunks(packet.chunks);
}

Expand All @@ -269,9 +277,9 @@ public void requestCatchupData(List<CatchupChunk> chunks) {
}

debugLog("requesting more catchup: " + chunks.size());
var byServer = new HashMap<String, List<CatchupChunk>>();
var byServer = new HashMap<SyncAddress, List<CatchupChunk>>();
for (CatchupChunk chunk : chunks) {
var list = byServer.computeIfAbsent(chunk.syncClient.address, (a) -> new ArrayList<>());
var list = byServer.computeIfAbsent(chunk.syncClient.syncAddress, (a) -> new ArrayList<>());
list.add(chunk);
}
for (List<CatchupChunk> chunksForServer : byServer.values()) {
Expand All @@ -283,7 +291,7 @@ public void requestCatchupData(List<CatchupChunk> chunks) {
public static void debugLog(String msg) {
// we could also make use of slf4j's debug() but I don't know how to reconfigure that at runtime based on globalConfig
if (modConfig.isShowDebugLog()) {
logger.info(msg);
LOGGER.info(msg);
}
}
}
Loading