Skip to content

Commit

Permalink
Add support to send older version packets to servers
Browse files Browse the repository at this point in the history
  • Loading branch information
Aeltumn committed Aug 6, 2023
1 parent b577296 commit 37a2570
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 19 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ Server developers are welcome to submit additional patches they need, however al

# For developers

Any developers interested in writing code that interacts with Noxesium should have a look at the `api` module which contains various structures useful for setting up a server-side implementation that interacts with Noxesium. This modules
does not have a dependency on fabric and can thus be used as a dependency in server software.

## Player Heads

Noxesium supports rendering player heads into text through a custom skull component. The details of which can be found by looking into the contents
Expand Down
24 changes: 22 additions & 2 deletions fabric/src/main/java/com/noxcrew/noxesium/NoxesiumMod.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package com.noxcrew.noxesium;

import com.noxcrew.noxesium.feature.rule.ServerRuleModule;
import com.noxcrew.noxesium.feature.skull.CustomSkullFont;
import com.noxcrew.noxesium.feature.skull.SkullFontModule;
import com.noxcrew.noxesium.network.NoxesiumPackets;
import com.noxcrew.noxesium.network.serverbound.ServerboundClientInformationPacket;
import com.noxcrew.noxesium.network.serverbound.ServerboundClientSettingsPacket;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
import net.minecraft.client.Minecraft;
import net.minecraft.resources.ResourceLocation;
Expand Down Expand Up @@ -39,6 +37,11 @@ public class NoxesiumMod implements ClientModInitializer {
SkullFontModule.getInstance()
));

/**
* The current maximum supported protocol version.
*/
private static int currentMaxProtocol = VERSION;

/**
* Adds a new module to the list of modules that should have
* their hooks called. Available for other mods to use.
Expand All @@ -47,6 +50,20 @@ public static void registerModule(NoxesiumModule module) {
modules.add(module);
}

/**
* Returns the latest protocol version that is currently supported.
*/
public static int getMaxProtocolVersion() {
return currentMaxProtocol;
}

/**
* Stores the maximum protocol version of the current server.
*/
public static void setServerVersion(int maxProtocolVersion) {
currentMaxProtocol = maxProtocolVersion;
}

@Override
public void onInitializeClient() {
// Every time the client joins a server we send over information on the version being used
Expand All @@ -66,6 +83,9 @@ public void onInitializeClient() {
// Call disconnection hooks
ClientPlayConnectionEvents.DISCONNECT.register((ignored1, ignored2) -> {
modules.forEach(NoxesiumModule::onQuitServer);

// Reset the current max protocol version
currentMaxProtocol = VERSION;
});

// Register all universal messaging channels
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
* Hooks into the SoundSource enum to add additional custom values.
Expand All @@ -36,9 +37,15 @@ private static SoundSource createNewCategory(String fieldName, int ordinal, Stri
at = @At(value = "FIELD", target = "Lnet/minecraft/sounds/SoundSource;$VALUES:[Lnet/minecraft/sounds/SoundSource;", opcode = Opcodes.PUTSTATIC, shift = At.Shift.AFTER)
)
private static void modifyValues(CallbackInfo ci) {
// Avoid conflicts by checking if they already exist
var newValues = new ArrayList<>(List.of($VALUES));
newValues.add(createNewCategory("CORE_MUSIC", newValues.size(), "core_music"));
newValues.add(createNewCategory("GAME_MUSIC", newValues.size(), "game_music"));
var existingValues = newValues.stream().map(Enum::name).toList();
if (!existingValues.contains("CORE_MUSIC")) {
newValues.add(createNewCategory("CORE_MUSIC", newValues.size(), "core_music"));
}
if (!existingValues.contains("GAME_MUSIC")) {
newValues.add(createNewCategory("GAME_MUSIC", newValues.size(), "game_music"));
}
$VALUES = newValues.toArray(new SoundSource[0]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.noxcrew.noxesium.network.clientbound.ClientboundNoxesiumPacket;
import com.noxcrew.noxesium.network.clientbound.ClientboundResetPacket;
import com.noxcrew.noxesium.network.clientbound.ClientboundResetServerRulesPacket;
import com.noxcrew.noxesium.network.clientbound.ClientboundServerInformationPacket;
import com.noxcrew.noxesium.network.serverbound.ServerboundClientInformationPacket;
import com.noxcrew.noxesium.network.serverbound.ServerboundNoxesiumPacket;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
Expand Down Expand Up @@ -39,6 +40,7 @@ public class NoxesiumPackets {
public static final PacketType<ClientboundChangeServerRulesPacket> CLIENT_CHANGE_SERVER_RULES = client("change_server_rules", ClientboundChangeServerRulesPacket::new);
public static final PacketType<ClientboundResetServerRulesPacket> CLIENT_RESET_SERVER_RULES = client("reset_server_rules", ClientboundResetServerRulesPacket::new);
public static final PacketType<ClientboundResetPacket> CLIENT_RESET = client("reset", ClientboundResetPacket::new);
public static final PacketType<ClientboundServerInformationPacket> CLIENT_SERVER_INFO = client("server_info", ClientboundServerInformationPacket::new);

public static final PacketType<ServerboundClientInformationPacket> SERVER_CLIENT_INFO = server("client_info");
public static final PacketType<ServerboundClientInformationPacket> SERVER_CLIENT_SETTINGS = server("client_settings");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.noxcrew.noxesium.network.clientbound;

import com.noxcrew.noxesium.NoxesiumMod;
import com.noxcrew.noxesium.network.NoxesiumPackets;
import com.noxcrew.noxesium.network.serverbound.ServerboundNoxesiumPacket;
import net.fabricmc.fabric.api.networking.v1.PacketSender;
import net.fabricmc.fabric.api.networking.v1.PacketType;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.FriendlyByteBuf;

/**
* Sent to the client when the server is first informed of it existing, this contains information
* about what protocol version the server supports.
*/
public class ClientboundServerInformationPacket extends ClientboundNoxesiumPacket {

private final int maxProtocolVersion;

public ClientboundServerInformationPacket(FriendlyByteBuf buf) {
super(buf.readVarInt());
this.maxProtocolVersion = buf.readVarInt();
}

@Override
public void receive(LocalPlayer player, PacketSender responseSender) {
// Whenever the server sends information about the supported protocol version we store
// that and can use it to downgrade server-side packets based on the newest version
// that can be sent.
NoxesiumMod.setServerVersion(maxProtocolVersion);
}

@Override
public PacketType<?> getType() {
return NoxesiumPackets.CLIENT_SERVER_INFO;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.noxcrew.noxesium.network.serverbound;

import com.noxcrew.noxesium.NoxesiumMod;
import com.noxcrew.noxesium.network.NoxesiumPacket;
import com.noxcrew.noxesium.network.NoxesiumPackets;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
Expand All @@ -12,21 +13,20 @@
public abstract class ServerboundNoxesiumPacket extends NoxesiumPacket {

/**
* Creates a new serverbound Noxesium packet with the given version.
* Creates a new serverbound Noxesium packet with the given latest version.
*
* @param version The version of this packet, this is always
* the first varint of any Noxesium packet and
* allows the contents of packets to change
* over time without much issue.
* @param latestVersion The latest version of this packet, this is always
* the first varint of any Noxesium packet and
* allows the contents of packets to change
* over time without much issue.
*/
public ServerboundNoxesiumPacket(int version) {
super(version);
public ServerboundNoxesiumPacket(int latestVersion) {
super(latestVersion);
}

@Override
public final void write(FriendlyByteBuf buf) {
buf.writeVarInt(version);
serialize(buf);
throw new UnsupportedOperationException("Cannot directly write a ServerboundNoxesiumPacket, use send()");
}

/**
Expand All @@ -37,13 +37,23 @@ public final void write(FriendlyByteBuf buf) {
*/
public abstract void serialize(FriendlyByteBuf buffer);

/**
* Returns the maximum packet version this packet should be serialized
* as based on the given protocol version. This is the protocol version
* used by the server, e.g. if this is 3 and the packet being serialized
* was v1 until protocol 4 and v2 after then this should return 1.
*/
public int getVersion(int protocolVersion) {
return version;
}

/**
* Writes this packet into the given buffer as the selected legacy version.
*
* @param version The version to serialize this packet as, it is guaranteed to be
* below the version of the packet.
* @param buffer The buffer to serialize to, the intended version varint has already
* been written.
* @param buffer The buffer to serialize to, the intended version varint has already
* been written.
*/
public void legacySerialize(int version, FriendlyByteBuf buffer) {
throw new UnsupportedOperationException("Packet " + getClass().getSimpleName() + " does not support legacy serialization as version version");
Expand All @@ -56,12 +66,17 @@ public void legacySerialize(int version, FriendlyByteBuf buffer) {
public boolean send() {
// We assume the server indicates which packets it wishes to receive, otherwise we do not send anything.
if (ClientPlayNetworking.canSend(getType()) && NoxesiumPackets.canSend(getType())) {
// TODO Determine the latest protocol version the server has indicated it supports and
// possibly use legacy serialization!
var maxProtocol = NoxesiumMod.getMaxProtocolVersion();
var maxVersion = getVersion(maxProtocol);

var buffer = PacketByteBufs.create();
buffer.writeVarInt(version);
serialize(buffer);
if (maxVersion >= version) {
buffer.writeVarInt(version);
serialize(buffer);
} else {
buffer.writeInt(maxVersion);
legacySerialize(maxVersion, buffer);
}
ClientPlayNetworking.send(getType().getId(), buffer);
return true;
}
Expand Down

0 comments on commit 37a2570

Please sign in to comment.