Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import gjum.minecraft.mapsync.mod.net.CloseContext;
import gjum.minecraft.mapsync.mod.net.Packet;
import gjum.minecraft.mapsync.mod.net.SyncClient;
import gjum.minecraft.mapsync.mod.net.packet.ServerboundDimensionChangePacket;
import gjum.minecraft.mapsync.mod.sync.DimensionState;
import gjum.minecraft.mapsync.mod.sync.GameContext;
import gjum.minecraft.mapsync.mod.net.UnexpectedPacketException;
Expand All @@ -31,6 +32,7 @@
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientChunkEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
Expand Down Expand Up @@ -132,14 +134,36 @@ public static void handleSyncPacket(
}
}

/// @param clientLevel This is the *new* dimension.
public static void handleWelcomed(
final @NotNull SyncClient client
) {
if (client.gameContext.getDimensionState().orElse(null) instanceof final DimensionState dimensionState) {
client.send(new ServerboundDimensionChangePacket(
dimensionState.dimension.identifier()
));
}
}

public static void handleGameConnection(
final @NotNull Minecraft minecraft,
final @NotNull GameContext gameContext
) {
if (gameContext.getGameConfig().shouldAutoConnect()) {
gameContext.getSyncConnections().setAll(Set.copyOf(
gameContext.getGameConfig().getSyncServerAddresses()
));
}
}

/// @param level This is the *new* dimension.
public static void handleDimensionChange(
final @NotNull Minecraft minecraft,
final @NotNull ClientLevel clientLevel,
final @NotNull ClientLevel level,
final @NotNull GameContext gameContext
) {
debugLog("handleDimensionChange");
// TODO tell sync server to only send chunks for this dimension now
gameContext.getSyncConnections().broadcast(new ServerboundDimensionChangePacket(
level.dimension().identifier()
));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public final class ServerConfig extends JsonConfig {
@Expose
private ArrayList<String> syncServerAddresses = new ArrayList<>();

@Expose
private boolean autoConnect = false;

public @NotNull List<@NotNull String> getSyncServerAddresses() {
return this.syncServerAddresses.stream()
.map(String::trim)
Expand All @@ -27,6 +30,16 @@ public void setSyncServerAddresses(
this.syncServerAddresses = new ArrayList<>(syncAddresses);
}

public boolean shouldAutoConnect() {
return this.autoConnect;
}

public void setAutoConnect(
final boolean autoConnect
) {
this.autoConnect = autoConnect;
}

@Override
public void resetToDefaults() {
this.setSyncServerAddresses(List.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.Set;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.Checkbox;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.network.chat.CommonComponents;
Expand Down Expand Up @@ -40,13 +41,6 @@ protected void init() {
final int offsetRight = this.width / 2 + innerWidth / 2;
this.offsetTop = this.height / 3;

this.addRenderableWidget(
Button.builder(Component.literal("Close"), (button) -> this.minecraft.setScreen(this.parentScreen))
.pos(offsetRight - 100, this.offsetTop)
.width(100)
.build()
);

final EditBox addressField = this.addRenderableWidget(new EditBox(
this.font,
this.offsetLeft,
Expand All @@ -58,6 +52,17 @@ protected void init() {
addressField.setValue(this.addressFieldValue);
addressField.setResponder((value) -> this.addressFieldValue = value);

this.addRenderableWidget(
Checkbox.builder(Component.literal("Auto-connect"), this.font)
.pos(offsetRight - 100, this.offsetTop + 18)
.selected(this.gameContext.getGameConfig().shouldAutoConnect())
.onValueChange((checkbox, value) -> {
this.gameContext.getGameConfig().setAutoConnect(value);
this.gameContext.getGameConfig().save();
})
.build()
);

this.addRenderableWidget(
Button
.builder(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import gjum.minecraft.mapsync.mod.net.packet.ClientboundWelcomePacket;
import gjum.minecraft.mapsync.mod.net.packet.ServerboundCatchupRequestPacket;
import gjum.minecraft.mapsync.mod.net.packet.ServerboundChunkTimestampsRequestPacket;
import gjum.minecraft.mapsync.mod.net.packet.ServerboundDimensionChangePacket;
import gjum.minecraft.mapsync.mod.net.packet.ServerboundHandshakePacket;
import gjum.minecraft.mapsync.mod.net.packet.ServerboundIdentityResponsePacket;
import org.apache.commons.lang3.NotImplementedException;
Expand Down Expand Up @@ -43,6 +44,7 @@ public static void encodePacket(
case ChunkTilePacket $ -> ChunkTilePacket.PACKET_ID;
case ServerboundHandshakePacket $ -> ServerboundHandshakePacket.PACKET_ID;
case ServerboundIdentityResponsePacket $ -> ServerboundIdentityResponsePacket.PACKET_ID;
case ServerboundDimensionChangePacket $ -> ServerboundDimensionChangePacket.PACKET_ID;
case ServerboundChunkTimestampsRequestPacket $ -> ServerboundChunkTimestampsRequestPacket.PACKET_ID;
case ServerboundCatchupRequestPacket $ -> ServerboundCatchupRequestPacket.PACKET_ID;
default -> throw new UnexpectedPacketException(packet);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package gjum.minecraft.mapsync.mod.net.auth;

import gjum.minecraft.mapsync.mod.sync.DimensionState;
import gjum.minecraft.mapsync.mod.MapSyncMod;
import gjum.minecraft.mapsync.mod.net.SyncClient;
import gjum.minecraft.mapsync.mod.net.UnexpectedPacketException;
import gjum.minecraft.mapsync.mod.net.packet.ClientboundIdentityRequestPacket;
Expand All @@ -21,17 +21,12 @@ private record AwaitingIdentityRequest() implements AuthState {}
public static void sendHandshake(
final @NotNull SyncClient client
) throws Exception {
final DimensionState dimensionState = client.gameContext.getDimensionState().orElse(null);
if (dimensionState == null) {
throw new IllegalStateException("no dimension state");
}
if (!client.authState.setIf(Objects::isNull, AwaitingIdentityRequest::new)) {
throw new IllegalStateException("already authenticated");
}
client.send(new ServerboundHandshakePacket(
MagicValues.VERSION,
client.gameContext.getGameAddress(),
dimensionState.dimension.identifier().toString()
client.gameContext.getGameAddress()
));
}

Expand Down Expand Up @@ -74,5 +69,6 @@ public static void handleWelcome(
if (!client.authState.setIf((state) -> state instanceof AwaitingWelcome, Welcomed::new)) {
throw new UnexpectedPacketException(packet);
}
MapSyncMod.handleWelcomed(client);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@
import gjum.minecraft.mapsync.mod.net.buffers.BufferReader;
import org.jetbrains.annotations.NotNull;

/// This is sent by the server to indicate a successful connection: that the client can begin sending chunk data. The
/// server will immediately follow up this packet with a [ClientboundRegionTimestampsPacket].
/// This is sent by the server to indicate a successful connection. The client should then inform the server of its
/// current dimension via [ServerboundDimensionChangePacket], after which the client can begin sending chunk data for
/// that dimension.
///
/// - Prev: [ServerboundIdentityResponsePacket]
/// - Next: [ClientboundRegionTimestampsPacket]
/// - Next: [ServerboundDimensionChangePacket]
public record ClientboundWelcomePacket() implements Packet {
public static final int PACKET_ID = 9;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package gjum.minecraft.mapsync.mod.net.packet;

import gjum.minecraft.mapsync.mod.net.Packet;
import gjum.minecraft.mapsync.mod.net.buffers.BufferWriter;
import gjum.minecraft.mapsync.mod.utils.Assertions;
import net.minecraft.resources.Identifier;
import org.jetbrains.annotations.NotNull;

/// The client should send this to the server:
///
/// 1. Whenever the player changes dimension (such as going through a portal)
/// 2. Whenever a new sync connection is made while the player is already in-game.
///
/// - Prev: [ClientboundWelcomePacket]
/// - Next: [ClientboundRegionTimestampsPacket]
public record ServerboundDimensionChangePacket(
@NotNull Identifier dimension
) implements Packet {
public static final int PACKET_ID = 10;

public ServerboundDimensionChangePacket {
Assertions.assertNotNull(dimension);
}

@Override
public void write(
final @NotNull BufferWriter writer
) throws Exception {
writer.writeString(this.dimension().toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,13 @@
/// - Next: [ClientboundIdentityRequestPacket]
public record ServerboundHandshakePacket(
@NotNull String modVersion,
@NotNull GameAddress gameAddress,
@NotNull String dimension
@NotNull GameAddress gameAddress
) implements Packet {
public static final int PACKET_ID = 1;

public ServerboundHandshakePacket {
Assertions.assertNotNull(modVersion);
Assertions.assertNotNull(gameAddress);
Assertions.assertNotNull(dimension);
}

@Override
Expand All @@ -29,6 +27,5 @@ public void write(
) throws Exception {
writer.writeString(this.modVersion());
writer.writeString(this.gameAddress().address());
writer.writeString(this.dimension());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ public static void initEvents() {
}
}
});
ClientPlayConnectionEvents.JOIN.register((gameConnection, packetSender, minecraft) -> {
if (instance instanceof final GameContext context) {
MapSyncMod.handleGameConnection(minecraft, context);
}
});
ClientPlayConnectionEvents.DISCONNECT.register((gameConnection, minecraft) -> {
if (INSTANCE.getAndSet((Object) null) instanceof final GameContext context) {
context.shutdown();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gjum.minecraft.mapsync.mod.sync;

import gjum.minecraft.mapsync.mod.MapSyncMod;
import gjum.minecraft.mapsync.mod.net.Packet;
import gjum.minecraft.mapsync.mod.net.SyncClient;
import java.util.Iterator;
import java.util.Map;
Expand Down Expand Up @@ -87,4 +88,12 @@ public void closeAll(
return true;
});
}

public void broadcast(
final @NotNull Packet packet
) {
for (final SyncClient syncClient : this) {
syncClient.send(packet);
}
}
}
38 changes: 36 additions & 2 deletions mapsync-server/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
ClientboundWelcomePacket,
UnexpectedPacketError,
ClientboundIdentityRequestPacket,
ServerboundDimensionChangePacket,
} from "./packets.ts";
import {
AwaitingHandshake,
Expand Down Expand Up @@ -73,6 +74,8 @@ export class ProtocolHandler {
return this.handleCatchupRequest(client, pkt);
case pkt instanceof ChunkTilePacket:
return this.handleChunkTilePacket(client, pkt);
case pkt instanceof ServerboundDimensionChangePacket:
return this.handleDimensionChange(client, pkt);
default:
throw new Error(
`Unknown packet [${node_utils.inspect(pkt)}] from client ${client.id}`,
Expand All @@ -94,8 +97,6 @@ export class ProtocolHandler {
}
// TODO: Check whether the game address is supported
client.gameAddress = packet.gameAddress;
// TODO: Make this its own packet
client.dimension = packet.dimension;
const serverSalt: Buffer = this.config.auth
? node_crypto.randomBytes(32)
: Buffer.allocUnsafe(0);
Expand Down Expand Up @@ -172,6 +173,18 @@ export class ProtocolHandler {
// TODO check version, mc server, user access

client.send(new ClientboundWelcomePacket());
}

private async handleDimensionChange(
client: WSClient,
pkt: ServerboundDimensionChangePacket,
) {
if (client.isInDimension(pkt.dimension)) {
return;
}
// TODO: Stop any sync process of the previous dimension

client.dimension = pkt.dimension;

for (const region of await database.getRegionTimestamps(
client.dimension!,
Expand All @@ -193,6 +206,13 @@ export class ProtocolHandler {
) {
const welcome = client.requireWelcomed();

if (!client.isInDimension(pkt.dimension)) {
client.warn(
`Client send chunk data for [${pkt.dimension}] when their dimension is [${client.dimension}]!`,
);
return;
}

// TODO ignore if same chunk hash exists in db

await database
Expand Down Expand Up @@ -225,6 +245,13 @@ export class ProtocolHandler {
) {
const welcome = client.requireWelcomed();

if (!client.isInDimension(pkt.dimension)) {
client.warn(
`Client requested catchup for [${pkt.dimension}] when their dimension is [${client.dimension}]!`,
);
return;
}

for (const req of pkt.chunks) {
let chunk = await database.getChunkData(
pkt.dimension,
Expand Down Expand Up @@ -262,6 +289,13 @@ export class ProtocolHandler {
) {
const welcome = client.requireWelcomed();

if (!client.isInDimension(pkt.dimension)) {
client.warn(
`Client requested chunk timestamps for [${pkt.dimension}] when their dimension is [${client.dimension}]!`,
);
return;
}

const chunks = await database.getChunkTimestamps(
pkt.dimension,
pkt.regionX,
Expand Down
Loading