From ca8be52f9e496ba7943bd74556775f445e930d56 Mon Sep 17 00:00:00 2001
From: noramibu <50046813+noramibu@users.noreply.github.com>
Date: Sat, 27 Jun 2026 21:08:48 +0300
Subject: [PATCH 1/2] Remove Fabric API dependency from Spoutcraft client
---
spoutcraft-fabric/build.gradle.kts | 3 -
spoutcraft-fabric/gradle.properties | 3 -
.../loadingoverlay/SpoutLogoIdentifier.java | 13 ++
.../ReplaceColorsAndSizesOverlayMixin.java | 2 +-
...egisteringTexturesLoadingOverlayMixin.java | 2 +-
.../ClientModCustomContentReceiving.java | 15 ++
.../clientmod/protocol/ClientModState.java | 11 +-
.../clientmod/protocol/SpoutProtocol.java | 203 +++++++++---------
.../ClientCommonPacketListenerImplMixin.java | 31 +++
...tConfigurationPacketListenerImplMixin.java | 27 +++
...lientHandshakePacketListenerImplMixin.java | 67 ++++++
.../mixin/ClientPacketListenerMixin.java | 18 ++
.../ClientboundCustomQueryPacketMixin.java | 27 +++
.../mixin/CustomPacketPayloadCodecMixin.java | 26 +++
.../main/SpoutcraftClientModInitializer.java | 13 --
....clientview.clientmod.protocol.mixins.json | 8 +-
.../spout/main/SpoutcraftModInitializer.java | 22 --
.../src/main/resources/fabric.mod.json | 11 +-
.../main/resources/spoutcraft.classtweaker | 6 +
19 files changed, 339 insertions(+), 169 deletions(-)
create mode 100644 spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientCommonPacketListenerImplMixin.java
create mode 100644 spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientConfigurationPacketListenerImplMixin.java
create mode 100644 spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientHandshakePacketListenerImplMixin.java
create mode 100644 spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientPacketListenerMixin.java
create mode 100644 spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientboundCustomQueryPacketMixin.java
create mode 100644 spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/CustomPacketPayloadCodecMixin.java
delete mode 100644 spoutcraft-fabric/src/client/java/spout/main/SpoutcraftClientModInitializer.java
delete mode 100644 spoutcraft-fabric/src/main/java/spout/main/SpoutcraftModInitializer.java
diff --git a/spoutcraft-fabric/build.gradle.kts b/spoutcraft-fabric/build.gradle.kts
index b365883e..48bece3e 100644
--- a/spoutcraft-fabric/build.gradle.kts
+++ b/spoutcraft-fabric/build.gradle.kts
@@ -46,9 +46,6 @@ dependencies {
implementation("net.fabricmc:fabric-loader:${providers.gradleProperty("loader_version").get()}")
- // Fabric API. This is technically optional, but you probably want it anyway.
- implementation("net.fabricmc.fabric-api:fabric-api:${providers.gradleProperty("fabric_api_version").get()}")
-
}
tasks.processResources {
diff --git a/spoutcraft-fabric/gradle.properties b/spoutcraft-fabric/gradle.properties
index a95e01cc..9f68b82a 100644
--- a/spoutcraft-fabric/gradle.properties
+++ b/spoutcraft-fabric/gradle.properties
@@ -15,6 +15,3 @@ loom_version=1.16-SNAPSHOT
mod_version=1.15-SNAPSHOT
maven_group=spout.client.fabric
archives_base_name=spoutcraft
-
-# Dependencies
-fabric_api_version=0.150.0+26.1.2
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/SpoutLogoIdentifier.java b/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/SpoutLogoIdentifier.java
index 3ca1365a..581990fb 100644
--- a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/SpoutLogoIdentifier.java
+++ b/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/SpoutLogoIdentifier.java
@@ -1,5 +1,8 @@
package spout.clientui.resourcepack.loadingoverlay;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
import net.minecraft.resources.Identifier;
import spout.branding.SpoutNamespace;
@@ -8,10 +11,20 @@
*/
public final class SpoutLogoIdentifier {
+ private static final String RESOURCE_PATH = "assets/spout/icon.png";
+
private SpoutLogoIdentifier() {
throw new UnsupportedOperationException();
}
public static final Identifier IDENTIFIER = Identifier.fromNamespaceAndPath(SpoutNamespace.SPOUT, "icon.png");
+ public static InputStream open() throws IOException {
+ InputStream input = SpoutLogoIdentifier.class.getClassLoader().getResourceAsStream(RESOURCE_PATH);
+ if (input == null) {
+ throw new FileNotFoundException(RESOURCE_PATH);
+ }
+ return input;
+ }
+
}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceColorsAndSizesOverlayMixin.java b/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceColorsAndSizesOverlayMixin.java
index db7c6527..8a1ff2ab 100644
--- a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceColorsAndSizesOverlayMixin.java
+++ b/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceColorsAndSizesOverlayMixin.java
@@ -70,7 +70,7 @@ public abstract class ReplaceColorsAndSizesOverlayMixin {
@Override
public TextureContents loadContents(ResourceManager resourceManager) throws IOException {
- try (InputStream input = resourceManager.open(SpoutLogoIdentifier.IDENTIFIER)) {
+ try (InputStream input = SpoutLogoIdentifier.open()) {
TextureContents result = new TextureContents(NativeImage.read(input),
new TextureMetadataSection(true, true, MipmapStrategy.MEAN, 0.0f));
return result;
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceLogoWhenRegisteringTexturesLoadingOverlayMixin.java b/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceLogoWhenRegisteringTexturesLoadingOverlayMixin.java
index a2aed265..7dd92a71 100644
--- a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceLogoWhenRegisteringTexturesLoadingOverlayMixin.java
+++ b/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceLogoWhenRegisteringTexturesLoadingOverlayMixin.java
@@ -25,7 +25,7 @@ public abstract class ReplaceLogoWhenRegisteringTexturesLoadingOverlayMixin {
@Override
public TextureContents loadContents(ResourceManager resourceManager) throws IOException {
- try (InputStream input = resourceManager.open(SpoutLogoIdentifier.IDENTIFIER)) {
+ try (InputStream input = SpoutLogoIdentifier.open()) {
TextureContents result = new TextureContents(NativeImage.read(input),
new TextureMetadataSection(true, true, MipmapStrategy.MEAN, 0.0f));
return result;
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/ClientModCustomContentReceiving.java b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/ClientModCustomContentReceiving.java
index d5e03f5d..aa71db16 100644
--- a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/ClientModCustomContentReceiving.java
+++ b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/ClientModCustomContentReceiving.java
@@ -72,6 +72,17 @@ public static void handlePacket(ClientModCustomContentPacketPayload payload) {
});
}).toList()
);
+ RemappedBlockStateRegistry blockStateRegistry =
+ (RemappedBlockStateRegistry) Block.BLOCK_STATE_REGISTRY;
+ for (var keyedValue : receivedContent.getBlocks()) {
+ Block block = BuiltInRegistries.BLOCK.get(keyedValue.identifier()).orElseThrow().value();
+ for (BlockState state : block.getStateDefinition().getPossibleStates()) {
+ state.initCache();
+ if (blockStateRegistry.getIdUnmapped(state) == -1) {
+ Block.BLOCK_STATE_REGISTRY.add(state);
+ }
+ }
+ }
// Set up registry id mappings where necessary
for (RegistryEntryIdList list : receivedContent.getRegistryEntryIdLists()) {
Registry registry = BuiltInRegistries.REGISTRY.getValue(list.registryIdentifier());
@@ -111,4 +122,8 @@ public static void handlePacket(ClientModCustomContentPacketPayload payload) {
}
}
+ static void clear() {
+ receivedContent = null;
+ }
+
}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/ClientModState.java b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/ClientModState.java
index fadfde31..ec459916 100644
--- a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/ClientModState.java
+++ b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/ClientModState.java
@@ -8,12 +8,7 @@
*
{@link #HANDSHAKE_STARTED} -> {@link #CLIENT_MOD_NOT_DETECTED} - When the configuration phase starts without having received a client mod detection packet
* {@link #CLIENT_MOD_DETECTED} -> {@link #RECEIVED_CUSTOM_CONTENT} - When the custom content packet has been received
* {@link #RECEIVED_CUSTOM_CONTENT} -> {@link #ADDED_CUSTOM_CONTENT} - When the custom content packet has been processed
- * {@link #IDLE} -> {@link #REMOVED_CUSTOM_CONTENT} - When the client is disconnecting and the custom content was never added
- * {@link #HANDSHAKE_STARTED} -> {@link #REMOVED_CUSTOM_CONTENT} - When the client is disconnecting and the custom content was never added
- * {@link #CLIENT_MOD_DETECTED} -> {@link #REMOVED_CUSTOM_CONTENT} - When the client is disconnecting and the custom content was never added
- * {@link #CLIENT_MOD_NOT_DETECTED} -> {@link #REMOVED_CUSTOM_CONTENT} - When the client is disconnecting and the client mod was never detected
- * {@link #ADDED_CUSTOM_CONTENT} -> {@link #REMOVED_CUSTOM_CONTENT} - When the client is disconnecting and the custom content has been removed
- * {@link #REMOVED_CUSTOM_CONTENT} -> {@link #IDLE} - When the client has disconnected
+ * Any state -> {@link #IDLE} - When the client disconnects or starts a new login
*
*/
public enum ClientModState {
@@ -41,8 +36,4 @@ public enum ClientModState {
* All custom content has been received and added (e.g. registered).
*/
ADDED_CUSTOM_CONTENT,
- /**
- * Received custom content has been removed, or we are disconnecting and it was never successfully added.
- */
- REMOVED_CUSTOM_CONTENT,
}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/SpoutProtocol.java b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/SpoutProtocol.java
index 3bc1a47a..394be709 100644
--- a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/SpoutProtocol.java
+++ b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/SpoutProtocol.java
@@ -1,14 +1,11 @@
package spout.clientview.clientmod.protocol;
import io.netty.buffer.Unpooled;
-import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationConnectionEvents;
-import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking;
-import net.fabricmc.fabric.api.client.networking.v1.ClientLoginConnectionEvents;
-import net.fabricmc.fabric.api.client.networking.v1.ClientLoginNetworking;
-import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
-import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
+import net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl;
import net.minecraft.client.multiplayer.ServerData;
import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.protocol.login.custom.CustomQueryAnswerPayload;
+import net.minecraft.network.protocol.login.custom.CustomQueryPayload;
import net.minecraft.resources.Identifier;
import spout.clientview.clientmod.protocol.mixin.ClientCommonPacketListenerImplAccessor;
import spout.gamecontent.datadriven.common.registry.temporarymodification.TemporaryRegistryModifiers;
@@ -16,8 +13,6 @@
import spout.clientview.clientmod.registryidmapping.RegistryIdMappings;
import spout.clientui.resourcepack.loadingoverlay.SwitchOverlayStyle;
import spout.branding.SpoutNamespace;
-import java.util.Set;
-import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -26,7 +21,7 @@
*/
public final class SpoutProtocol {
- private static final Identifier CLIENT_MOD_DETECTION_PACKET_ID = Identifier.fromNamespaceAndPath(SpoutNamespace.SPOUT, "detect_client_mod");
+ public static final Identifier CLIENT_MOD_DETECTION_PACKET_ID = Identifier.fromNamespaceAndPath(SpoutNamespace.SPOUT, "detect_client_mod");
private static final int MIN_PROTOCOL_VERSION = 5;
private static final int MAX_PROTOCOL_VERSION = 5;
@@ -36,92 +31,84 @@ private SpoutProtocol() {
throw new UnsupportedOperationException();
}
- public static void initialize() {
- ClientLoginNetworking.registerGlobalReceiver(CLIENT_MOD_DETECTION_PACKET_ID, (client, handler, buf, callbacksConsumer) -> {
- // First, the server will send a 0, if not, then there must be a protocol difference that we are unaware of
- int zero = buf.readVarInt();
- if (zero == 0) {
- // Read the nonce
- int nonce = buf.readVarInt();
- // Read the protocol versions supported by the server (and perform basic validation on what we read)
- int minServerProtocolVersion = buf.readVarInt();
- if (minServerProtocolVersion >= 1) {
- int maxServerProtocolVersion = buf.readVarInt();
- if (maxServerProtocolVersion >= minServerProtocolVersion) {
- // The best protocol version is the highest supported by both client and server
- int bestProtocolVersion = Math.min(maxServerProtocolVersion, MAX_PROTOCOL_VERSION);
- boolean isBestProtocolVersionAcceptable = bestProtocolVersion >= minServerProtocolVersion && bestProtocolVersion >= MIN_PROTOCOL_VERSION;
- int responseProtocolVersion = -1; // In case of failure, respond with an invalid version
- if (isBestProtocolVersionAcceptable) {
- changeState(ClientModState.HANDSHAKE_STARTED, ClientModState.CLIENT_MOD_DETECTED);
- SwitchOverlayStyle.setSpout();
- responseProtocolVersion = bestProtocolVersion;
- }
- // Respond
- FriendlyByteBuf response = new FriendlyByteBuf(Unpooled.buffer(15));
- response.writeVarInt(0);
- response.writeVarInt(nonce);
- response.writeVarInt(responseProtocolVersion);
- return CompletableFuture.completedFuture(response);
- }
- }
- }
- // We did not understand this protocol
- return CompletableFuture.completedFuture(null);
- });
- PayloadTypeRegistry.clientboundConfiguration().register(ClientModCustomContentPacketPayload.TYPE, ClientModCustomContentPacketPayload.STREAM_CODEC);
- ClientConfigurationNetworking.registerGlobalReceiver(ClientModCustomContentPacketPayload.TYPE, (payload, context) -> {
- ClientModCustomContentReceiving.handlePacket(payload);
- });
- ClientLoginConnectionEvents.INIT.register((handler, client) -> {
- SpoutProtocol.changeState(ClientModState.IDLE, ClientModState.HANDSHAKE_STARTED);
- });
- ClientConfigurationConnectionEvents.INIT.register((handler, client) -> {
- // Make sure the state is valid
- while (true) {
- if (SpoutProtocol.getState() == ClientModState.CLIENT_MOD_DETECTED) {
- // Force accepting of packs
- ClientCommonPacketListenerImplAccessor accessor = (ClientCommonPacketListenerImplAccessor) handler;
- ServerData serverData = accessor.getServerData();
- serverData.setResourcePackStatus(ServerData.ServerPackStatus.ENABLED);
-
- break;
- }
- if (SpoutProtocol.tryChangeState(ClientModState.HANDSHAKE_STARTED, ClientModState.CLIENT_MOD_NOT_DETECTED)) {
- break;
- }
- Thread.onSpinWait();
- }
- });
- ClientLoginConnectionEvents.DISCONNECT.register((handler, client) -> {
- onDisconnect();
- });
- ClientConfigurationConnectionEvents.DISCONNECT.register((handler, client) -> {
- onDisconnect();
- });
- ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> {
- onDisconnect();
- });
+ public static void onLoginStart() {
+ SpoutProtocol.onDisconnect();
+ state.set(ClientModState.HANDSHAKE_STARTED);
}
- private static void onDisconnect() {
+ public static ClientModDetectionQueryPayload readClientModDetectionQuery(FriendlyByteBuf input) {
+ ClientModDetectionQueryPayload payload = new ClientModDetectionQueryPayload(
+ input.readVarInt(),
+ input.readVarInt(),
+ input.readVarInt(),
+ input.readVarInt()
+ );
+ input.skipBytes(input.readableBytes());
+ return payload;
+ }
+
+ public static CustomQueryAnswerPayload createClientModDetectionAnswer(CustomQueryPayload payload) {
+ ClientModDetectionQueryPayload detectionPayload = getClientModDetectionQuery(payload);
+ // First, the server will send a 0. If not, then there must be a protocol difference that we are unaware of.
+ if (detectionPayload.protocolMarker != 0
+ || detectionPayload.minProtocolVersion < 1
+ || detectionPayload.maxProtocolVersion < detectionPayload.minProtocolVersion) {
+ return null;
+ }
+ // The best protocol version is the highest supported by both client and server.
+ int bestProtocolVersion = Math.min(
+ detectionPayload.maxProtocolVersion,
+ MAX_PROTOCOL_VERSION
+ );
+ int responseProtocolVersion = -1; // In case of failure, respond with an invalid version.
+ if (bestProtocolVersion >= detectionPayload.minProtocolVersion
+ && bestProtocolVersion >= MIN_PROTOCOL_VERSION) {
+ changeState(ClientModState.HANDSHAKE_STARTED, ClientModState.CLIENT_MOD_DETECTED);
+ SwitchOverlayStyle.setSpout();
+ responseProtocolVersion = bestProtocolVersion;
+ }
+ int selectedProtocolVersion = responseProtocolVersion;
+ return output -> {
+ output.writeVarInt(0);
+ output.writeVarInt(detectionPayload.nonce);
+ output.writeVarInt(selectedProtocolVersion);
+ };
+ }
+
+ private static ClientModDetectionQueryPayload getClientModDetectionQuery(CustomQueryPayload payload) {
+ if (payload instanceof ClientModDetectionQueryPayload detectionPayload) {
+ return detectionPayload;
+ }
+ // Fixes Spout login when Fabric API is present; fabric-networking-api-v1 wraps login payloads in a generic buffer payload.
+ FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer());
+ try {
+ payload.write(buffer);
+ return readClientModDetectionQuery(buffer);
+ } finally {
+ buffer.release();
+ }
+ }
+
+ public static void onConfigurationStart(ClientCommonPacketListenerImpl handler) {
+ if (SpoutProtocol.getState() == ClientModState.CLIENT_MOD_DETECTED) {
+ // Force accepting of packs.
+ ClientCommonPacketListenerImplAccessor accessor = (ClientCommonPacketListenerImplAccessor) handler;
+ ServerData serverData = accessor.getServerData();
+ serverData.setResourcePackStatus(ServerData.ServerPackStatus.ENABLED);
+ return;
+ }
+ SpoutProtocol.tryChangeState(ClientModState.HANDSHAKE_STARTED, ClientModState.CLIENT_MOD_NOT_DETECTED);
+ }
+
+ public static void onDisconnect() {
SwitchOverlayStyle.setMojang();
- // Clear custom content, if present
- while (true) {
- if (SpoutProtocol.getState() == ClientModState.ADDED_CUSTOM_CONTENT) {
- TemporaryRegistryModifiers.removeCustomContent();
- RegistryIdMappings.clear();
- BlockStateRegistryIdMappings.clear();
- SpoutProtocol.changeState(ClientModState.ADDED_CUSTOM_CONTENT, ClientModState.REMOVED_CUSTOM_CONTENT);
- break;
- }
- if (SpoutProtocol.tryChangeState(Set.of(ClientModState.IDLE, ClientModState.HANDSHAKE_STARTED, ClientModState.CLIENT_MOD_DETECTED, ClientModState.CLIENT_MOD_NOT_DETECTED), ClientModState.REMOVED_CUSTOM_CONTENT)) {
- break;
- }
- Thread.onSpinWait();
+ ClientModState oldState = state.getAndSet(ClientModState.IDLE);
+ ClientModCustomContentReceiving.clear();
+ if (oldState == ClientModState.ADDED_CUSTOM_CONTENT) {
+ TemporaryRegistryModifiers.removeCustomContent();
+ RegistryIdMappings.clear();
+ BlockStateRegistryIdMappings.clear();
}
- // Reset to idle
- SpoutProtocol.changeState(ClientModState.REMOVED_CUSTOM_CONTENT, ClientModState.IDLE);
}
public static boolean tryChangeState(ClientModState oldState, ClientModState newState) {
@@ -134,24 +121,30 @@ public static void changeState(ClientModState oldState, ClientModState newState)
}
}
- public static boolean tryChangeState(Set oldStates, ClientModState newState) {
- ClientModState currentState = state.get();
- if (oldStates.contains(currentState)) {
- if (state.compareAndSet(currentState, newState)) {
- return true;
- }
- }
- return false;
+ public static ClientModState getState() {
+ return state.get();
}
- public static void changeState(Set oldStates, ClientModState newState) {
- while (!tryChangeState(oldStates, newState)) {
- Thread.onSpinWait();
+ public record ClientModDetectionQueryPayload(
+ int protocolMarker,
+ int nonce,
+ int minProtocolVersion,
+ int maxProtocolVersion
+ ) implements CustomQueryPayload {
+
+ @Override
+ public Identifier id() {
+ return CLIENT_MOD_DETECTION_PACKET_ID;
+ }
+
+ @Override
+ public void write(FriendlyByteBuf output) {
+ output.writeVarInt(this.protocolMarker);
+ output.writeVarInt(this.nonce);
+ output.writeVarInt(this.minProtocolVersion);
+ output.writeVarInt(this.maxProtocolVersion);
}
- }
- public static ClientModState getState() {
- return state.get();
}
}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientCommonPacketListenerImplMixin.java b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientCommonPacketListenerImplMixin.java
new file mode 100644
index 00000000..8cfd2917
--- /dev/null
+++ b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientCommonPacketListenerImplMixin.java
@@ -0,0 +1,31 @@
+package spout.clientview.clientmod.protocol.mixin;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl;
+import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
+import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import spout.clientview.clientmod.protocol.ClientModCustomContentPacketPayload;
+import spout.clientview.clientmod.protocol.ClientModCustomContentReceiving;
+
+@Mixin(ClientCommonPacketListenerImpl.class)
+public abstract class ClientCommonPacketListenerImplMixin {
+
+ @Inject(method = "handleCustomPayload", at = @At("HEAD"), cancellable = true)
+ private void handleSpoutCustomPayload(ClientboundCustomPayloadPacket packet, CallbackInfo ci) {
+ CustomPacketPayload payload = packet.payload();
+ if (payload instanceof ClientModCustomContentPacketPayload spoutPayload) {
+ Minecraft client = Minecraft.getInstance();
+ if (client.isSameThread()) {
+ ClientModCustomContentReceiving.handlePacket(spoutPayload);
+ } else {
+ client.submit(() -> ClientModCustomContentReceiving.handlePacket(spoutPayload)).join();
+ }
+ ci.cancel();
+ }
+ }
+
+}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientConfigurationPacketListenerImplMixin.java b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientConfigurationPacketListenerImplMixin.java
new file mode 100644
index 00000000..3d4d1f72
--- /dev/null
+++ b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientConfigurationPacketListenerImplMixin.java
@@ -0,0 +1,27 @@
+package spout.clientview.clientmod.protocol.mixin;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.multiplayer.ClientCommonPacketListenerImpl;
+import net.minecraft.client.multiplayer.ClientConfigurationPacketListenerImpl;
+import net.minecraft.client.multiplayer.CommonListenerCookie;
+import net.minecraft.network.Connection;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import spout.clientview.clientmod.protocol.SpoutProtocol;
+
+@Mixin(ClientConfigurationPacketListenerImpl.class)
+public abstract class ClientConfigurationPacketListenerImplMixin {
+
+ @Inject(method = "", at = @At("TAIL"))
+ private void markConfigurationStart(
+ Minecraft minecraft,
+ Connection connection,
+ CommonListenerCookie cookie,
+ CallbackInfo ci
+ ) {
+ SpoutProtocol.onConfigurationStart((ClientCommonPacketListenerImpl) (Object) this);
+ }
+
+}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientHandshakePacketListenerImplMixin.java b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientHandshakePacketListenerImplMixin.java
new file mode 100644
index 00000000..e645b0ac
--- /dev/null
+++ b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientHandshakePacketListenerImplMixin.java
@@ -0,0 +1,67 @@
+package spout.clientview.clientmod.protocol.mixin;
+
+import java.time.Duration;
+import java.util.function.Consumer;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.screens.Screen;
+import net.minecraft.client.multiplayer.ClientHandshakePacketListenerImpl;
+import net.minecraft.client.multiplayer.LevelLoadTracker;
+import net.minecraft.client.multiplayer.ServerData;
+import net.minecraft.client.multiplayer.TransferState;
+import net.minecraft.network.Connection;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.protocol.login.ClientboundCustomQueryPacket;
+import net.minecraft.network.protocol.login.ServerboundCustomQueryAnswerPacket;
+import net.minecraft.network.protocol.login.custom.CustomQueryPayload;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import spout.clientview.clientmod.protocol.SpoutProtocol;
+
+@Mixin(ClientHandshakePacketListenerImpl.class)
+public abstract class ClientHandshakePacketListenerImplMixin {
+
+ @Shadow
+ @Final
+ private Connection connection;
+
+ @Shadow
+ @Final
+ private Consumer updateStatus;
+
+ @Inject(method = "", at = @At("TAIL"))
+ private void markLoginStart(
+ Connection connection,
+ Minecraft minecraft,
+ ServerData serverData,
+ Screen parent,
+ boolean newWorld,
+ Duration worldLoadDuration,
+ Consumer updateStatus,
+ LevelLoadTracker levelLoadTracker,
+ TransferState transferState,
+ CallbackInfo ci
+ ) {
+ SpoutProtocol.onLoginStart();
+ }
+
+ @Inject(method = "handleCustomQuery", at = @At("HEAD"), cancellable = true)
+ private void handleSpoutCustomQuery(ClientboundCustomQueryPacket packet, CallbackInfo ci) {
+ CustomQueryPayload payload = packet.payload();
+ if (!SpoutProtocol.CLIENT_MOD_DETECTION_PACKET_ID.equals(payload.id())) {
+ return;
+ }
+ this.updateStatus.accept(Component.translatable("connect.negotiating"));
+ this.connection.send(
+ new ServerboundCustomQueryAnswerPacket(
+ packet.transactionId(),
+ SpoutProtocol.createClientModDetectionAnswer(payload)
+ )
+ );
+ ci.cancel();
+ }
+
+}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientPacketListenerMixin.java b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientPacketListenerMixin.java
new file mode 100644
index 00000000..8c387993
--- /dev/null
+++ b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientPacketListenerMixin.java
@@ -0,0 +1,18 @@
+package spout.clientview.clientmod.protocol.mixin;
+
+import net.minecraft.client.multiplayer.ClientPacketListener;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import spout.clientview.clientmod.protocol.SpoutProtocol;
+
+@Mixin(ClientPacketListener.class)
+public abstract class ClientPacketListenerMixin {
+
+ @Inject(method = "clearLevel", at = @At("HEAD"))
+ private void removeSpoutContentBeforeClearingLevel(CallbackInfo ci) {
+ SpoutProtocol.onDisconnect();
+ }
+
+}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientboundCustomQueryPacketMixin.java b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientboundCustomQueryPacketMixin.java
new file mode 100644
index 00000000..8f2019ff
--- /dev/null
+++ b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientboundCustomQueryPacketMixin.java
@@ -0,0 +1,27 @@
+package spout.clientview.clientmod.protocol.mixin;
+
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.protocol.login.ClientboundCustomQueryPacket;
+import net.minecraft.network.protocol.login.custom.CustomQueryPayload;
+import net.minecraft.resources.Identifier;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import spout.clientview.clientmod.protocol.SpoutProtocol;
+
+@Mixin(ClientboundCustomQueryPacket.class)
+public abstract class ClientboundCustomQueryPacketMixin {
+
+ @Inject(method = "readPayload", at = @At("HEAD"), cancellable = true)
+ private static void readSpoutPayload(
+ Identifier identifier,
+ FriendlyByteBuf input,
+ CallbackInfoReturnable cir
+ ) {
+ if (SpoutProtocol.CLIENT_MOD_DETECTION_PACKET_ID.equals(identifier)) {
+ cir.setReturnValue(SpoutProtocol.readClientModDetectionQuery(input));
+ }
+ }
+
+}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/CustomPacketPayloadCodecMixin.java b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/CustomPacketPayloadCodecMixin.java
new file mode 100644
index 00000000..cc0b74e4
--- /dev/null
+++ b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/CustomPacketPayloadCodecMixin.java
@@ -0,0 +1,26 @@
+package spout.clientview.clientmod.protocol.mixin;
+
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.codec.StreamCodec;
+import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
+import net.minecraft.resources.Identifier;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+import spout.clientview.clientmod.protocol.ClientModCustomContentPacketPayload;
+
+@Mixin(targets = "net.minecraft.network.protocol.common.custom.CustomPacketPayload$1")
+public abstract class CustomPacketPayloadCodecMixin {
+
+ @Inject(method = "findCodec", at = @At("HEAD"), cancellable = true)
+ private void findSpoutCodec(
+ Identifier identifier,
+ CallbackInfoReturnable> cir
+ ) {
+ if (ClientModCustomContentPacketPayload.TYPE.id().equals(identifier)) {
+ cir.setReturnValue((StreamCodec super B, ? extends CustomPacketPayload>) ClientModCustomContentPacketPayload.STREAM_CODEC);
+ }
+ }
+
+}
diff --git a/spoutcraft-fabric/src/client/java/spout/main/SpoutcraftClientModInitializer.java b/spoutcraft-fabric/src/client/java/spout/main/SpoutcraftClientModInitializer.java
deleted file mode 100644
index ebc7c30e..00000000
--- a/spoutcraft-fabric/src/client/java/spout/main/SpoutcraftClientModInitializer.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package spout.main;
-
-import net.fabricmc.api.ClientModInitializer;
-import spout.clientview.clientmod.protocol.SpoutProtocol;
-
-public class SpoutcraftClientModInitializer implements ClientModInitializer {
-
- @Override
- public void onInitializeClient() {
- SpoutProtocol.initialize();
- }
-
-}
diff --git a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.clientview.clientmod.protocol.mixins.json b/spoutcraft-fabric/src/client/resources/spoutcraft.spout.clientview.clientmod.protocol.mixins.json
index 937860b6..8ae74370 100644
--- a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.clientview.clientmod.protocol.mixins.json
+++ b/spoutcraft-fabric/src/client/resources/spoutcraft.spout.clientview.clientmod.protocol.mixins.json
@@ -4,7 +4,13 @@
"compatibilityLevel": "JAVA_25",
"client": [
"AllowSpoutServerPacksMixin",
- "ClientCommonPacketListenerImplAccessor"
+ "ClientCommonPacketListenerImplAccessor",
+ "ClientCommonPacketListenerImplMixin",
+ "ClientConfigurationPacketListenerImplMixin",
+ "ClientHandshakePacketListenerImplMixin",
+ "ClientPacketListenerMixin",
+ "ClientboundCustomQueryPacketMixin",
+ "CustomPacketPayloadCodecMixin"
],
"injectors": {
"defaultRequire": 1
diff --git a/spoutcraft-fabric/src/main/java/spout/main/SpoutcraftModInitializer.java b/spoutcraft-fabric/src/main/java/spout/main/SpoutcraftModInitializer.java
deleted file mode 100644
index c309d5d4..00000000
--- a/spoutcraft-fabric/src/main/java/spout/main/SpoutcraftModInitializer.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package spout.main;
-
-import net.fabricmc.api.ModInitializer;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class SpoutcraftModInitializer implements ModInitializer {
-
- public static final String MOD_ID = "spoutcraft";
- public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
-
- @Override
- public void onInitialize() {
- try {
- Class.forName("spout.main.SpoutcraftClientModInitializer");
- } catch (ClassNotFoundException ignored) {
- LOGGER.warn("Spoutcraft client mod was loaded on a server - will have no effect");
- }
- }
-
-}
diff --git a/spoutcraft-fabric/src/main/resources/fabric.mod.json b/spoutcraft-fabric/src/main/resources/fabric.mod.json
index 81b8b81b..c92ca968 100644
--- a/spoutcraft-fabric/src/main/resources/fabric.mod.json
+++ b/spoutcraft-fabric/src/main/resources/fabric.mod.json
@@ -14,14 +14,6 @@
"license": "See the included LICENSE.txt",
"icon": "assets/spout/icon.png",
"environment": "*",
- "entrypoints": {
- "main": [
- "spout.main.SpoutcraftModInitializer"
- ],
- "client": [
- "spout.main.SpoutcraftClientModInitializer"
- ]
- },
"accessWidener": "spoutcraft.classtweaker",
"mixins": [
{
@@ -76,7 +68,6 @@
"depends": {
"fabricloader": ">=0.19.2",
"minecraft": "~26.1.2",
- "java": ">=25",
- "fabric-api": "*"
+ "java": ">=25"
}
}
diff --git a/spoutcraft-fabric/src/main/resources/spoutcraft.classtweaker b/spoutcraft-fabric/src/main/resources/spoutcraft.classtweaker
index b6f7186a..0ff51edc 100644
--- a/spoutcraft-fabric/src/main/resources/spoutcraft.classtweaker
+++ b/spoutcraft-fabric/src/main/resources/spoutcraft.classtweaker
@@ -40,5 +40,11 @@ accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties
accessible field net/minecraft/world/level/block/state/BlockBehaviour$Properties speedFactor F
accessible method net/minecraft/core/registries/BuiltInRegistries internalRegister (Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/core/WritableRegistry;Lnet/minecraft/core/registries/BuiltInRegistries$RegistryBootstrap;)Lnet/minecraft/core/WritableRegistry;
accessible method net/minecraft/core/registries/BuiltInRegistries registerSimple (Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/core/registries/BuiltInRegistries$RegistryBootstrap;)Lnet/minecraft/core/Registry;
+accessible method net/minecraft/world/level/block/Blocks always (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z
+accessible method net/minecraft/world/level/block/Blocks always (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/EntityType;)Ljava/lang/Boolean;
+accessible method net/minecraft/world/level/block/Blocks never (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z
+accessible method net/minecraft/world/level/block/Blocks never (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/EntityType;)Ljava/lang/Boolean;
+accessible method net/minecraft/world/level/block/Blocks ocelotOrParrot (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/EntityType;)Ljava/lang/Boolean;
+accessible method net/minecraft/world/level/block/StairBlock (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockBehaviour$Properties;)V
accessible method net/minecraft/world/level/block/state/BlockBehaviour propertiesCodec ()Lcom/mojang/serialization/codecs/RecordCodecBuilder;
transitive-extendable method net/minecraft/core/IdMapper byId (I)Ljava/lang/Object;
From 6d7793c3908b83a19858f1681010789ff1ac5faa Mon Sep 17 00:00:00 2001
From: noramibu <50046813+noramibu@users.noreply.github.com>
Date: Sat, 27 Jun 2026 23:10:51 +0300
Subject: [PATCH 2/2] Refactor Spoutcraft client for multiloader support
---
settings.gradle.kts | 2 +-
...egisteringTexturesLoadingOverlayMixin.java | 39 ---------
...ojangLogoAfterTexturesRegisteredMixin.java | 25 ------
.../mixin/ClientPacketListenerMixin.java | 18 -----
.../block/RemappedBlockStateRegistry.java | 30 -------
.../MapBlockStateRegistryIdsBlockMixin.java | 28 -------
.../.editorconfig | 0
.../.gitignore | 0
spoutcraft-mod/build.gradle.kts | 8 ++
.../loadingoverlay/SpoutLogoIdentifier.java | 0
.../loadingoverlay/SwitchOverlayStyle.java | 0
...sitionsOfSpoutLogoLoadingOverlayMixin.java | 2 +-
.../LoadingOverlayLogoLocationAccessor.java | 0
.../ReplaceColorsAndSizesOverlayMixin.java | 3 +-
.../loadingoverlay/mixin/package-info.java | 0
.../loadingoverlay/package-info.java | 0
.../clientui/resourcepack/package-info.java | 0
...noreResourcePackDownloadProgressMixin.java | 0
.../toast/mixin/package-info.java | 0
.../resourcepack/toast/package-info.java | 0
.../clientmod/command/SpoutcraftCommand.java | 77 ++++++++++++++++++
.../ClientModCustomContentReceiving.java | 55 ++++++++++---
.../clientmod/protocol/ClientModState.java | 0
.../clientmod/protocol/SpoutProtocol.java | 32 ++++++--
.../mixin/AllowSpoutServerPacksMixin.java | 0
...lientCommonPacketListenerImplAccessor.java | 0
.../ClientCommonPacketListenerImplMixin.java | 0
...tConfigurationPacketListenerImplMixin.java | 0
...lientHandshakePacketListenerImplMixin.java | 0
.../mixin/ClientPacketListenerMixin.java | 38 +++++++++
.../ClientboundCustomQueryPacketMixin.java | 0
.../mixin/CustomPacketPayloadCodecMixin.java | 2 +-
.../protocol/mixin/package-info.java | 0
.../registryidmapping/RegistryIdMappings.java | 0
.../mixin/MapIdsByteBufCodecsMixin.java | 0
.../block/BlockStateRegistryIdMappings.java | 0
.../block/TemporaryBlockRegistryModifier.java | 0
.../mixin/BlockCodecAccessorBlockMixin.java | 0
...MapBlockStateRegistryIdsIdMapperMixin.java | 22 +++++
...aceBlockBehaviourPropertiesCodecMixin.java | 0
...rmattedBlockStateCodecStairBlockMixin.java | 0
...eCodecWeatheringCopperStairBlockMixin.java | 0
...icalOffsetAccessorBlockBehaviourMixin.java | 0
...kEntityTypeDataDrivenValidBlocksMixin.java | 0
...tBlockTypeRegistryMappedRegistryMixin.java | 0
.../CacheByNameCodecMappedRegistryMixin.java | 0
.../TemporaryRegistryModifier.java | 14 +++-
.../TemporaryRegistryModifiers.java | 0
.../mixin/HolderSetNamedAccessor.java | 0
.../mixin/MappedRegistryAccessor.java | 0
.../item/TemporaryItemRegistryModifier.java | 5 +-
.../DataComponentInitializersAccessor.java | 0
...alizationDecoratorItemPropertiesMixin.java | 0
.../ItemTypeDecoratorBlockItemMixin.java | 0
...TypeDecoratorDoubleHighBlockItemMixin.java | 0
.../mixin/ItemTypeDecoratorEggItemMixin.java | 0
.../mixin/ItemTypeDecoratorItemMixin.java | 0
...eSpoutBootstrapBuiltInRegistriesMixin.java | 0
...ui.resourcepack.loadingoverlay.mixins.json | 4 +-
...ut.clientui.resourcepack.toast.mixins.json | 0
....clientview.clientmod.protocol.mixins.json | 0
...ew.clientmod.registryidmapping.mixins.json | 0
...t.gamecontent.datadriven.block.mixins.json | 2 +-
...tent.datadriven.block.subtypes.mixins.json | 0
...content.datadriven.blockentity.mixins.json | 0
...mecontent.datadriven.blocktype.mixins.json | 0
...tadriven.common.registry.codec.mixins.json | 0
...registry.temporarymodification.mixins.json | 0
...ut.gamecontent.datadriven.item.mixins.json | 0
...t.spout.gamecontent.datadriven.mixins.json | 0
.../fabric}/build.gradle.kts | 18 +++--
.../src/main/resources/fabric.mod.json | 0
.../main/resources/spoutcraft.classtweaker | 1 -
.../gradle.properties | 6 +-
spoutcraft-mod/neoforge/build.gradle.kts | 80 +++++++++++++++++++
.../spout/neoforge/SpoutcraftNeoForgeMod.java | 25 ++++++
.../resources/META-INF/accesstransformer.cfg | 47 +++++++++++
.../resources/META-INF/neoforge.mods.toml | 62 ++++++++++++++
.../settings.gradle.kts | 8 ++
79 files changed, 471 insertions(+), 182 deletions(-)
delete mode 100644 spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceLogoWhenRegisteringTexturesLoadingOverlayMixin.java
delete mode 100644 spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceMojangLogoAfterTexturesRegisteredMixin.java
delete mode 100644 spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientPacketListenerMixin.java
delete mode 100644 spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/RemappedBlockStateRegistry.java
delete mode 100644 spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/mixin/MapBlockStateRegistryIdsBlockMixin.java
rename {spoutcraft-fabric => spoutcraft-mod}/.editorconfig (100%)
rename {spoutcraft-fabric => spoutcraft-mod}/.gitignore (100%)
create mode 100644 spoutcraft-mod/build.gradle.kts
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientui/resourcepack/loadingoverlay/SpoutLogoIdentifier.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientui/resourcepack/loadingoverlay/SwitchOverlayStyle.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ChangePositionsOfSpoutLogoLoadingOverlayMixin.java (97%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/LoadingOverlayLogoLocationAccessor.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceColorsAndSizesOverlayMixin.java (95%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/package-info.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientui/resourcepack/loadingoverlay/package-info.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientui/resourcepack/package-info.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientui/resourcepack/toast/mixin/IgnoreResourcePackDownloadProgressMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientui/resourcepack/toast/mixin/package-info.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientui/resourcepack/toast/package-info.java (100%)
create mode 100644 spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/command/SpoutcraftCommand.java
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientview/clientmod/protocol/ClientModCustomContentReceiving.java (78%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientview/clientmod/protocol/ClientModState.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientview/clientmod/protocol/SpoutProtocol.java (84%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientview/clientmod/protocol/mixin/AllowSpoutServerPacksMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientCommonPacketListenerImplAccessor.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientCommonPacketListenerImplMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientConfigurationPacketListenerImplMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientHandshakePacketListenerImplMixin.java (100%)
create mode 100644 spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientPacketListenerMixin.java
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientboundCustomQueryPacketMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientview/clientmod/protocol/mixin/CustomPacketPayloadCodecMixin.java (88%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientview/clientmod/protocol/mixin/package-info.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientview/clientmod/registryidmapping/RegistryIdMappings.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/clientview/clientmod/registryidmapping/mixin/MapIdsByteBufCodecsMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/block/BlockStateRegistryIdMappings.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/block/TemporaryBlockRegistryModifier.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/block/mixin/BlockCodecAccessorBlockMixin.java (100%)
create mode 100644 spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/mixin/MapBlockStateRegistryIdsIdMapperMixin.java
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/block/mixin/ReplaceBlockBehaviourPropertiesCodecMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/block/mixin/UseFormattedBlockStateCodecStairBlockMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/block/mixin/UseFormattedBlockStateCodecWeatheringCopperStairBlockMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/block/subtypes/mixin/BlockBehaviourMaxVerticalOffsetAccessorBlockBehaviourMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/blockentity/mixin/BlockEntityTypeDataDrivenValidBlocksMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/blocktype/mixin/MirrorMinecraftBlockTypeRegistryMappedRegistryMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/common/registry/codec/mixin/CacheByNameCodecMappedRegistryMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/TemporaryRegistryModifier.java (92%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/TemporaryRegistryModifiers.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/mixin/HolderSetNamedAccessor.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/mixin/MappedRegistryAccessor.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/item/TemporaryItemRegistryModifier.java (93%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/item/mixin/DataComponentInitializersAccessor.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemPropertiesSerializationDecoratorItemPropertiesMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorBlockItemMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorDoubleHighBlockItemMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorEggItemMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorItemMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/java/spout/gamecontent/datadriven/mixin/IncludeSpoutBootstrapBuiltInRegistriesMixin.java (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/resources/spoutcraft.spout.clientui.resourcepack.loadingoverlay.mixins.json (64%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/resources/spoutcraft.spout.clientui.resourcepack.toast.mixins.json (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/resources/spoutcraft.spout.clientview.clientmod.protocol.mixins.json (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/resources/spoutcraft.spout.clientview.clientmod.registryidmapping.mixins.json (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/resources/spoutcraft.spout.gamecontent.datadriven.block.mixins.json (89%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/resources/spoutcraft.spout.gamecontent.datadriven.block.subtypes.mixins.json (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/resources/spoutcraft.spout.gamecontent.datadriven.blockentity.mixins.json (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/resources/spoutcraft.spout.gamecontent.datadriven.blocktype.mixins.json (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/resources/spoutcraft.spout.gamecontent.datadriven.common.registry.codec.mixins.json (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/resources/spoutcraft.spout.gamecontent.datadriven.common.registry.temporarymodification.mixins.json (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/resources/spoutcraft.spout.gamecontent.datadriven.item.mixins.json (100%)
rename {spoutcraft-fabric => spoutcraft-mod/common}/src/client/resources/spoutcraft.spout.gamecontent.datadriven.mixins.json (100%)
rename {spoutcraft-fabric => spoutcraft-mod/fabric}/build.gradle.kts (81%)
rename {spoutcraft-fabric => spoutcraft-mod/fabric}/src/main/resources/fabric.mod.json (100%)
rename {spoutcraft-fabric => spoutcraft-mod/fabric}/src/main/resources/spoutcraft.classtweaker (98%)
rename {spoutcraft-fabric => spoutcraft-mod}/gradle.properties (82%)
create mode 100644 spoutcraft-mod/neoforge/build.gradle.kts
create mode 100644 spoutcraft-mod/neoforge/src/main/java/spout/neoforge/SpoutcraftNeoForgeMod.java
create mode 100644 spoutcraft-mod/neoforge/src/main/resources/META-INF/accesstransformer.cfg
create mode 100644 spoutcraft-mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml
rename {spoutcraft-fabric => spoutcraft-mod}/settings.gradle.kts (58%)
diff --git a/settings.gradle.kts b/settings.gradle.kts
index ddf1be50..24f697d8 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -2,4 +2,4 @@ rootProject.name = "spout-monorepo"
includeBuild("spout-fabric")
includeBuild("spout-paper")
-includeBuild("spoutcraft-fabric")
+includeBuild("spoutcraft-mod")
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceLogoWhenRegisteringTexturesLoadingOverlayMixin.java b/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceLogoWhenRegisteringTexturesLoadingOverlayMixin.java
deleted file mode 100644
index 7dd92a71..00000000
--- a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceLogoWhenRegisteringTexturesLoadingOverlayMixin.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package spout.clientui.resourcepack.loadingoverlay.mixin;
-
-import com.mojang.blaze3d.platform.NativeImage;
-import net.minecraft.client.gui.screens.LoadingOverlay;
-import net.minecraft.client.renderer.texture.MipmapStrategy;
-import net.minecraft.client.renderer.texture.ReloadableTexture;
-import net.minecraft.client.renderer.texture.TextureContents;
-import net.minecraft.client.renderer.texture.TextureManager;
-import net.minecraft.client.resources.metadata.texture.TextureMetadataSection;
-import net.minecraft.server.packs.resources.ResourceManager;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-import spout.clientui.resourcepack.loadingoverlay.SpoutLogoIdentifier;
-import java.io.IOException;
-import java.io.InputStream;
-
-@Mixin(LoadingOverlay.class)
-public abstract class ReplaceLogoWhenRegisteringTexturesLoadingOverlayMixin {
-
- @Inject(method = "registerTextures", at = @At("HEAD"), cancellable = true)
- private static void spout$replaceLogo(TextureManager textureManager, CallbackInfo ci) {
- textureManager.registerAndLoad(SpoutLogoIdentifier.IDENTIFIER, new ReloadableTexture(SpoutLogoIdentifier.IDENTIFIER) {
-
- @Override
- public TextureContents loadContents(ResourceManager resourceManager) throws IOException {
- try (InputStream input = SpoutLogoIdentifier.open()) {
- TextureContents result = new TextureContents(NativeImage.read(input),
- new TextureMetadataSection(true, true, MipmapStrategy.MEAN, 0.0f));
- return result;
- }
- }
-
- });
- ci.cancel(); // Prevent vanilla logo instance from being created
- }
-
-}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceMojangLogoAfterTexturesRegisteredMixin.java b/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceMojangLogoAfterTexturesRegisteredMixin.java
deleted file mode 100644
index c9911764..00000000
--- a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceMojangLogoAfterTexturesRegisteredMixin.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package spout.clientui.resourcepack.loadingoverlay.mixin;
-
-import net.minecraft.client.gui.screens.LoadingOverlay;
-import net.minecraft.client.renderer.texture.ReloadableTexture;
-import net.minecraft.client.renderer.texture.TextureManager;
-import net.minecraft.resources.Identifier;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-
-@Mixin(TextureManager.class)
-public abstract class ReplaceMojangLogoAfterTexturesRegisteredMixin {
-
- @Inject(
- method = "registerAndLoad(Lnet/minecraft/resources/Identifier;Lnet/minecraft/client/renderer/texture/ReloadableTexture;)V",
- at = @At("RETURN")
- )
- private void afterTextureRegistered(Identifier id, ReloadableTexture texture, CallbackInfo ci) {
- if (id.getNamespace().equals(Identifier.DEFAULT_NAMESPACE) && id.getPath().equals("textures/environment/end_sky.png") && LoadingOverlay.MOJANG_STUDIOS_LOGO_LOCATION.getNamespace().equals(Identifier.DEFAULT_NAMESPACE)) {
- // SwitchOverlayLogo.setSpout();
- }
- }
-
-}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientPacketListenerMixin.java b/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientPacketListenerMixin.java
deleted file mode 100644
index 8c387993..00000000
--- a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientPacketListenerMixin.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package spout.clientview.clientmod.protocol.mixin;
-
-import net.minecraft.client.multiplayer.ClientPacketListener;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-import spout.clientview.clientmod.protocol.SpoutProtocol;
-
-@Mixin(ClientPacketListener.class)
-public abstract class ClientPacketListenerMixin {
-
- @Inject(method = "clearLevel", at = @At("HEAD"))
- private void removeSpoutContentBeforeClearingLevel(CallbackInfo ci) {
- SpoutProtocol.onDisconnect();
- }
-
-}
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/RemappedBlockStateRegistry.java b/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/RemappedBlockStateRegistry.java
deleted file mode 100644
index e9fcba0a..00000000
--- a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/RemappedBlockStateRegistry.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package spout.gamecontent.datadriven.block;
-
-import net.minecraft.core.IdMapper;
-import net.minecraft.world.level.block.Block;
-import net.minecraft.world.level.block.state.BlockState;
-import org.jspecify.annotations.Nullable;
-
-/**
- * The implementation for {@link Block#BLOCK_STATE_REGISTRY}.
- */
-public final class RemappedBlockStateRegistry extends IdMapper {
-
- @Override
- public int getId(BlockState thing) {
- return BlockStateRegistryIdMappings.applyClientToServer(super.getId(thing));
- }
-
- public int getIdUnmapped(BlockState thing) {
- return super.getId(thing);
- }
-
- public @Nullable BlockState byId(int id) {
- return super.byId(BlockStateRegistryIdMappings.applyServerToClient(id));
- }
-
- public @Nullable BlockState byIdUnmapped(int id) {
- return super.byId(id);
- }
-
-}
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/mixin/MapBlockStateRegistryIdsBlockMixin.java b/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/mixin/MapBlockStateRegistryIdsBlockMixin.java
deleted file mode 100644
index 3060df52..00000000
--- a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/mixin/MapBlockStateRegistryIdsBlockMixin.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package spout.gamecontent.datadriven.block.mixin;
-
-import net.minecraft.core.IdMapper;
-import net.minecraft.world.level.block.Block;
-import net.minecraft.world.level.block.state.BlockState;
-import org.spongepowered.asm.mixin.Final;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Mutable;
-import org.spongepowered.asm.mixin.Shadow;
-import org.spongepowered.asm.mixin.injection.At;
-import org.spongepowered.asm.mixin.injection.Inject;
-import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
-import spout.gamecontent.datadriven.block.RemappedBlockStateRegistry;
-
-@Mixin(Block.class)
-public abstract class MapBlockStateRegistryIdsBlockMixin {
-
- @Shadow
- @Final
- @Mutable
- public static IdMapper BLOCK_STATE_REGISTRY;
-
- @Inject(method = "", at = @At("TAIL"))
- private static void replaceBlockStateRegistry(CallbackInfo ci) {
- BLOCK_STATE_REGISTRY = new RemappedBlockStateRegistry();
- }
-
-}
diff --git a/spoutcraft-fabric/.editorconfig b/spoutcraft-mod/.editorconfig
similarity index 100%
rename from spoutcraft-fabric/.editorconfig
rename to spoutcraft-mod/.editorconfig
diff --git a/spoutcraft-fabric/.gitignore b/spoutcraft-mod/.gitignore
similarity index 100%
rename from spoutcraft-fabric/.gitignore
rename to spoutcraft-mod/.gitignore
diff --git a/spoutcraft-mod/build.gradle.kts b/spoutcraft-mod/build.gradle.kts
new file mode 100644
index 00000000..1cf55f0a
--- /dev/null
+++ b/spoutcraft-mod/build.gradle.kts
@@ -0,0 +1,8 @@
+plugins {
+ base
+}
+
+tasks.named("build") {
+ dependsOn(":fabric:build")
+ dependsOn(":neoforge:build")
+}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/SpoutLogoIdentifier.java b/spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/SpoutLogoIdentifier.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/SpoutLogoIdentifier.java
rename to spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/SpoutLogoIdentifier.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/SwitchOverlayStyle.java b/spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/SwitchOverlayStyle.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/SwitchOverlayStyle.java
rename to spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/SwitchOverlayStyle.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ChangePositionsOfSpoutLogoLoadingOverlayMixin.java b/spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ChangePositionsOfSpoutLogoLoadingOverlayMixin.java
similarity index 97%
rename from spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ChangePositionsOfSpoutLogoLoadingOverlayMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ChangePositionsOfSpoutLogoLoadingOverlayMixin.java
index 417eb0a5..a213aa73 100644
--- a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ChangePositionsOfSpoutLogoLoadingOverlayMixin.java
+++ b/spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ChangePositionsOfSpoutLogoLoadingOverlayMixin.java
@@ -24,7 +24,7 @@ private static void adjustedGraphicsBlit(GuiGraphicsExtractor graphics, RenderPi
// Adjust parameters
int contentX = (int) ((double) graphics.guiWidth() * (double) 0.5F);
int logoY = (int) ((double) graphics.guiHeight() * (double) 0.5F);
- double logoHeight = Math.min((double) graphics.guiWidth() * (double) 0.75F, (double) graphics.guiHeight()) * ADJUSTED_GRAPHICS_WIDTH_FACTOR;
+ double logoHeight = Math.min((double) graphics.guiWidth() * (double) 0.75F, graphics.guiHeight()) * ADJUSTED_GRAPHICS_WIDTH_FACTOR;
int logoHeightHalf = (int) (logoHeight * (double) 0.5F);
double contentWidth = logoHeight * (double) 4.0F;
int logoWidthHalf = (int) (contentWidth * (double) 0.5F);
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/LoadingOverlayLogoLocationAccessor.java b/spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/LoadingOverlayLogoLocationAccessor.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/LoadingOverlayLogoLocationAccessor.java
rename to spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/LoadingOverlayLogoLocationAccessor.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceColorsAndSizesOverlayMixin.java b/spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceColorsAndSizesOverlayMixin.java
similarity index 95%
rename from spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceColorsAndSizesOverlayMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceColorsAndSizesOverlayMixin.java
index 8a1ff2ab..bac612c9 100644
--- a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceColorsAndSizesOverlayMixin.java
+++ b/spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/ReplaceColorsAndSizesOverlayMixin.java
@@ -71,9 +71,8 @@ public abstract class ReplaceColorsAndSizesOverlayMixin {
@Override
public TextureContents loadContents(ResourceManager resourceManager) throws IOException {
try (InputStream input = SpoutLogoIdentifier.open()) {
- TextureContents result = new TextureContents(NativeImage.read(input),
+ return new TextureContents(NativeImage.read(input),
new TextureMetadataSection(true, true, MipmapStrategy.MEAN, 0.0f));
- return result;
}
}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/package-info.java b/spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/package-info.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/package-info.java
rename to spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/mixin/package-info.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/package-info.java b/spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/package-info.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/loadingoverlay/package-info.java
rename to spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/loadingoverlay/package-info.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/package-info.java b/spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/package-info.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/package-info.java
rename to spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/package-info.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/toast/mixin/IgnoreResourcePackDownloadProgressMixin.java b/spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/toast/mixin/IgnoreResourcePackDownloadProgressMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/toast/mixin/IgnoreResourcePackDownloadProgressMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/toast/mixin/IgnoreResourcePackDownloadProgressMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/toast/mixin/package-info.java b/spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/toast/mixin/package-info.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/toast/mixin/package-info.java
rename to spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/toast/mixin/package-info.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/toast/package-info.java b/spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/toast/package-info.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientui/resourcepack/toast/package-info.java
rename to spoutcraft-mod/common/src/client/java/spout/clientui/resourcepack/toast/package-info.java
diff --git a/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/command/SpoutcraftCommand.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/command/SpoutcraftCommand.java
new file mode 100644
index 00000000..6764af16
--- /dev/null
+++ b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/command/SpoutcraftCommand.java
@@ -0,0 +1,77 @@
+package spout.clientview.clientmod.command;
+
+import com.mojang.brigadier.Command;
+import com.mojang.brigadier.CommandDispatcher;
+import com.mojang.brigadier.builder.LiteralArgumentBuilder;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.multiplayer.ClientSuggestionProvider;
+import net.minecraft.network.chat.Component;
+import spout.clientview.clientmod.protocol.ClientModCustomContentReceiving;
+import spout.clientview.clientmod.protocol.SpoutProtocol;
+
+/**
+ * Client-side diagnostics for Spoutcraft.
+ */
+public final class SpoutcraftCommand {
+
+ private static final String NAME = "spoutcraft";
+ private static final String UNKNOWN = "unknown";
+
+ private SpoutcraftCommand() {
+ throw new UnsupportedOperationException();
+ }
+
+ public static void register(CommandDispatcher dispatcher) {
+ dispatcher.register(
+ LiteralArgumentBuilder.literal(NAME)
+ .executes(context -> {
+ showInfo();
+ return Command.SINGLE_SUCCESS;
+ })
+ );
+ }
+
+ public static boolean executeIfSpoutcraftCommand(String command) {
+ if (!command.equals(NAME)) {
+ return false;
+ }
+ showInfo();
+ return true;
+ }
+
+ private static void showInfo() {
+ ClientModCustomContentReceiving.LoadedContentSummary summary =
+ ClientModCustomContentReceiving.getLoadedContentSummary();
+
+ send("Spoutcraft");
+ send("State: " + SpoutProtocol.getState());
+ send("Server protocol: " + protocolRange());
+ send("Negotiated protocol: " + unknownIfNegative(SpoutProtocol.getSelectedProtocolVersion()));
+ send("Loaded blocks: " + summary.blocks());
+ send("Loaded block states: " + summary.blockStates());
+ send("Loaded items: " + summary.items());
+ send("Registry id lists: " + summary.registryIdLists());
+ send("Block-state id lists: " + summary.blockStateIdLists());
+ }
+
+ private static String protocolRange() {
+ int min = SpoutProtocol.getServerMinProtocolVersion();
+ int max = SpoutProtocol.getServerMaxProtocolVersion();
+ if (min < 0 || max < 0) {
+ return UNKNOWN;
+ }
+ return min + "-" + max;
+ }
+
+ private static String unknownIfNegative(int value) {
+ return value < 0 ? UNKNOWN : Integer.toString(value);
+ }
+
+ private static void send(String message) {
+ Minecraft client = Minecraft.getInstance();
+ if (client.player != null) {
+ client.player.sendSystemMessage(Component.literal(message));
+ }
+ }
+
+}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/ClientModCustomContentReceiving.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/ClientModCustomContentReceiving.java
similarity index 78%
rename from spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/ClientModCustomContentReceiving.java
rename to spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/ClientModCustomContentReceiving.java
index aa71db16..393649bb 100644
--- a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/ClientModCustomContentReceiving.java
+++ b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/ClientModCustomContentReceiving.java
@@ -12,7 +12,6 @@
import org.jspecify.annotations.Nullable;
import spout.gamecontent.datadriven.common.registry.temporarymodification.TemporaryRegistryModifiers;
import spout.gamecontent.datadriven.block.BlockStateRegistryIdMappings;
-import spout.gamecontent.datadriven.block.RemappedBlockStateRegistry;
import spout.clientview.clientmod.registryidmapping.RegistryIdMappings;
import spout.clientview.clientmod.registryidmapping.BlockStateRegistryEntryIdList;
import spout.gamecontent.datadriven.block.ContextAwareBlockPropertiesDecoding;
@@ -36,6 +35,7 @@ private ClientModCustomContentReceiving() {
* The current received content, or null if not currently receiving.
*/
private static volatile @Nullable ClientModCustomContent receivedContent;
+ private static volatile LoadedContentSummary loadedContentSummary = LoadedContentSummary.empty();
public static void handlePacket(ClientModCustomContentPacketPayload payload) {
while (SpoutProtocol.getState() != ClientModState.RECEIVED_CUSTOM_CONTENT && !SpoutProtocol.tryChangeState(ClientModState.CLIENT_MOD_DETECTED, ClientModState.RECEIVED_CUSTOM_CONTENT)) {
@@ -72,34 +72,29 @@ public static void handlePacket(ClientModCustomContentPacketPayload payload) {
});
}).toList()
);
- RemappedBlockStateRegistry blockStateRegistry =
- (RemappedBlockStateRegistry) Block.BLOCK_STATE_REGISTRY;
+ int blockStateCount = 0;
for (var keyedValue : receivedContent.getBlocks()) {
Block block = BuiltInRegistries.BLOCK.get(keyedValue.identifier()).orElseThrow().value();
for (BlockState state : block.getStateDefinition().getPossibleStates()) {
state.initCache();
- if (blockStateRegistry.getIdUnmapped(state) == -1) {
+ blockStateCount++;
+ if (Block.BLOCK_STATE_REGISTRY.getId(state) == -1) {
Block.BLOCK_STATE_REGISTRY.add(state);
}
}
}
// Set up registry id mappings where necessary
for (RegistryEntryIdList list : receivedContent.getRegistryEntryIdLists()) {
- Registry registry = BuiltInRegistries.REGISTRY.getValue(list.registryIdentifier());
+ Registry> registry = BuiltInRegistries.REGISTRY.getValue(list.registryIdentifier());
if (registry != null) {
- for (IntObjectPair pair : list.entryIds()) {
- int currentId = registry.getId(registry.getValue(pair.right()));
- if (currentId != pair.leftInt()) {
- RegistryIdMappings.add(registry, currentId, pair.leftInt());
- }
- }
+ addRegistryIdMappings(registry, list);
}
}
// Set up block state mappings where necessary
for (BlockStateRegistryEntryIdList list : receivedContent.getBlockStateRegistryEntryIdLists()) {
for (IntObjectPair pair : list.entryIds()) {
BlockState state = BlockStateStringConversion.blockStateFromString(pair.right());
- int idOnClient = ((RemappedBlockStateRegistry) Block.BLOCK_STATE_REGISTRY).getIdUnmapped(state);
+ int idOnClient = Block.BLOCK_STATE_REGISTRY.getId(state);
int receivedId = pair.leftInt();
if (idOnClient != receivedId) {
BlockStateRegistryIdMappings.add(idOnClient, receivedId);
@@ -107,6 +102,13 @@ public static void handlePacket(ClientModCustomContentPacketPayload payload) {
}
}
// Change the state
+ loadedContentSummary = new LoadedContentSummary(
+ receivedContent.getBlocks().size(),
+ receivedContent.getItems().size(),
+ blockStateCount,
+ receivedContent.getRegistryEntryIdLists().size(),
+ receivedContent.getBlockStateRegistryEntryIdLists().size()
+ );
SpoutProtocol.changeState(ClientModState.RECEIVED_CUSTOM_CONTENT, ClientModState.ADDED_CUSTOM_CONTENT);
receivedContent = null;
}
@@ -122,8 +124,37 @@ public static void handlePacket(ClientModCustomContentPacketPayload payload) {
}
}
+ private static void addRegistryIdMappings(Registry registry, RegistryEntryIdList list) {
+ for (IntObjectPair pair : list.entryIds()) {
+ T value = registry.getValue(pair.right());
+ int currentId = registry.getId(value);
+ if (currentId != pair.leftInt()) {
+ RegistryIdMappings.add(registry, currentId, pair.leftInt());
+ }
+ }
+ }
+
static void clear() {
receivedContent = null;
+ loadedContentSummary = LoadedContentSummary.empty();
+ }
+
+ public static LoadedContentSummary getLoadedContentSummary() {
+ return loadedContentSummary;
+ }
+
+ public record LoadedContentSummary(
+ int blocks,
+ int items,
+ int blockStates,
+ int registryIdLists,
+ int blockStateIdLists
+ ) {
+
+ private static LoadedContentSummary empty() {
+ return new LoadedContentSummary(0, 0, 0, 0, 0);
+ }
+
}
}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/ClientModState.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/ClientModState.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/ClientModState.java
rename to spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/ClientModState.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/SpoutProtocol.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/SpoutProtocol.java
similarity index 84%
rename from spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/SpoutProtocol.java
rename to spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/SpoutProtocol.java
index 394be709..653f5ac2 100644
--- a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/SpoutProtocol.java
+++ b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/SpoutProtocol.java
@@ -26,6 +26,9 @@ public final class SpoutProtocol {
private static final int MAX_PROTOCOL_VERSION = 5;
private static final AtomicReference state = new AtomicReference<>(ClientModState.IDLE);
+ private static volatile int serverMinProtocolVersion = -1;
+ private static volatile int serverMaxProtocolVersion = -1;
+ private static volatile int selectedProtocolVersion = -1;
private SpoutProtocol() {
throw new UnsupportedOperationException();
@@ -60,18 +63,20 @@ public static CustomQueryAnswerPayload createClientModDetectionAnswer(CustomQuer
detectionPayload.maxProtocolVersion,
MAX_PROTOCOL_VERSION
);
- int responseProtocolVersion = -1; // In case of failure, respond with an invalid version.
- if (bestProtocolVersion >= detectionPayload.minProtocolVersion
- && bestProtocolVersion >= MIN_PROTOCOL_VERSION) {
+ int responseProtocolVersion =
+ bestProtocolVersion >= detectionPayload.minProtocolVersion
+ && bestProtocolVersion == MIN_PROTOCOL_VERSION ? bestProtocolVersion : -1;
+ if (responseProtocolVersion != -1) {
changeState(ClientModState.HANDSHAKE_STARTED, ClientModState.CLIENT_MOD_DETECTED);
SwitchOverlayStyle.setSpout();
- responseProtocolVersion = bestProtocolVersion;
}
- int selectedProtocolVersion = responseProtocolVersion;
+ serverMinProtocolVersion = detectionPayload.minProtocolVersion;
+ serverMaxProtocolVersion = detectionPayload.maxProtocolVersion;
+ selectedProtocolVersion = responseProtocolVersion;
return output -> {
output.writeVarInt(0);
output.writeVarInt(detectionPayload.nonce);
- output.writeVarInt(selectedProtocolVersion);
+ output.writeVarInt(responseProtocolVersion);
};
}
@@ -103,6 +108,9 @@ public static void onConfigurationStart(ClientCommonPacketListenerImpl handler)
public static void onDisconnect() {
SwitchOverlayStyle.setMojang();
ClientModState oldState = state.getAndSet(ClientModState.IDLE);
+ serverMinProtocolVersion = -1;
+ serverMaxProtocolVersion = -1;
+ selectedProtocolVersion = -1;
ClientModCustomContentReceiving.clear();
if (oldState == ClientModState.ADDED_CUSTOM_CONTENT) {
TemporaryRegistryModifiers.removeCustomContent();
@@ -125,6 +133,18 @@ public static ClientModState getState() {
return state.get();
}
+ public static int getServerMinProtocolVersion() {
+ return serverMinProtocolVersion;
+ }
+
+ public static int getServerMaxProtocolVersion() {
+ return serverMaxProtocolVersion;
+ }
+
+ public static int getSelectedProtocolVersion() {
+ return selectedProtocolVersion;
+ }
+
public record ClientModDetectionQueryPayload(
int protocolMarker,
int nonce,
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/AllowSpoutServerPacksMixin.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/AllowSpoutServerPacksMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/AllowSpoutServerPacksMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/AllowSpoutServerPacksMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientCommonPacketListenerImplAccessor.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientCommonPacketListenerImplAccessor.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientCommonPacketListenerImplAccessor.java
rename to spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientCommonPacketListenerImplAccessor.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientCommonPacketListenerImplMixin.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientCommonPacketListenerImplMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientCommonPacketListenerImplMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientCommonPacketListenerImplMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientConfigurationPacketListenerImplMixin.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientConfigurationPacketListenerImplMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientConfigurationPacketListenerImplMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientConfigurationPacketListenerImplMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientHandshakePacketListenerImplMixin.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientHandshakePacketListenerImplMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientHandshakePacketListenerImplMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientHandshakePacketListenerImplMixin.java
diff --git a/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientPacketListenerMixin.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientPacketListenerMixin.java
new file mode 100644
index 00000000..71e93a8d
--- /dev/null
+++ b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientPacketListenerMixin.java
@@ -0,0 +1,38 @@
+package spout.clientview.clientmod.protocol.mixin;
+
+import com.mojang.brigadier.CommandDispatcher;
+import net.minecraft.client.multiplayer.ClientSuggestionProvider;
+import net.minecraft.client.multiplayer.ClientPacketListener;
+import net.minecraft.network.protocol.game.ClientboundCommandsPacket;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+import spout.clientview.clientmod.command.SpoutcraftCommand;
+import spout.clientview.clientmod.protocol.SpoutProtocol;
+
+@Mixin(ClientPacketListener.class)
+public abstract class ClientPacketListenerMixin {
+
+ @Shadow
+ private CommandDispatcher commands;
+
+ @Inject(method = "clearLevel", at = @At("HEAD"))
+ private void removeSpoutContentBeforeClearingLevel(CallbackInfo ci) {
+ SpoutProtocol.onDisconnect();
+ }
+
+ @Inject(method = "handleCommands", at = @At("TAIL"))
+ private void registerSpoutcraftCommand(ClientboundCommandsPacket packet, CallbackInfo ci) {
+ SpoutcraftCommand.register(this.commands);
+ }
+
+ @Inject(method = "sendCommand", at = @At("HEAD"), cancellable = true)
+ private void runSpoutcraftCommand(String command, CallbackInfo ci) {
+ if (SpoutcraftCommand.executeIfSpoutcraftCommand(command)) {
+ ci.cancel();
+ }
+ }
+
+}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientboundCustomQueryPacketMixin.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientboundCustomQueryPacketMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientboundCustomQueryPacketMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/ClientboundCustomQueryPacketMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/CustomPacketPayloadCodecMixin.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/CustomPacketPayloadCodecMixin.java
similarity index 88%
rename from spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/CustomPacketPayloadCodecMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/CustomPacketPayloadCodecMixin.java
index cc0b74e4..7eeac8a8 100644
--- a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/CustomPacketPayloadCodecMixin.java
+++ b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/CustomPacketPayloadCodecMixin.java
@@ -19,7 +19,7 @@ private void findSpoutCodec(
CallbackInfoReturnable> cir
) {
if (ClientModCustomContentPacketPayload.TYPE.id().equals(identifier)) {
- cir.setReturnValue((StreamCodec super B, ? extends CustomPacketPayload>) ClientModCustomContentPacketPayload.STREAM_CODEC);
+ cir.setReturnValue(ClientModCustomContentPacketPayload.STREAM_CODEC);
}
}
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/package-info.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/package-info.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientview/clientmod/protocol/mixin/package-info.java
rename to spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/protocol/mixin/package-info.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/registryidmapping/RegistryIdMappings.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/registryidmapping/RegistryIdMappings.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientview/clientmod/registryidmapping/RegistryIdMappings.java
rename to spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/registryidmapping/RegistryIdMappings.java
diff --git a/spoutcraft-fabric/src/client/java/spout/clientview/clientmod/registryidmapping/mixin/MapIdsByteBufCodecsMixin.java b/spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/registryidmapping/mixin/MapIdsByteBufCodecsMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/clientview/clientmod/registryidmapping/mixin/MapIdsByteBufCodecsMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/clientview/clientmod/registryidmapping/mixin/MapIdsByteBufCodecsMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/BlockStateRegistryIdMappings.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/BlockStateRegistryIdMappings.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/BlockStateRegistryIdMappings.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/BlockStateRegistryIdMappings.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/TemporaryBlockRegistryModifier.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/TemporaryBlockRegistryModifier.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/TemporaryBlockRegistryModifier.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/TemporaryBlockRegistryModifier.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/mixin/BlockCodecAccessorBlockMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/mixin/BlockCodecAccessorBlockMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/mixin/BlockCodecAccessorBlockMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/mixin/BlockCodecAccessorBlockMixin.java
diff --git a/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/mixin/MapBlockStateRegistryIdsIdMapperMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/mixin/MapBlockStateRegistryIdsIdMapperMixin.java
new file mode 100644
index 00000000..f3b5fb57
--- /dev/null
+++ b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/mixin/MapBlockStateRegistryIdsIdMapperMixin.java
@@ -0,0 +1,22 @@
+package spout.gamecontent.datadriven.block.mixin;
+
+import net.minecraft.core.IdMapper;
+import net.minecraft.world.level.block.Block;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.ModifyVariable;
+import spout.gamecontent.datadriven.block.BlockStateRegistryIdMappings;
+
+@Mixin(IdMapper.class)
+public abstract class MapBlockStateRegistryIdsIdMapperMixin {
+
+ @ModifyVariable(method = "byId", at = @At("HEAD"), argsOnly = true)
+ private int mapBlockStateId(int id) {
+ IdMapper> registry = (IdMapper>) (Object) this;
+ if (registry == Block.BLOCK_STATE_REGISTRY) {
+ return BlockStateRegistryIdMappings.applyServerToClient(id);
+ }
+ return id;
+ }
+
+}
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/mixin/ReplaceBlockBehaviourPropertiesCodecMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/mixin/ReplaceBlockBehaviourPropertiesCodecMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/mixin/ReplaceBlockBehaviourPropertiesCodecMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/mixin/ReplaceBlockBehaviourPropertiesCodecMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/mixin/UseFormattedBlockStateCodecStairBlockMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/mixin/UseFormattedBlockStateCodecStairBlockMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/mixin/UseFormattedBlockStateCodecStairBlockMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/mixin/UseFormattedBlockStateCodecStairBlockMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/mixin/UseFormattedBlockStateCodecWeatheringCopperStairBlockMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/mixin/UseFormattedBlockStateCodecWeatheringCopperStairBlockMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/mixin/UseFormattedBlockStateCodecWeatheringCopperStairBlockMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/mixin/UseFormattedBlockStateCodecWeatheringCopperStairBlockMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/subtypes/mixin/BlockBehaviourMaxVerticalOffsetAccessorBlockBehaviourMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/subtypes/mixin/BlockBehaviourMaxVerticalOffsetAccessorBlockBehaviourMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/block/subtypes/mixin/BlockBehaviourMaxVerticalOffsetAccessorBlockBehaviourMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/block/subtypes/mixin/BlockBehaviourMaxVerticalOffsetAccessorBlockBehaviourMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/blockentity/mixin/BlockEntityTypeDataDrivenValidBlocksMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/blockentity/mixin/BlockEntityTypeDataDrivenValidBlocksMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/blockentity/mixin/BlockEntityTypeDataDrivenValidBlocksMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/blockentity/mixin/BlockEntityTypeDataDrivenValidBlocksMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/blocktype/mixin/MirrorMinecraftBlockTypeRegistryMappedRegistryMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/blocktype/mixin/MirrorMinecraftBlockTypeRegistryMappedRegistryMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/blocktype/mixin/MirrorMinecraftBlockTypeRegistryMappedRegistryMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/blocktype/mixin/MirrorMinecraftBlockTypeRegistryMappedRegistryMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/common/registry/codec/mixin/CacheByNameCodecMappedRegistryMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/common/registry/codec/mixin/CacheByNameCodecMappedRegistryMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/common/registry/codec/mixin/CacheByNameCodecMappedRegistryMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/common/registry/codec/mixin/CacheByNameCodecMappedRegistryMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/TemporaryRegistryModifier.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/TemporaryRegistryModifier.java
similarity index 92%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/TemporaryRegistryModifier.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/TemporaryRegistryModifier.java
index 2a3db759..869596fc 100644
--- a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/TemporaryRegistryModifier.java
+++ b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/TemporaryRegistryModifier.java
@@ -37,6 +37,7 @@ public TemporaryRegistryModifier(R registry) {
this.registry = registry;
}
+ @SuppressWarnings("unchecked")
public MappedRegistryAccessor getRegistryAccessor() {
return (MappedRegistryAccessor) this.registry;
}
@@ -125,8 +126,8 @@ public void remove(ResourceKey resourceKey, T resource) {
}
- private static Field allTagsField;
- private static Method unboundMethod;
+ private static final Field allTagsField;
+ private static final Method unboundMethod;
static {
try {
allTagsField = Arrays.stream(MappedRegistry.class.getDeclaredFields())
@@ -152,13 +153,18 @@ private Map, HolderSet.Named> copyFrozenTags(Map, HolderS
Map, HolderSet.Named> target = new IdentityHashMap<>();
for (Map.Entry, HolderSet.Named> entry : source.entrySet()) {
HolderSet.Named holderSet = this.getRegistryAccessor().callCreateTag(entry.getValue().key());
- @Nullable List> contents = ((HolderSetNamedAccessor) entry.getValue()).getContents();
+ List> contents = this.getHolderSetAccessor(entry.getValue()).getContents();
if (contents != null) {
- ((HolderSetNamedAccessor) holderSet).callBind(new ArrayList<>(contents));
+ this.getHolderSetAccessor(holderSet).callBind(new ArrayList<>(contents));
}
target.put(entry.getKey(), holderSet);
}
return target;
}
+ @SuppressWarnings("unchecked")
+ private HolderSetNamedAccessor getHolderSetAccessor(HolderSet.Named holderSet) {
+ return (HolderSetNamedAccessor) holderSet;
+ }
+
}
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/TemporaryRegistryModifiers.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/TemporaryRegistryModifiers.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/TemporaryRegistryModifiers.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/TemporaryRegistryModifiers.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/mixin/HolderSetNamedAccessor.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/mixin/HolderSetNamedAccessor.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/mixin/HolderSetNamedAccessor.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/mixin/HolderSetNamedAccessor.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/mixin/MappedRegistryAccessor.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/mixin/MappedRegistryAccessor.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/mixin/MappedRegistryAccessor.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/common/registry/temporarymodification/mixin/MappedRegistryAccessor.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/TemporaryItemRegistryModifier.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/TemporaryItemRegistryModifier.java
similarity index 93%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/TemporaryItemRegistryModifier.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/TemporaryItemRegistryModifier.java
index a23f7bcd..5b8c49b4 100644
--- a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/TemporaryItemRegistryModifier.java
+++ b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/TemporaryItemRegistryModifier.java
@@ -48,7 +48,10 @@ public void removeWhileUnfrozen(List, Item>> resources) {
private static ResourceKey> getInitializerResourceKey(Object initializer) {
if (initializerResourceKeyField == null) {
- initializerResourceKeyField = Arrays.stream(initializer.getClass().getDeclaredFields()).filter(field -> field.getType() == ResourceKey.class).findFirst().get();
+ initializerResourceKeyField = Arrays.stream(initializer.getClass().getDeclaredFields())
+ .filter(field -> field.getType() == ResourceKey.class)
+ .findFirst()
+ .orElseThrow();
initializerResourceKeyField.setAccessible(true);
}
try {
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/mixin/DataComponentInitializersAccessor.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/mixin/DataComponentInitializersAccessor.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/mixin/DataComponentInitializersAccessor.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/mixin/DataComponentInitializersAccessor.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemPropertiesSerializationDecoratorItemPropertiesMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemPropertiesSerializationDecoratorItemPropertiesMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemPropertiesSerializationDecoratorItemPropertiesMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemPropertiesSerializationDecoratorItemPropertiesMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorBlockItemMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorBlockItemMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorBlockItemMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorBlockItemMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorDoubleHighBlockItemMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorDoubleHighBlockItemMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorDoubleHighBlockItemMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorDoubleHighBlockItemMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorEggItemMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorEggItemMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorEggItemMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorEggItemMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorItemMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorItemMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorItemMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/item/mixin/ItemTypeDecoratorItemMixin.java
diff --git a/spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/mixin/IncludeSpoutBootstrapBuiltInRegistriesMixin.java b/spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/mixin/IncludeSpoutBootstrapBuiltInRegistriesMixin.java
similarity index 100%
rename from spoutcraft-fabric/src/client/java/spout/gamecontent/datadriven/mixin/IncludeSpoutBootstrapBuiltInRegistriesMixin.java
rename to spoutcraft-mod/common/src/client/java/spout/gamecontent/datadriven/mixin/IncludeSpoutBootstrapBuiltInRegistriesMixin.java
diff --git a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.clientui.resourcepack.loadingoverlay.mixins.json b/spoutcraft-mod/common/src/client/resources/spoutcraft.spout.clientui.resourcepack.loadingoverlay.mixins.json
similarity index 64%
rename from spoutcraft-fabric/src/client/resources/spoutcraft.spout.clientui.resourcepack.loadingoverlay.mixins.json
rename to spoutcraft-mod/common/src/client/resources/spoutcraft.spout.clientui.resourcepack.loadingoverlay.mixins.json
index e943836b..14cee7cd 100644
--- a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.clientui.resourcepack.loadingoverlay.mixins.json
+++ b/spoutcraft-mod/common/src/client/resources/spoutcraft.spout.clientui.resourcepack.loadingoverlay.mixins.json
@@ -5,9 +5,7 @@
"client": [
"ChangePositionsOfSpoutLogoLoadingOverlayMixin",
"LoadingOverlayLogoLocationAccessor",
- "ReplaceColorsAndSizesOverlayMixin",
- "ReplaceLogoWhenRegisteringTexturesLoadingOverlayMixin",
- "ReplaceMojangLogoAfterTexturesRegisteredMixin"
+ "ReplaceColorsAndSizesOverlayMixin"
],
"injectors": {
"defaultRequire": 1
diff --git a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.clientui.resourcepack.toast.mixins.json b/spoutcraft-mod/common/src/client/resources/spoutcraft.spout.clientui.resourcepack.toast.mixins.json
similarity index 100%
rename from spoutcraft-fabric/src/client/resources/spoutcraft.spout.clientui.resourcepack.toast.mixins.json
rename to spoutcraft-mod/common/src/client/resources/spoutcraft.spout.clientui.resourcepack.toast.mixins.json
diff --git a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.clientview.clientmod.protocol.mixins.json b/spoutcraft-mod/common/src/client/resources/spoutcraft.spout.clientview.clientmod.protocol.mixins.json
similarity index 100%
rename from spoutcraft-fabric/src/client/resources/spoutcraft.spout.clientview.clientmod.protocol.mixins.json
rename to spoutcraft-mod/common/src/client/resources/spoutcraft.spout.clientview.clientmod.protocol.mixins.json
diff --git a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.clientview.clientmod.registryidmapping.mixins.json b/spoutcraft-mod/common/src/client/resources/spoutcraft.spout.clientview.clientmod.registryidmapping.mixins.json
similarity index 100%
rename from spoutcraft-fabric/src/client/resources/spoutcraft.spout.clientview.clientmod.registryidmapping.mixins.json
rename to spoutcraft-mod/common/src/client/resources/spoutcraft.spout.clientview.clientmod.registryidmapping.mixins.json
diff --git a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.block.mixins.json b/spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.block.mixins.json
similarity index 89%
rename from spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.block.mixins.json
rename to spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.block.mixins.json
index 898a0d1a..03df290b 100644
--- a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.block.mixins.json
+++ b/spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.block.mixins.json
@@ -4,7 +4,7 @@
"compatibilityLevel": "JAVA_25",
"mixins": [
"BlockCodecAccessorBlockMixin",
- "MapBlockStateRegistryIdsBlockMixin",
+ "MapBlockStateRegistryIdsIdMapperMixin",
"ReplaceBlockBehaviourPropertiesCodecMixin",
"UseFormattedBlockStateCodecStairBlockMixin",
"UseFormattedBlockStateCodecWeatheringCopperStairBlockMixin"
diff --git a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.block.subtypes.mixins.json b/spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.block.subtypes.mixins.json
similarity index 100%
rename from spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.block.subtypes.mixins.json
rename to spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.block.subtypes.mixins.json
diff --git a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.blockentity.mixins.json b/spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.blockentity.mixins.json
similarity index 100%
rename from spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.blockentity.mixins.json
rename to spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.blockentity.mixins.json
diff --git a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.blocktype.mixins.json b/spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.blocktype.mixins.json
similarity index 100%
rename from spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.blocktype.mixins.json
rename to spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.blocktype.mixins.json
diff --git a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.common.registry.codec.mixins.json b/spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.common.registry.codec.mixins.json
similarity index 100%
rename from spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.common.registry.codec.mixins.json
rename to spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.common.registry.codec.mixins.json
diff --git a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.common.registry.temporarymodification.mixins.json b/spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.common.registry.temporarymodification.mixins.json
similarity index 100%
rename from spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.common.registry.temporarymodification.mixins.json
rename to spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.common.registry.temporarymodification.mixins.json
diff --git a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.item.mixins.json b/spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.item.mixins.json
similarity index 100%
rename from spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.item.mixins.json
rename to spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.item.mixins.json
diff --git a/spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.mixins.json b/spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.mixins.json
similarity index 100%
rename from spoutcraft-fabric/src/client/resources/spoutcraft.spout.gamecontent.datadriven.mixins.json
rename to spoutcraft-mod/common/src/client/resources/spoutcraft.spout.gamecontent.datadriven.mixins.json
diff --git a/spoutcraft-fabric/build.gradle.kts b/spoutcraft-mod/fabric/build.gradle.kts
similarity index 81%
rename from spoutcraft-fabric/build.gradle.kts
rename to spoutcraft-mod/fabric/build.gradle.kts
index 48bece3e..a8af2bbf 100644
--- a/spoutcraft-fabric/build.gradle.kts
+++ b/spoutcraft-mod/fabric/build.gradle.kts
@@ -7,7 +7,7 @@ version = providers.gradleProperty("mod_version").get()
group = providers.gradleProperty("maven_group").get()
base {
- archivesName = providers.gradleProperty("archives_base_name")
+ archivesName = providers.gradleProperty("archives_base_name").map { "$it-fabric" }
}
repositories {
@@ -32,12 +32,14 @@ loom {
}
sourceSets.getByName("client") {
- java.srcDir("../common-src/src/main/java")
- java.srcDir("../common-minecraft-src/src/main/java")
- java.srcDir("../common-fabric-src/src/main/java")
- resources.srcDir("../common-src/src/main/resources")
- resources.srcDir("../common-minecraft-src/src/main/resources")
- resources.srcDir("../common-fabric-src/src/main/resources")
+ java.srcDir("../common/src/client/java")
+ java.srcDir("../../common-src/src/main/java")
+ java.srcDir("../../common-minecraft-src/src/main/java")
+ java.srcDir("../../common-fabric-src/src/main/java")
+ resources.srcDir("../common/src/client/resources")
+ resources.srcDir("../../common-src/src/main/resources")
+ resources.srcDir("../../common-minecraft-src/src/main/resources")
+ resources.srcDir("../../common-fabric-src/src/main/resources")
}
dependencies {
@@ -77,7 +79,7 @@ tasks.jar {
inputs.property("archivesName", archivesName)
inputs.property("projectName", projectName)
- from("LICENSE.md") {
+ from(rootProject.file("../LICENSE.md")) {
rename { "${it}_${projectName}" }
}
diff --git a/spoutcraft-fabric/src/main/resources/fabric.mod.json b/spoutcraft-mod/fabric/src/main/resources/fabric.mod.json
similarity index 100%
rename from spoutcraft-fabric/src/main/resources/fabric.mod.json
rename to spoutcraft-mod/fabric/src/main/resources/fabric.mod.json
diff --git a/spoutcraft-fabric/src/main/resources/spoutcraft.classtweaker b/spoutcraft-mod/fabric/src/main/resources/spoutcraft.classtweaker
similarity index 98%
rename from spoutcraft-fabric/src/main/resources/spoutcraft.classtweaker
rename to spoutcraft-mod/fabric/src/main/resources/spoutcraft.classtweaker
index 0ff51edc..9abb16d0 100644
--- a/spoutcraft-fabric/src/main/resources/spoutcraft.classtweaker
+++ b/spoutcraft-mod/fabric/src/main/resources/spoutcraft.classtweaker
@@ -47,4 +47,3 @@ accessible method net/minecraft/world/level/block/Blocks never (Lnet/minecraft/w
accessible method net/minecraft/world/level/block/Blocks ocelotOrParrot (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/EntityType;)Ljava/lang/Boolean;
accessible method net/minecraft/world/level/block/StairBlock (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockBehaviour$Properties;)V
accessible method net/minecraft/world/level/block/state/BlockBehaviour propertiesCodec ()Lcom/mojang/serialization/codecs/RecordCodecBuilder;
-transitive-extendable method net/minecraft/core/IdMapper byId (I)Ljava/lang/Object;
diff --git a/spoutcraft-fabric/gradle.properties b/spoutcraft-mod/gradle.properties
similarity index 82%
rename from spoutcraft-fabric/gradle.properties
rename to spoutcraft-mod/gradle.properties
index 9f68b82a..b5c5cfc8 100644
--- a/spoutcraft-fabric/gradle.properties
+++ b/spoutcraft-mod/gradle.properties
@@ -11,7 +11,11 @@ minecraft_version=26.1.2
loader_version=0.19.2
loom_version=1.16-SNAPSHOT
+# NeoForge Properties
+neoforge_version=26.1.2.76
+moddevgradle_version=2.0.141
+
# Mod Properties
mod_version=1.15-SNAPSHOT
-maven_group=spout.client.fabric
+maven_group=spout.client
archives_base_name=spoutcraft
diff --git a/spoutcraft-mod/neoforge/build.gradle.kts b/spoutcraft-mod/neoforge/build.gradle.kts
new file mode 100644
index 00000000..a85e923f
--- /dev/null
+++ b/spoutcraft-mod/neoforge/build.gradle.kts
@@ -0,0 +1,80 @@
+plugins {
+ id("net.neoforged.moddev")
+ `maven-publish`
+}
+
+version = providers.gradleProperty("mod_version").get()
+group = providers.gradleProperty("maven_group").get()
+
+base {
+ archivesName = providers.gradleProperty("archives_base_name").map { "$it-neoforge" }
+}
+
+repositories {
+ mavenCentral()
+}
+
+neoForge {
+ version = providers.gradleProperty("neoforge_version").get()
+
+ accessTransformers {
+ file("src/main/resources/META-INF/accesstransformer.cfg")
+ }
+
+ mods {
+ register("spoutcraft_mod") {
+ sourceSet(sourceSets.main.get())
+ }
+ }
+}
+
+sourceSets.main {
+ java.srcDir("../common/src/client/java")
+ java.srcDir("../../common-src/src/main/java")
+ java.srcDir("../../common-minecraft-src/src/main/java")
+ java.srcDir("../../common-fabric-src/src/main/java")
+ resources.srcDir("../common/src/client/resources")
+ resources.srcDir("../../common-src/src/main/resources")
+ resources.srcDir("../../common-minecraft-src/src/main/resources")
+ resources.srcDir("../../common-fabric-src/src/main/resources")
+}
+
+tasks.processResources {
+ val version = project.version
+ inputs.property("version", version)
+
+ filesMatching("META-INF/neoforge.mods.toml") {
+ expand("version" to version)
+ }
+}
+
+tasks.withType().configureEach {
+ options.release = 25
+}
+
+java {
+ withSourcesJar()
+
+ sourceCompatibility = JavaVersion.VERSION_25
+ targetCompatibility = JavaVersion.VERSION_25
+}
+
+tasks.jar {
+ val archivesName = base.archivesName
+ val projectName = project.name
+ inputs.property("archivesName", archivesName)
+ inputs.property("projectName", projectName)
+
+ from(rootProject.file("../LICENSE.md")) {
+ rename { "${it}_${projectName}" }
+ }
+}
+
+publishing {
+ publications {
+ register("mavenJava") {
+ artifactId = base.archivesName.get()
+ from(components["java"])
+ }
+ }
+}
diff --git a/spoutcraft-mod/neoforge/src/main/java/spout/neoforge/SpoutcraftNeoForgeMod.java b/spoutcraft-mod/neoforge/src/main/java/spout/neoforge/SpoutcraftNeoForgeMod.java
new file mode 100644
index 00000000..93eee3fe
--- /dev/null
+++ b/spoutcraft-mod/neoforge/src/main/java/spout/neoforge/SpoutcraftNeoForgeMod.java
@@ -0,0 +1,25 @@
+package spout.neoforge;
+
+import net.neoforged.bus.api.IEventBus;
+import net.neoforged.fml.common.Mod;
+import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
+import net.neoforged.neoforge.network.registration.HandlerThread;
+import spout.clientview.clientmod.protocol.ClientModCustomContentPacketPayload;
+import spout.clientview.clientmod.protocol.ClientModCustomContentReceiving;
+
+@Mod("spoutcraft_mod")
+public final class SpoutcraftNeoForgeMod {
+
+ public SpoutcraftNeoForgeMod(IEventBus modEventBus) {
+ modEventBus.addListener(this::registerPayloadHandlers);
+ }
+
+ private void registerPayloadHandlers(RegisterPayloadHandlersEvent event) {
+ event.registrar("1").optional().executesOn(HandlerThread.NETWORK).commonToClient(
+ ClientModCustomContentPacketPayload.TYPE,
+ ClientModCustomContentPacketPayload.STREAM_CODEC,
+ (payload, context) -> ClientModCustomContentReceiving.handlePacket(payload)
+ );
+ }
+
+}
diff --git a/spoutcraft-mod/neoforge/src/main/resources/META-INF/accesstransformer.cfg b/spoutcraft-mod/neoforge/src/main/resources/META-INF/accesstransformer.cfg
new file mode 100644
index 00000000..8b26dba6
--- /dev/null
+++ b/spoutcraft-mod/neoforge/src/main/resources/META-INF/accesstransformer.cfg
@@ -0,0 +1,47 @@
+public net.minecraft.core.registries.BuiltInRegistries$RegistryBootstrap
+public net.minecraft.world.item.Item$Properties componentInitializer
+public net.minecraft.world.item.Item$Properties id
+public net.minecraft.world.item.Item$Properties requiredFeatures
+public net.minecraft.world.flag.FeatureFlagRegistry names
+public net.minecraft.world.level.block.Blocks NOT_EXTENDED_PISTON
+public net.minecraft.world.level.block.Blocks NOT_CLOSED_SHULKER
+public net.minecraft.world.level.block.StairBlock baseState
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties canOcclude
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties destroyTime
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties dynamicShape
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties emissiveRendering
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties explosionResistance
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties friction
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties forceSolidOff
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties forceSolidOn
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties hasCollision
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties id
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties ignitedByLava
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties instrument
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties isAir
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties isRandomlyTicking
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties isRedstoneConductor
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties isSuffocating
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties isViewBlocking
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties jumpFactor
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties lightEmission
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties liquid
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties mapColor
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties offsetFunction
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties postProcess
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties pushReaction
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties replaceable
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties requiredFeatures
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties requiresCorrectToolForDrops
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties soundType
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties spawnTerrainParticles
+public net.minecraft.world.level.block.state.BlockBehaviour$Properties speedFactor
+public net.minecraft.core.registries.BuiltInRegistries internalRegister(Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/core/WritableRegistry;Lnet/minecraft/core/registries/BuiltInRegistries$RegistryBootstrap;)Lnet/minecraft/core/WritableRegistry;
+public net.minecraft.core.registries.BuiltInRegistries registerSimple(Lnet/minecraft/resources/ResourceKey;Lnet/minecraft/core/registries/BuiltInRegistries$RegistryBootstrap;)Lnet/minecraft/core/Registry;
+public net.minecraft.world.level.block.Blocks always(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z
+public net.minecraft.world.level.block.Blocks always(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/EntityType;)Ljava/lang/Boolean;
+public net.minecraft.world.level.block.Blocks never(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Z
+public net.minecraft.world.level.block.Blocks never(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/EntityType;)Ljava/lang/Boolean;
+public net.minecraft.world.level.block.Blocks ocelotOrParrot(Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/EntityType;)Ljava/lang/Boolean;
+public net.minecraft.world.level.block.StairBlock (Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockBehaviour$Properties;)V
+public net.minecraft.world.level.block.state.BlockBehaviour propertiesCodec()Lcom/mojang/serialization/codecs/RecordCodecBuilder;
diff --git a/spoutcraft-mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/spoutcraft-mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml
new file mode 100644
index 00000000..85718a0b
--- /dev/null
+++ b/spoutcraft-mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml
@@ -0,0 +1,62 @@
+modLoader = "javafml"
+loaderVersion = "[5,)"
+license = "See the included LICENSE.txt"
+issueTrackerURL = "https://github.com/ModernSpout/Spout/issues"
+
+[[mods]]
+modId = "spoutcraft_mod"
+version = "${version}"
+displayName = "Spoutcraft"
+logoFile = "assets/spout/icon.png"
+description = "Automatically downloads and installs modded content when joining Spout servers"
+authors = "Martijn Muijsers, Spoutcraft authors and contributors"
+
+[[dependencies."spoutcraft_mod"]]
+modId = "neoforge"
+type = "required"
+versionRange = "[26.1.2,)"
+ordering = "NONE"
+side = "CLIENT"
+
+[[dependencies."spoutcraft_mod"]]
+modId = "minecraft"
+type = "required"
+versionRange = "[26.1.2,26.2)"
+ordering = "NONE"
+side = "CLIENT"
+
+[[mixins]]
+config = "spoutcraft.spout.clientui.resourcepack.loadingoverlay.mixins.json"
+
+[[mixins]]
+config = "spoutcraft.spout.clientui.resourcepack.toast.mixins.json"
+
+[[mixins]]
+config = "spoutcraft.spout.clientview.clientmod.protocol.mixins.json"
+
+[[mixins]]
+config = "spoutcraft.spout.clientview.clientmod.registryidmapping.mixins.json"
+
+[[mixins]]
+config = "spoutcraft.spout.gamecontent.datadriven.block.mixins.json"
+
+[[mixins]]
+config = "spoutcraft.spout.gamecontent.datadriven.block.subtypes.mixins.json"
+
+[[mixins]]
+config = "spoutcraft.spout.gamecontent.datadriven.blockentity.mixins.json"
+
+[[mixins]]
+config = "spoutcraft.spout.gamecontent.datadriven.blocktype.mixins.json"
+
+[[mixins]]
+config = "spoutcraft.spout.gamecontent.datadriven.common.registry.codec.mixins.json"
+
+[[mixins]]
+config = "spoutcraft.spout.gamecontent.datadriven.common.registry.temporarymodification.mixins.json"
+
+[[mixins]]
+config = "spoutcraft.spout.gamecontent.datadriven.item.mixins.json"
+
+[[mixins]]
+config = "spoutcraft.spout.gamecontent.datadriven.mixins.json"
diff --git a/spoutcraft-fabric/settings.gradle.kts b/spoutcraft-mod/settings.gradle.kts
similarity index 58%
rename from spoutcraft-fabric/settings.gradle.kts
rename to spoutcraft-mod/settings.gradle.kts
index c2e4278a..c1f0a49e 100644
--- a/spoutcraft-fabric/settings.gradle.kts
+++ b/spoutcraft-mod/settings.gradle.kts
@@ -4,13 +4,21 @@ pluginManagement {
name = "Fabric"
url = uri("https://maven.fabricmc.net/")
}
+ maven {
+ name = "NeoForge"
+ url = uri("https://maven.neoforged.net/releases/")
+ }
mavenCentral()
gradlePluginPortal()
}
plugins {
id("net.fabricmc.fabric-loom") version providers.gradleProperty("loom_version")
+ id("net.neoforged.moddev") version providers.gradleProperty("moddevgradle_version")
}
}
rootProject.name = "spoutcraft-mod"
+
+include("fabric")
+include("neoforge")