From cc8f31acfa0999622b43cd20774a577e3160ec81 Mon Sep 17 00:00:00 2001
From: Hei Piao
Date: Thu, 20 Mar 2025 23:23:55 +0800
Subject: [PATCH 1/5] Port a little more for shearapi-network...
---
shearapi-network/build.gradle | 6 +-
.../network/registration/NetworkRegistry.java | 57 ++++++++--------
.../injection/IConnectionExtension.java | 7 ++
.../IConnectionProtocolExtension.java | 6 ++
.../IServerCommonPacketListenerExtension.java | 42 ++----------
.../network/mixin/ConnectionMixin.java | 18 +++++
.../mixin/ConnectionProtocolMixin.java | 21 ++++++
.../network/mixin/FriendlyByteBufMixin.java | 9 +++
.../ServerCommonPacketListenerImplMixin.java | 66 +++++++++++++++++++
...rConfigurationPacketListenerImplMixin.java | 35 ++++++++++
...erverConfigurationPacketListenerMixin.java | 10 +++
.../src/main/resources/fabric.mod.json | 1 +
.../resources/shearapi-network.accesswidener | 3 +
.../resources/shearapi-network.mixins.json | 7 +-
14 files changed, 222 insertions(+), 66 deletions(-)
create mode 100644 shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IConnectionExtension.java
create mode 100644 shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IConnectionProtocolExtension.java
create mode 100644 shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ConnectionMixin.java
create mode 100644 shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ConnectionProtocolMixin.java
create mode 100644 shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/FriendlyByteBufMixin.java
create mode 100644 shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerConfigurationPacketListenerImplMixin.java
create mode 100644 shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerConfigurationPacketListenerMixin.java
create mode 100644 shearapi-network/src/main/resources/shearapi-network.accesswidener
diff --git a/shearapi-network/build.gradle b/shearapi-network/build.gradle
index 41ef612..b39be99 100644
--- a/shearapi-network/build.gradle
+++ b/shearapi-network/build.gradle
@@ -1,4 +1,8 @@
+loom {
+ accessWidenerPath = file("src/main/resources/shearapi-network.accesswidener")
+}
+
dependencies {
api project(path: ":shearapi-utils", configuration: "namedElements")
api project(path: ":shearapi-runtime", configuration: "namedElements")
-}
\ No newline at end of file
+}
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/registration/NetworkRegistry.java b/shearapi-network/src/main/java/net/neoforged/neoforge/network/registration/NetworkRegistry.java
index 1c4ba5b..c197c09 100644
--- a/shearapi-network/src/main/java/net/neoforged/neoforge/network/registration/NetworkRegistry.java
+++ b/shearapi-network/src/main/java/net/neoforged/neoforge/network/registration/NetworkRegistry.java
@@ -43,7 +43,6 @@
import net.minecraft.server.network.ServerConfigurationPacketListenerImpl;
import net.minecraft.server.network.ServerPlayerConnection;
import net.minecraft.util.thread.ReentrantBlockableEventLoop;
-import net.neoforged.fml.config.ConfigTracker;
import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
import net.neoforged.neoforge.network.connection.ConnectionPhase;
import net.neoforged.neoforge.network.connection.ConnectionType;
@@ -284,7 +283,7 @@ public FriendlyByteBuf.Reader extends CustomPacketPayload> getReader(ResourceL
* @param packet The packet that was received.
*/
public void onModdedPacketAtServer(ServerCommonPacketListener listener, ServerboundCustomPayloadPacket packet) {
- final NetworkPayloadSetup payloadSetup = listener.getConnection().channel().attr(ATTRIBUTE_PAYLOAD_SETUP).get();
+ final NetworkPayloadSetup payloadSetup = listener.getConnection().channel.attr(ATTRIBUTE_PAYLOAD_SETUP).get();
//Check if this client was even setup properly.
if (payloadSetup == null) {
LOGGER.warn("Received a modded custom payload packet from a client that has not negotiated with the server. Disconnecting client.");
@@ -319,7 +318,7 @@ public void onModdedPacketAtServer(ServerCommonPacketListener listener, Serverbo
configurationPacketListener::finishCurrentTask,
new EventLoopSynchronizedWorkHandler<>(configurationPacketListener.getMainThreadEventLoop(), packet.payload()),
PacketFlow.SERVERBOUND,
- listener.getConnection().channel().pipeline().lastContext(),
+ listener.getConnection().channel.pipeline().lastContext(),
Optional.empty()));
} else if (listener instanceof ServerGamePacketListener playPacketListener) {
//Get the configuration channel for the packet.
@@ -347,7 +346,7 @@ public void onModdedPacketAtServer(ServerCommonPacketListener listener, Serverbo
new ServerPacketHandler(playPacketListener),
new EventLoopSynchronizedWorkHandler<>(playPacketListener.getMainThreadEventLoop(), packet.payload()),
PacketFlow.SERVERBOUND,
- listener.getConnection().channel().pipeline().lastContext(),
+ listener.getConnection().channel.pipeline().lastContext(),
listener instanceof ServerPlayerConnection connection ? Optional.of(connection.getPlayer()) : Optional.empty()));
} else {
LOGGER.error("Received a modded custom payload packet from a client that is not in the configuration or play phase. Disconnecting client.");
@@ -372,7 +371,7 @@ public boolean onModdedPacketAtClient(ClientCommonPacketListener listener, Clien
return false;
}
- final NetworkPayloadSetup payloadSetup = listener.getConnection().channel().attr(ATTRIBUTE_PAYLOAD_SETUP).get();
+ final NetworkPayloadSetup payloadSetup = listener.getConnection().channel.attr(ATTRIBUTE_PAYLOAD_SETUP).get();
//Check if this server was even setup properly.
if (payloadSetup == null) {
LOGGER.warn("Received a modded custom payload packet from a server that has not negotiated with the client. Disconnecting server.");
@@ -407,7 +406,7 @@ public boolean onModdedPacketAtClient(ClientCommonPacketListener listener, Clien
(task) -> LOGGER.warn("Tried to finish a task on the client. This should not happen. Ignoring. Task: {}", task),
new EventLoopSynchronizedWorkHandler<>(configurationPacketListener.getMainThreadEventLoop(), packet.payload()),
PacketFlow.CLIENTBOUND,
- listener.getConnection().channel().pipeline().lastContext(),
+ listener.getConnection().channel.pipeline().lastContext(),
Optional.ofNullable(configurationPacketListener.getMinecraft().player)));
} else if (listener instanceof ClientGamePacketListener playPacketListener) {
//Get the configuration channel for the packet.
@@ -435,7 +434,7 @@ public boolean onModdedPacketAtClient(ClientCommonPacketListener listener, Clien
new ClientPacketHandler(playPacketListener),
new EventLoopSynchronizedWorkHandler<>(playPacketListener.getMainThreadEventLoop(), packet.payload()),
PacketFlow.CLIENTBOUND,
- listener.getConnection().channel().pipeline().lastContext(),
+ listener.getConnection().channel.pipeline().lastContext(),
Optional.ofNullable(playPacketListener.getMinecraft().player)));
} else {
LOGGER.error("Received a modded custom payload packet from a server that is not in the configuration or play phase. Disconnecting server.");
@@ -469,9 +468,9 @@ public void onModdedConnectionDetectedAtServer(ServerConfigurationPacketListener
.map(entry -> new NegotiableNetworkComponent(entry.id(), entry.version(), entry.flow(), entry.optional()))
.toList());
- sender.getConnection().channel().attr(ATTRIBUTE_CONNECTION_TYPE).set(sender.getConnectionType());
- sender.getConnection().channel().attr(ATTRIBUTE_FLOW).set(PacketFlow.SERVERBOUND);
- sender.getConnection().channel().attr(ATTRIBUTE_PAYLOAD_SETUP).set(NetworkPayloadSetup.empty());
+ sender.getConnection().channel.attr(ATTRIBUTE_CONNECTION_TYPE).set(sender.getConnectionType());
+ sender.getConnection().channel.attr(ATTRIBUTE_FLOW).set(PacketFlow.SERVERBOUND);
+ sender.getConnection().channel.attr(ATTRIBUTE_PAYLOAD_SETUP).set(NetworkPayloadSetup.empty());
//Negotiation failed. Disconnect the client.
if (!configurationNegotiationResult.success()) {
@@ -508,7 +507,7 @@ public void onModdedConnectionDetectedAtServer(ServerConfigurationPacketListener
.map(entry -> new NetworkChannel(entry.id(), entry.version()))
.collect(Collectors.toSet()));
- sender.getConnection().channel().attr(ATTRIBUTE_PAYLOAD_SETUP).set(setup);
+ sender.getConnection().channel.attr(ATTRIBUTE_PAYLOAD_SETUP).set(setup);
NetworkFilters.injectIfNecessary(sender.getConnection(), sender.getConnectionType());
@@ -537,9 +536,9 @@ public boolean onVanillaOrOtherConnectionDetectedAtServer(ServerConfigurationPac
List.of());
//Because we are in vanilla land, no matter what we are not able to support any custom channels.
- sender.getConnection().channel().attr(ATTRIBUTE_PAYLOAD_SETUP).set(NetworkPayloadSetup.empty());
- sender.getConnection().channel().attr(ATTRIBUTE_CONNECTION_TYPE).set(sender.getConnectionType());
- sender.getConnection().channel().attr(ATTRIBUTE_FLOW).set(PacketFlow.SERVERBOUND);
+ sender.getConnection().channel.attr(ATTRIBUTE_PAYLOAD_SETUP).set(NetworkPayloadSetup.empty());
+ sender.getConnection().channel.attr(ATTRIBUTE_CONNECTION_TYPE).set(sender.getConnectionType());
+ sender.getConnection().channel.attr(ATTRIBUTE_FLOW).set(PacketFlow.SERVERBOUND);
//Negotiation failed. Disconnect the client.
if (!configurationNegotiationResult.success()) {
@@ -678,11 +677,11 @@ public boolean canSendPacket(Packet> packet, ClientCommonPacketListener listen
* Returns a mutable map of the currently known ad-hoc channels.
*/
private Set getKnownAdHocChannelsOfOtherEnd(Connection connection) {
- var map = connection.channel().attr(ATTRIBUTE_ADHOC_CHANNELS).get();
+ var map = connection.channel.attr(ATTRIBUTE_ADHOC_CHANNELS).get();
if (map == null) {
map = new HashSet<>();
- connection.channel().attr(ATTRIBUTE_ADHOC_CHANNELS).set(map);
+ connection.channel.attr(ATTRIBUTE_ADHOC_CHANNELS).set(map);
}
return map;
@@ -766,9 +765,9 @@ public void onModdedNetworkConnectionEstablished(ClientConfigurationPacketListen
NetworkFilters.injectIfNecessary(listener.getConnection(), listener.getConnectionType());
- listener.getConnection().channel().attr(ATTRIBUTE_PAYLOAD_SETUP).set(setup);
- listener.getConnection().channel().attr(ATTRIBUTE_CONNECTION_TYPE).set(listener.getConnectionType());
- listener.getConnection().channel().attr(ATTRIBUTE_FLOW).set(PacketFlow.CLIENTBOUND);
+ listener.getConnection().channel.attr(ATTRIBUTE_PAYLOAD_SETUP).set(setup);
+ listener.getConnection().channel.attr(ATTRIBUTE_CONNECTION_TYPE).set(listener.getConnectionType());
+ listener.getConnection().channel.attr(ATTRIBUTE_FLOW).set(PacketFlow.CLIENTBOUND);
final ImmutableSet.Builder nowListeningOn = ImmutableSet.builder();
nowListeningOn.addAll(getInitialClientListeningChannels());
@@ -798,9 +797,9 @@ public boolean onVanillaNetworkConnectionEstablished(ClientConfigurationPacketLi
.toList());
//Because we are in vanilla land, no matter what we are not able to support any custom channels.
- sender.getConnection().channel().attr(ATTRIBUTE_PAYLOAD_SETUP).set(NetworkPayloadSetup.empty());
- sender.getConnection().channel().attr(ATTRIBUTE_CONNECTION_TYPE).set(sender.getConnectionType());
- sender.getConnection().channel().attr(ATTRIBUTE_FLOW).set(PacketFlow.CLIENTBOUND);
+ sender.getConnection().channel.attr(ATTRIBUTE_PAYLOAD_SETUP).set(NetworkPayloadSetup.empty());
+ sender.getConnection().channel.attr(ATTRIBUTE_CONNECTION_TYPE).set(sender.getConnectionType());
+ sender.getConnection().channel.attr(ATTRIBUTE_FLOW).set(PacketFlow.CLIENTBOUND);
//Negotiation failed. Disconnect the client.
if (!configurationNegotiationResult.success()) {
@@ -867,7 +866,7 @@ public boolean isConnected(ClientCommonPacketListener listener, ResourceLocation
* @return True if the connection has a connection setup that can transmit the given payload id, false otherwise.
*/
public boolean isConnected(final Connection connection, ConnectionPhase connectionPhase, ResourceLocation payloadId) {
- final NetworkPayloadSetup payloadSetup = connection.channel().attr(ATTRIBUTE_PAYLOAD_SETUP).get();
+ final NetworkPayloadSetup payloadSetup = connection.channel.attr(ATTRIBUTE_PAYLOAD_SETUP).get();
if (payloadSetup == null) {
return getKnownAdHocChannelsOfOtherEnd(connection).contains(payloadId);
}
@@ -933,9 +932,9 @@ public List> filterGameBundlePackets(Channe
* @param connection The connection to configure.
*/
public void configureMockConnection(final Connection connection) {
- connection.channel().attr(ATTRIBUTE_CONNECTION_TYPE).set(ConnectionType.NEOFORGE);
- connection.channel().attr(ATTRIBUTE_FLOW).set(PacketFlow.SERVERBOUND);
- connection.channel().attr(ATTRIBUTE_PAYLOAD_SETUP).set(NetworkPayloadSetup.empty());
+ connection.channel.attr(ATTRIBUTE_CONNECTION_TYPE).set(ConnectionType.NEOFORGE);
+ connection.channel.attr(ATTRIBUTE_FLOW).set(PacketFlow.SERVERBOUND);
+ connection.channel.attr(ATTRIBUTE_PAYLOAD_SETUP).set(NetworkPayloadSetup.empty());
final NetworkPayloadSetup setup = NetworkPayloadSetup.from(
this.knownConfigurationRegistrations.entrySet().stream()
@@ -945,7 +944,7 @@ public void configureMockConnection(final Connection connection) {
.map(entry -> new NetworkChannel(entry.getKey(), entry.getValue().version()))
.collect(Collectors.toSet()));
- connection.channel().attr(ATTRIBUTE_PAYLOAD_SETUP).set(setup);
+ connection.channel.attr(ATTRIBUTE_PAYLOAD_SETUP).set(setup);
NetworkFilters.injectIfNecessary(connection, ConnectionType.NEOFORGE);
}
@@ -1041,7 +1040,7 @@ private static Set getInitialClientListeningChannels() {
}
public void onConfigurationFinished(ServerConfigurationPacketListener serverConfigurationPacketListener) {
- final NetworkPayloadSetup setup = serverConfigurationPacketListener.getConnection().channel().attr(ATTRIBUTE_PAYLOAD_SETUP).get();
+ final NetworkPayloadSetup setup = serverConfigurationPacketListener.getConnection().channel.attr(ATTRIBUTE_PAYLOAD_SETUP).get();
if (setup == null) {
LOGGER.error("Somebody tried to finish the configuration phase of a connection that has not negotiated with the client. Not finishing configuration.");
return;
@@ -1067,7 +1066,7 @@ public void onConfigurationFinished(ServerConfigurationPacketListener serverConf
}
public void onConfigurationFinished(ClientConfigurationPacketListener listener) {
- final NetworkPayloadSetup setup = listener.getConnection().channel().attr(ATTRIBUTE_PAYLOAD_SETUP).get();
+ final NetworkPayloadSetup setup = listener.getConnection().channel.attr(ATTRIBUTE_PAYLOAD_SETUP).get();
if (setup == null) {
LOGGER.error("Somebody tried to finish the configuration phase of a connection that has not negotiated with the server. Not finishing configuration.");
return;
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IConnectionExtension.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IConnectionExtension.java
new file mode 100644
index 0000000..a5d889b
--- /dev/null
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IConnectionExtension.java
@@ -0,0 +1,7 @@
+package net.pillowmc.shearapi.network.injection;
+
+import io.netty.channel.Channel;
+
+public interface IConnectionExtension {
+ Channel channel();
+}
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IConnectionProtocolExtension.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IConnectionProtocolExtension.java
new file mode 100644
index 0000000..d497be3
--- /dev/null
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IConnectionProtocolExtension.java
@@ -0,0 +1,6 @@
+package net.pillowmc.shearapi.network.injection;
+
+public interface IConnectionProtocolExtension {
+ boolean isPlay();
+ boolean isConfiguration();
+}
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerCommonPacketListenerExtension.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerCommonPacketListenerExtension.java
index 900faf2..39ce141 100644
--- a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerCommonPacketListenerExtension.java
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerCommonPacketListenerExtension.java
@@ -25,19 +25,6 @@
*
*/
public interface IServerCommonPacketListenerExtension {
- /**
- * {@return the {@link ServerCommonPacketListener} that the extensions is attached to}
- */
- private ServerCommonPacketListener self() {
- return (ServerCommonPacketListener) this;
- }
-
- /**
- * Sends a packet to the client which this listener is attached to.
- *
- * @param packet The packet to send
- */
- void send(Packet> packet);
/**
* Sends a custom payload to the client which this listener is attached to.
@@ -45,17 +32,9 @@ private ServerCommonPacketListener self() {
* @param packetPayload The payload to send
*/
default void send(CustomPacketPayload packetPayload) {
- this.send(new ClientboundCustomPayloadPacket(packetPayload));
+ throw new AssertionError("This should be implemented by mixin!");
}
- /**
- * Sends a packet to the client which this listener is attached to.
- *
- * @param packet The packet to send
- * @param packetSendListener The listener to call when the packet is sent
- */
- void send(Packet> packet, @Nullable PacketSendListener packetSendListener);
-
/**
* Sends a custom payload to the client which this listener is attached to.
*
@@ -63,16 +42,9 @@ default void send(CustomPacketPayload packetPayload) {
* @param listener The listener to call when the packet is sent
*/
default void send(CustomPacketPayload packetPayload, @Nullable PacketSendListener listener) {
- this.send(new ClientboundCustomPayloadPacket(packetPayload), listener);
+ throw new AssertionError("This should be implemented by mixin!");
}
- /**
- * Triggers a disconnection with the given reason.
- *
- * @param reason The reason for the disconnection
- */
- void disconnect(Component reason);
-
/**
* {@return the connection this listener is attached to}
*/
@@ -85,12 +57,12 @@ default void send(CustomPacketPayload packetPayload, @Nullable PacketSendListene
/**
* {@return true if the connection is to a vanilla client}
- *
+ *
* @deprecated Use {@link #getConnectionType()} instead
*/
@Deprecated(forRemoval = true)
default boolean isVanillaConnection() {
- return getConnectionType().isVanilla();
+ throw new AssertionError("This should be implemented by mixin!");
}
/**
@@ -99,16 +71,16 @@ default boolean isVanillaConnection() {
* @param payloadId The payload id to check
*/
default boolean isConnected(final ResourceLocation payloadId) {
- return NetworkRegistry.getInstance().isConnected(self(), payloadId);
+ throw new AssertionError("This should be implemented by mixin!");
}
/**
* {@return true if the custom payload is usable by this connection}
- *
+ *
* @param payload The payload to check
*/
default boolean isConnected(final CustomPacketPayload payload) {
- return isConnected(payload.id());
+ throw new AssertionError("This should be implemented by mixin!");
}
/**
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ConnectionMixin.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ConnectionMixin.java
new file mode 100644
index 0000000..92a64da
--- /dev/null
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ConnectionMixin.java
@@ -0,0 +1,18 @@
+package net.pillowmc.shearapi.network.mixin;
+
+import io.netty.channel.Channel;
+import net.minecraft.network.Connection;
+import net.pillowmc.shearapi.network.injection.IConnectionExtension;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+@Mixin(Connection.class)
+public class ConnectionMixin implements IConnectionExtension {
+ @Shadow
+ public Channel channel;
+
+ @Override
+ public Channel channel() {
+ return this.channel;
+ }
+}
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ConnectionProtocolMixin.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ConnectionProtocolMixin.java
new file mode 100644
index 0000000..94bbea5
--- /dev/null
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ConnectionProtocolMixin.java
@@ -0,0 +1,21 @@
+package net.pillowmc.shearapi.network.mixin;
+
+import net.minecraft.network.ConnectionProtocol;
+import net.pillowmc.shearapi.network.injection.IConnectionProtocolExtension;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+@Mixin(ConnectionProtocol.class)
+public class ConnectionProtocolMixin implements IConnectionProtocolExtension {
+
+ @Override
+ public boolean isPlay() {
+ return (Object) this == ConnectionProtocol.PLAY;
+ }
+
+ @Override
+ public boolean isConfiguration() {
+ return (Object) this == ConnectionProtocol.CONFIGURATION;
+ }
+}
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/FriendlyByteBufMixin.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/FriendlyByteBufMixin.java
new file mode 100644
index 0000000..8b16328
--- /dev/null
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/FriendlyByteBufMixin.java
@@ -0,0 +1,9 @@
+package net.pillowmc.shearapi.network.mixin;
+
+import net.minecraft.network.FriendlyByteBuf;
+import net.pillowmc.shearapi.network.injection.IFriendlyByteBufExtension;
+import org.spongepowered.asm.mixin.Mixin;
+
+@Mixin(FriendlyByteBuf.class)
+public class FriendlyByteBufMixin implements IFriendlyByteBufExtension {
+}
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerCommonPacketListenerImplMixin.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerCommonPacketListenerImplMixin.java
index ed098f0..0fb0245 100644
--- a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerCommonPacketListenerImplMixin.java
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerCommonPacketListenerImplMixin.java
@@ -1,10 +1,76 @@
package net.pillowmc.shearapi.network.mixin;
+import net.minecraft.network.Connection;
+import net.minecraft.network.PacketSendListener;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.protocol.Packet;
+import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
+import net.minecraft.network.protocol.common.ServerCommonPacketListener;
+import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerCommonPacketListenerImpl;
+import net.minecraft.util.thread.ReentrantBlockableEventLoop;
+import net.neoforged.neoforge.network.connection.ConnectionType;
+import net.neoforged.neoforge.network.registration.NetworkRegistry;
import net.pillowmc.shearapi.network.injection.IServerCommonPacketListenerExtension;
+import org.jetbrains.annotations.Nullable;
+import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
@Mixin(ServerCommonPacketListenerImpl.class)
public abstract class ServerCommonPacketListenerImplMixin implements IServerCommonPacketListenerExtension {
+ @Override
+ public Connection getConnection() {
+ return connection;
+ }
+
+ @Shadow
+ @Final
+ protected Connection connection;
+
+ @Shadow
+ @Final
+ protected MinecraftServer server;
+
+ @Shadow
+ public abstract void send(Packet> packet);
+
+ @Shadow
+ public abstract void send(Packet> packet, @Nullable PacketSendListener packetSendListener);
+
+ @Override
+ public ReentrantBlockableEventLoop> getMainThreadEventLoop() {
+ return server;
+ }
+
+ @Override
+ public abstract ConnectionType getConnectionType();
+
+ @Override
+ public void send(CustomPacketPayload packetPayload) {
+ this.send(new ClientboundCustomPayloadPacket(packetPayload));
+ }
+
+ @Override
+ public void send(CustomPacketPayload packetPayload, @Nullable PacketSendListener listener) {
+ this.send(new ClientboundCustomPayloadPacket(packetPayload), listener);
+ }
+
+ @Override
+ public boolean isVanillaConnection() {
+ return getConnectionType().isVanilla();
+ }
+
+ @Override
+ public boolean isConnected(ResourceLocation payloadId) {
+ return NetworkRegistry.getInstance().isConnected((ServerCommonPacketListener) (Object)this, payloadId);
+ }
+
+ @Override
+ public boolean isConnected(CustomPacketPayload payload) {
+ return this.isConnected(payload.id());
+ }
}
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerConfigurationPacketListenerImplMixin.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerConfigurationPacketListenerImplMixin.java
new file mode 100644
index 0000000..5cbc6a7
--- /dev/null
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerConfigurationPacketListenerImplMixin.java
@@ -0,0 +1,35 @@
+package net.pillowmc.shearapi.network.mixin;
+
+import net.minecraft.network.Connection;
+import net.minecraft.network.protocol.configuration.ServerConfigurationPacketListener;
+import net.minecraft.server.network.ConfigurationTask;
+import net.minecraft.server.network.ServerConfigurationPacketListenerImpl;
+import net.minecraft.util.thread.ReentrantBlockableEventLoop;
+import net.neoforged.neoforge.network.connection.ConnectionType;
+import net.pillowmc.shearapi.network.injection.IServerConfigurationPacketListenerExtension;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+import org.spongepowered.asm.mixin.gen.Invoker;
+
+@Mixin(ServerConfigurationPacketListenerImpl.class)
+public abstract class ServerConfigurationPacketListenerImplMixin implements IServerConfigurationPacketListenerExtension {
+
+ @Override
+ @Shadow
+ public abstract void finishCurrentTask(ConfigurationTask.Type task);
+
+ @Override
+ public Connection getConnection() {
+ return null;
+ }
+
+ @Override
+ public ReentrantBlockableEventLoop> getMainThreadEventLoop() {
+ return null;
+ }
+
+ @Override
+ public ConnectionType getConnectionType() {
+ return null;
+ }
+}
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerConfigurationPacketListenerMixin.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerConfigurationPacketListenerMixin.java
new file mode 100644
index 0000000..9e3b4f7
--- /dev/null
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerConfigurationPacketListenerMixin.java
@@ -0,0 +1,10 @@
+package net.pillowmc.shearapi.network.mixin;
+
+import net.minecraft.network.protocol.configuration.ServerConfigurationPacketListener;
+import net.pillowmc.shearapi.network.injection.IServerConfigurationPacketListenerExtension;
+import org.spongepowered.asm.mixin.Mixin;
+
+@Mixin(ServerConfigurationPacketListener.class)
+public interface ServerConfigurationPacketListenerMixin extends IServerConfigurationPacketListenerExtension {
+
+}
diff --git a/shearapi-network/src/main/resources/fabric.mod.json b/shearapi-network/src/main/resources/fabric.mod.json
index d4e7913..a13d489 100644
--- a/shearapi-network/src/main/resources/fabric.mod.json
+++ b/shearapi-network/src/main/resources/fabric.mod.json
@@ -22,6 +22,7 @@
"shearapi-utils": "~${version}",
"shearapi-runtime": "~${version}"
},
+ "accessWidener": "shearapi-network.accesswidener",
"entrypoints": {
"client": ["net.pillowmc.shearapi.network.client.ShearAPINetworkClient"],
"shearapi-runtime:mod_bus_subscriber": ["net.neoforged.neoforge.network.ConfigurationInitialization::clazz"]
diff --git a/shearapi-network/src/main/resources/shearapi-network.accesswidener b/shearapi-network/src/main/resources/shearapi-network.accesswidener
new file mode 100644
index 0000000..c83c15d
--- /dev/null
+++ b/shearapi-network/src/main/resources/shearapi-network.accesswidener
@@ -0,0 +1,3 @@
+accessWidener v1 named
+accessible field net/minecraft/network/Connection channel Lio/netty/channel/Channel;
+#accessible method net/minecraft/network/ServerConfigurationPacketListenerImpl finishCurrentTask (Lnet/minecraft/server/network/ConfigurationTask$Type;)V
diff --git a/shearapi-network/src/main/resources/shearapi-network.mixins.json b/shearapi-network/src/main/resources/shearapi-network.mixins.json
index dcd8685..d96013a 100644
--- a/shearapi-network/src/main/resources/shearapi-network.mixins.json
+++ b/shearapi-network/src/main/resources/shearapi-network.mixins.json
@@ -3,7 +3,12 @@
"package": "net.pillowmc.shearapi.network.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
- "ServerCommonPacketListenerMixin"
+ "ConnectionMixin",
+ "ConnectionProtocolMixin",
+ "FriendlyByteBufMixin",
+ "ServerCommonPacketListenerImplMixin",
+ "ServerCommonPacketListenerMixin",
+ "ServerConfigurationPacketListenerMixin"
],
"injectors": {
"defaultRequire": 1
From 20362cd82257182ece66ebdb1378a7cd80ae838c Mon Sep 17 00:00:00 2001
From: Hei Piao
Date: Sat, 22 Mar 2025 08:59:01 +0800
Subject: [PATCH 2/5] Port a little more for shearapi-network...
---
...rConfigurationPacketListenerExtension.java | 6 +++
.../ServerCommonPacketListenerImplMixin.java | 48 +++++++++++++++++++
...rConfigurationPacketListenerImplMixin.java | 44 ++++++++++++++---
.../resources/shearapi-network.accesswidener | 2 +-
4 files changed, 93 insertions(+), 7 deletions(-)
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerConfigurationPacketListenerExtension.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerConfigurationPacketListenerExtension.java
index c9ad80b..6340c4f 100644
--- a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerConfigurationPacketListenerExtension.java
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerConfigurationPacketListenerExtension.java
@@ -5,9 +5,11 @@
package net.pillowmc.shearapi.network.injection;
+import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket;
import net.minecraft.network.protocol.configuration.ServerConfigurationPacketListener;
import net.minecraft.server.network.ConfigurationTask;
import net.minecraft.server.network.ServerConfigurationPacketListenerImpl;
+import net.neoforged.neoforge.network.connection.ConnectionType;
/**
* Extension class for {@link ServerConfigurationPacketListener}
@@ -20,4 +22,8 @@ public interface IServerConfigurationPacketListenerExtension extends IServerComm
* @implNote This forces the normally private method implementation in {@link ServerConfigurationPacketListenerImpl#finishCurrentTask(ConfigurationTask.Type)} to become public, and adds this to the signature of {@link ServerConfigurationPacketListener}
*/
void finishCurrentTask(ConfigurationTask.Type task);
+
+ void shearapi$setConnectionType(ConnectionType type);
+ boolean shearapi$isHandlingModdedConfigurationPhase();
+ void shearapi$setHandlingModdedConfigurationPhase();
}
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerCommonPacketListenerImplMixin.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerCommonPacketListenerImplMixin.java
index 0fb0245..7761265 100644
--- a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerCommonPacketListenerImplMixin.java
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerCommonPacketListenerImplMixin.java
@@ -6,18 +6,26 @@
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
import net.minecraft.network.protocol.common.ServerCommonPacketListener;
+import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerCommonPacketListenerImpl;
+import net.minecraft.server.network.ServerConfigurationPacketListenerImpl;
import net.minecraft.util.thread.ReentrantBlockableEventLoop;
import net.neoforged.neoforge.network.connection.ConnectionType;
+import net.neoforged.neoforge.network.payload.MinecraftRegisterPayload;
+import net.neoforged.neoforge.network.payload.MinecraftUnregisterPayload;
+import net.neoforged.neoforge.network.payload.ModdedNetworkQueryPayload;
import net.neoforged.neoforge.network.registration.NetworkRegistry;
import net.pillowmc.shearapi.network.injection.IServerCommonPacketListenerExtension;
import org.jetbrains.annotations.Nullable;
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;
@Mixin(ServerCommonPacketListenerImpl.class)
public abstract class ServerCommonPacketListenerImplMixin implements IServerCommonPacketListenerExtension {
@@ -73,4 +81,44 @@ public boolean isConnected(ResourceLocation payloadId) {
public boolean isConnected(CustomPacketPayload payload) {
return this.isConnected(payload.id());
}
+
+ // This should be in ServerConfigurationPacketListenerImplMixin...
+ @Inject(method = "handleCustomPayload", at = @At("HEAD"), cancellable = true)
+ private void handleCustomPayloadHead(ServerboundCustomPayloadPacket packet, CallbackInfo ci) {
+ if (!((Object)this instanceof ServerConfigurationPacketListenerImpl self)) return;
+ if (packet.payload() instanceof MinecraftRegisterPayload payload) {
+ self.shearapi$setConnectionType(self.getConnectionType().withMinecraftRegisterPayload());
+ NetworkRegistry.getInstance().onMinecraftRegister(self, payload.newChannels());
+ return;
+ }
+
+ if (packet.payload() instanceof MinecraftUnregisterPayload payload) {
+ self.shearapi$setConnectionType(self.getConnectionType().withMinecraftRegisterPayload());
+ NetworkRegistry.getInstance().onMinecraftUnregister(self, payload.forgottenChannels());
+ return;
+ }
+
+ if (packet.payload() instanceof ModdedNetworkQueryPayload payload) {
+ self.shearapi$setConnectionType(self.getConnectionType().withNeoForgeQueryPayload());
+ NetworkRegistry.getInstance().onModdedConnectionDetectedAtServer(
+ self,
+ payload.configuration(),
+ payload.play()
+ );
+ return;
+ }
+
+ if (self.shearapi$isHandlingModdedConfigurationPhase()) {
+ NetworkRegistry.getInstance().onModdedPacketAtServer(self, packet);
+ ci.cancel();
+ }
+
+ }
+
+ @Inject(method = "handleCustomPayload", at = @At("TAIL"))
+ private void handleCustomPayloadTail(ServerboundCustomPayloadPacket packet, CallbackInfo ci) {
+ if ((Object)this instanceof ServerConfigurationPacketListenerImpl self) {
+ NetworkRegistry.getInstance().onModdedPacketAtServer(self, packet);
+ }
+ }
}
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerConfigurationPacketListenerImplMixin.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerConfigurationPacketListenerImplMixin.java
index 5cbc6a7..82a2a3f 100644
--- a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerConfigurationPacketListenerImplMixin.java
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerConfigurationPacketListenerImplMixin.java
@@ -1,35 +1,67 @@
package net.pillowmc.shearapi.network.mixin;
import net.minecraft.network.Connection;
+import net.minecraft.network.protocol.Packet;
+import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket;
import net.minecraft.network.protocol.configuration.ServerConfigurationPacketListener;
+import net.minecraft.network.protocol.configuration.ServerboundFinishConfigurationPacket;
import net.minecraft.server.network.ConfigurationTask;
import net.minecraft.server.network.ServerConfigurationPacketListenerImpl;
import net.minecraft.util.thread.ReentrantBlockableEventLoop;
import net.neoforged.neoforge.network.connection.ConnectionType;
+import net.neoforged.neoforge.network.payload.MinecraftRegisterPayload;
+import net.neoforged.neoforge.network.payload.MinecraftUnregisterPayload;
+import net.neoforged.neoforge.network.payload.ModdedNetworkQueryPayload;
+import net.neoforged.neoforge.network.registration.NetworkRegistry;
import net.pillowmc.shearapi.network.injection.IServerConfigurationPacketListenerExtension;
import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.gen.Invoker;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+import java.util.Set;
@Mixin(ServerConfigurationPacketListenerImpl.class)
public abstract class ServerConfigurationPacketListenerImplMixin implements IServerConfigurationPacketListenerExtension {
+ private ConnectionType connectionType = ConnectionType.VANILLA;
+ private boolean isHandlingModdedConfigurationPhase = false;
@Override
@Shadow
public abstract void finishCurrentTask(ConfigurationTask.Type task);
@Override
- public Connection getConnection() {
- return null;
+ public ConnectionType getConnectionType() {
+ return connectionType;
}
@Override
- public ReentrantBlockableEventLoop> getMainThreadEventLoop() {
- return null;
+ public void shearapi$setConnectionType(ConnectionType connectionType) {
+ this.connectionType = connectionType;
}
@Override
- public ConnectionType getConnectionType() {
- return null;
+ public boolean shearapi$isHandlingModdedConfigurationPhase() {
+ return isHandlingModdedConfigurationPhase;
+ }
+
+ @Override
+ public void shearapi$setHandlingModdedConfigurationPhase() {
+ isHandlingModdedConfigurationPhase = true;
+ }
+
+ @Inject(method = "handleConfigurationFinished", at = @At("HEAD"))
+ private void handleConfigurationFinished(ServerboundFinishConfigurationPacket serverboundFinishConfigurationPacket, CallbackInfo ci) {
+ if (this.connectionType == ConnectionType.OTHER) {
+ NetworkRegistry.getInstance().onModdedConnectionDetectedAtServer(
+ (ServerConfigurationPacketListener) this,
+ Set.of(),
+ Set.of()
+ );
+ }
+ NetworkRegistry.getInstance().onConfigurationFinished((ServerConfigurationPacketListener) this);
}
}
diff --git a/shearapi-network/src/main/resources/shearapi-network.accesswidener b/shearapi-network/src/main/resources/shearapi-network.accesswidener
index c83c15d..6983b0c 100644
--- a/shearapi-network/src/main/resources/shearapi-network.accesswidener
+++ b/shearapi-network/src/main/resources/shearapi-network.accesswidener
@@ -1,3 +1,3 @@
accessWidener v1 named
accessible field net/minecraft/network/Connection channel Lio/netty/channel/Channel;
-#accessible method net/minecraft/network/ServerConfigurationPacketListenerImpl finishCurrentTask (Lnet/minecraft/server/network/ConfigurationTask$Type;)V
+accessible method net/minecraft/server/network/ServerConfigurationPacketListenerImpl finishCurrentTask (Lnet/minecraft/server/network/ConfigurationTask$Type;)V
From 3f7c017075b0361bc0e6d9a6af14924a203d5660 Mon Sep 17 00:00:00 2001
From: Hei Piao
Date: Wed, 26 Mar 2025 22:55:42 +0800
Subject: [PATCH 3/5] wip: port a little more for shearapi-network
---
.../network/registration/NetworkRegistry.java | 29 ++++++++----
.../IServerCommonPacketListenerExtension.java | 46 ++++++++++++++++---
.../ServerCommonPacketListenerImplMixin.java | 33 +++----------
.../src/main/resources/fabric.mod.json | 3 +-
.../resources/shearapi-network.accesswidener | 2 +
5 files changed, 72 insertions(+), 41 deletions(-)
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/registration/NetworkRegistry.java b/shearapi-network/src/main/java/net/neoforged/neoforge/network/registration/NetworkRegistry.java
index c197c09..1eb98e8 100644
--- a/shearapi-network/src/main/java/net/neoforged/neoforge/network/registration/NetworkRegistry.java
+++ b/shearapi-network/src/main/java/net/neoforged/neoforge/network/registration/NetworkRegistry.java
@@ -64,6 +64,7 @@
import net.neoforged.neoforge.network.payload.ModdedNetworkQueryComponent;
import net.neoforged.neoforge.network.payload.ModdedNetworkQueryPayload;
import net.neoforged.neoforge.network.payload.ModdedNetworkSetupFailedPayload;
+import net.pillowmc.shearapi.runtime.ShearAPIVersion;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
@@ -287,7 +288,7 @@ public void onModdedPacketAtServer(ServerCommonPacketListener listener, Serverbo
//Check if this client was even setup properly.
if (payloadSetup == null) {
LOGGER.warn("Received a modded custom payload packet from a client that has not negotiated with the server. Disconnecting client.");
- listener.disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s".formatted(NeoForgeVersion.getVersion())));
+ listener.disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s".formatted(ShearAPIVersion.getVersion())));
return;
}
@@ -298,7 +299,7 @@ public void onModdedPacketAtServer(ServerCommonPacketListener listener, Serverbo
//Check if the channel should even be processed.
if (channel == null && !isAdhocConfigurationChannelReadable(packet.payload().id(), PacketFlow.SERVERBOUND)) {
LOGGER.warn("Received a modded custom payload packet from a client with an unknown or not accepted channel. Disconnecting client.");
- listener.disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s".formatted(NeoForgeVersion.getVersion())));
+ listener.disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s".formatted(ShearAPIVersion.getVersion())));
return;
}
@@ -327,7 +328,7 @@ public void onModdedPacketAtServer(ServerCommonPacketListener listener, Serverbo
//Check if the channel should even be processed.
if (channel == null && !isAdhocPlayChannelReadable(packet.payload().id(), PacketFlow.SERVERBOUND)) {
LOGGER.warn("Received a modded custom payload packet from a client with an unknown or not accepted channel. Disconnecting client.");
- listener.disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s".formatted(NeoForgeVersion.getVersion())));
+ listener.disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s".formatted(ShearAPIVersion.getVersion())));
return;
}
@@ -366,6 +367,7 @@ public void onModdedPacketAtServer(ServerCommonPacketListener listener, Serverbo
* @param listener The listener which received the packet.
* @param packet The packet that was received.
*/
+ // TODO: (ShearAPI) move to client
public boolean onModdedPacketAtClient(ClientCommonPacketListener listener, ClientboundCustomPayloadPacket packet) {
if (packet.payload().id().getNamespace().equals("minecraft")) {
return false;
@@ -415,7 +417,7 @@ public boolean onModdedPacketAtClient(ClientCommonPacketListener listener, Clien
//Check if the channel should even be processed.
if (channel == null && !isAdhocPlayChannelReadable(packet.payload().id(), PacketFlow.CLIENTBOUND)) {
LOGGER.warn("Received a modded custom payload packet from a server with an unknown or not accepted channel. Disconnecting server.");
- listener.getConnection().disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s".formatted(NeoForgeVersion.getVersion())));
+ listener.getConnection().disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s".formatted(ShearAPIVersion.getVersion())));
return false;
}
@@ -478,7 +480,7 @@ public void onModdedConnectionDetectedAtServer(ServerConfigurationPacketListener
sender.send(new ModdedNetworkSetupFailedPayload(configurationNegotiationResult.failureReasons()));
}
- sender.disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s".formatted(NeoForgeVersion.getVersion())));
+ sender.disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s".formatted(ShearAPIVersion.getVersion())));
return;
}
@@ -496,7 +498,7 @@ public void onModdedConnectionDetectedAtServer(ServerConfigurationPacketListener
sender.send(new ModdedNetworkSetupFailedPayload(playNegotiationResult.failureReasons()));
}
- sender.disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s".formatted(NeoForgeVersion.getVersion())));
+ sender.disconnect(Component.translatable("multiplayer.disconnect.incompatible", "NeoForge %s".formatted(ShearAPIVersion.getVersion())));
}
final NetworkPayloadSetup setup = NetworkPayloadSetup.from(
@@ -542,7 +544,7 @@ public boolean onVanillaOrOtherConnectionDetectedAtServer(ServerConfigurationPac
//Negotiation failed. Disconnect the client.
if (!configurationNegotiationResult.success()) {
- sender.disconnect(Component.translatableWithFallback("neoforge.network.negotiation.failure.vanilla.client.not_supported", "You are trying to connect to a server that is running NeoForge, but you are not. Please install NeoForge Version: %s to connect to this server.", NeoForgeVersion.getVersion()));
+ sender.disconnect(Component.translatableWithFallback("neoforge.network.negotiation.failure.vanilla.client.not_supported", "You are trying to connect to a server that is running NeoForge, but you are not. Please install NeoForge Version: %s to connect to this server.", ShearAPIVersion.getVersion()));
return false;
}
@@ -554,7 +556,7 @@ public boolean onVanillaOrOtherConnectionDetectedAtServer(ServerConfigurationPac
//Negotiation failed. Disconnect the client.
if (!playNegotiationResult.success()) {
- sender.disconnect(Component.translatableWithFallback("neoforge.network.negotiation.failure.vanilla.client.not_supported", "You are trying to connect to a server that is running NeoForge, but you are not. Please install NeoForge Version: %s to connect to this server.", NeoForgeVersion.getVersion()));
+ sender.disconnect(Component.translatableWithFallback("neoforge.network.negotiation.failure.vanilla.client.not_supported", "You are trying to connect to a server that is running NeoForge, but you are not. Please install NeoForge Version: %s to connect to this server.", ShearAPIVersion.getVersion()));
return false;
}
@@ -643,6 +645,7 @@ public boolean shouldSendPacketRaw(Packet> packet) {
* @param listener The listener that wants to send the packet.
* @return True if the packet can be sent, false otherwise.
*/
+ // TODO: (ShearAPI) move to client
public boolean canSendPacket(Packet> packet, ClientCommonPacketListener listener) {
if (!(packet instanceof ServerboundCustomPayloadPacket customPayloadPacket)) {
return true;
@@ -732,6 +735,7 @@ private boolean isAdhocPlayChannelReadable(ResourceLocation id, PacketFlow flow)
*
* @param listener The listener which received the query.
*/
+ // TODO: (ShearAPI) move to client
public void onNetworkQuery(ClientConfigurationPacketListener listener) {
final ModdedNetworkQueryPayload payload = new ModdedNetworkQueryPayload(
knownConfigurationRegistrations.entrySet().stream()
@@ -754,6 +758,7 @@ public void onNetworkQuery(ClientConfigurationPacketListener listener) {
* @param configuration The configuration channels that were negotiated.
* @param play The play channels that were negotiated.
*/
+ // TODO: (ShearAPI) move to client
public void onModdedNetworkConnectionEstablished(ClientConfigurationPacketListener listener, Set configuration, Set play) {
final NetworkPayloadSetup setup = NetworkPayloadSetup.from(
configuration.stream()
@@ -787,6 +792,7 @@ public void onModdedNetworkConnectionEstablished(ClientConfigurationPacketListen
* @param sender The listener which received the brand payload.
* @return True if the vanilla connection should be handled by the client, false otherwise.
*/
+ // TODO: (ShearAPI) move to client
public boolean onVanillaNetworkConnectionEstablished(ClientConfigurationPacketListener sender) {
NetworkFilters.cleanIfNecessary(sender.getConnection());
@@ -853,6 +859,7 @@ public boolean isConnected(ServerCommonPacketListener listener, ResourceLocation
* @param payloadId The payload id to check.
* @return True if the listener has a connection setup that can transmit the given payload id, false otherwise.
*/
+ // TODO: (ShearAPI) move to client
public boolean isConnected(ClientCommonPacketListener listener, ResourceLocation payloadId) {
return isConnected(listener.getConnection(), ConnectionPhase.fromPacketListener(listener), payloadId);
}
@@ -955,6 +962,7 @@ public void configureMockConnection(final Connection connection) {
* @param listener The listener which received the payload.
* @param resourceLocations The resource locations that were registered.
*/
+ // TODO: (ShearAPI) move to client
public void onMinecraftRegister(ClientCommonPacketListener listener, Set resourceLocations) {
onMinecraftRegister(resourceLocations, listener.getConnection());
}
@@ -985,6 +993,7 @@ private void onMinecraftRegister(Set resourceLocations, Connec
* @param listener The listener which received the payload.
* @param resourceLocations The resource locations that were unregistered.
*/
+ // TODO: (ShearAPI) move to client
public void onMinecraftUnregister(ClientCommonPacketListener listener, Set resourceLocations) {
onMinecraftUnregister(resourceLocations, listener.getConnection());
}
@@ -1030,6 +1039,7 @@ public Set getInitialServerUnregisterChannels() {
return nowForgottenChannels.build();
}
+ // TODO: (ShearAPI) move to client
private static Set getInitialClientListeningChannels() {
return Set.of(
MinecraftRegisterPayload.ID,
@@ -1065,6 +1075,7 @@ public void onConfigurationFinished(ServerConfigurationPacketListener serverConf
serverConfigurationPacketListener.send(new MinecraftRegisterPayload(nowListeningOn.build()));
}
+ // TODO: (ShearAPI) move to client
public void onConfigurationFinished(ClientConfigurationPacketListener listener) {
final NetworkPayloadSetup setup = listener.getConnection().channel.attr(ATTRIBUTE_PAYLOAD_SETUP).get();
if (setup == null) {
@@ -1156,6 +1167,7 @@ private static void resolvePacketGenerics(Packet p
}
}
+ // TODO: (ShearAPI) move to client
@SuppressWarnings("unchecked")
private record ClientPacketHandler(ClientCommonPacketListener listener) implements IPacketHandler {
@Override
@@ -1194,6 +1206,7 @@ public void disconnect(Component reason) {
}
}
+ // TODO: (ShearAPI) move to client
private record ClientReplyHandler(ClientCommonPacketListener listener) implements IReplyHandler {
@Override
public void send(CustomPacketPayload payload) {
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerCommonPacketListenerExtension.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerCommonPacketListenerExtension.java
index 39ce141..0c3f772 100644
--- a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerCommonPacketListenerExtension.java
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerCommonPacketListenerExtension.java
@@ -26,12 +26,31 @@
*/
public interface IServerCommonPacketListenerExtension {
+ /**
+ * Sends a packet to the client which this listener is attached to.
+ *
+ * @param packet The packet to send
+ */
+ default void send(Packet> packet) {
+ throw new AssertionError("This should be implemented by mixin!");
+ }
+
/**
* Sends a custom payload to the client which this listener is attached to.
*
* @param packetPayload The payload to send
*/
default void send(CustomPacketPayload packetPayload) {
+ this.send(new ClientboundCustomPayloadPacket(packetPayload));
+ }
+
+ /**
+ * Sends a packet to the client which this listener is attached to.
+ *
+ * @param packet The packet to send
+ * @param packetSendListener The listener to call when the packet is sent
+ */
+ default void send(Packet> packet, @Nullable PacketSendListener packetSendListener) {
throw new AssertionError("This should be implemented by mixin!");
}
@@ -42,18 +61,31 @@ default void send(CustomPacketPayload packetPayload) {
* @param listener The listener to call when the packet is sent
*/
default void send(CustomPacketPayload packetPayload, @Nullable PacketSendListener listener) {
+ this.send(new ClientboundCustomPayloadPacket(packetPayload), listener);
+ }
+
+ /**
+ * Triggers a disconnection with the given reason.
+ *
+ * @param reason The reason for the disconnection
+ */
+ default void disconnect(Component reason) {
throw new AssertionError("This should be implemented by mixin!");
}
/**
* {@return the connection this listener is attached to}
*/
- Connection getConnection();
+ default Connection getConnection() {
+ throw new AssertionError("This should be implemented by mixin!");
+ }
/**
* {@return the main thread event loop}
*/
- ReentrantBlockableEventLoop> getMainThreadEventLoop();
+ default ReentrantBlockableEventLoop> getMainThreadEventLoop() {
+ throw new AssertionError("This should be implemented by mixin!");
+ }
/**
* {@return true if the connection is to a vanilla client}
@@ -62,7 +94,7 @@ default void send(CustomPacketPayload packetPayload, @Nullable PacketSendListene
*/
@Deprecated(forRemoval = true)
default boolean isVanillaConnection() {
- throw new AssertionError("This should be implemented by mixin!");
+ return getConnectionType().isVanilla();
}
/**
@@ -71,7 +103,7 @@ default boolean isVanillaConnection() {
* @param payloadId The payload id to check
*/
default boolean isConnected(final ResourceLocation payloadId) {
- throw new AssertionError("This should be implemented by mixin!");
+ return NetworkRegistry.getInstance().isConnected((ServerCommonPacketListener) this, payloadId);
}
/**
@@ -80,11 +112,13 @@ default boolean isConnected(final ResourceLocation payloadId) {
* @param payload The payload to check
*/
default boolean isConnected(final CustomPacketPayload payload) {
- throw new AssertionError("This should be implemented by mixin!");
+ return isConnected(payload.id());
}
/**
* {@return the connection type of the connection}
*/
- ConnectionType getConnectionType();
+ default ConnectionType getConnectionType() {
+ throw new AssertionError("This should be implemented by mixin!");
+ }
}
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerCommonPacketListenerImplMixin.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerCommonPacketListenerImplMixin.java
index 7761265..edff5b1 100644
--- a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerCommonPacketListenerImplMixin.java
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/mixin/ServerCommonPacketListenerImplMixin.java
@@ -44,9 +44,11 @@ public Connection getConnection() {
protected MinecraftServer server;
@Shadow
+ @Override
public abstract void send(Packet> packet);
@Shadow
+ @Override
public abstract void send(Packet> packet, @Nullable PacketSendListener packetSendListener);
@Override
@@ -54,32 +56,11 @@ public ReentrantBlockableEventLoop> getMainThreadEventLoop() {
return server;
}
- @Override
- public abstract ConnectionType getConnectionType();
-
- @Override
- public void send(CustomPacketPayload packetPayload) {
- this.send(new ClientboundCustomPayloadPacket(packetPayload));
- }
-
- @Override
- public void send(CustomPacketPayload packetPayload, @Nullable PacketSendListener listener) {
- this.send(new ClientboundCustomPayloadPacket(packetPayload), listener);
- }
-
- @Override
- public boolean isVanillaConnection() {
- return getConnectionType().isVanilla();
- }
-
- @Override
- public boolean isConnected(ResourceLocation payloadId) {
- return NetworkRegistry.getInstance().isConnected((ServerCommonPacketListener) (Object)this, payloadId);
- }
-
- @Override
- public boolean isConnected(CustomPacketPayload payload) {
- return this.isConnected(payload.id());
+ @Inject(method = "send(Lnet/minecraft/network/protocol/Packet;Lnet/minecraft/network/PacketSendListener;)V", at = @At("HEAD"), cancellable = true)
+ private void injectSend(Packet> packet, PacketSendListener packetSendListener, CallbackInfo ci) {
+ if (!NetworkRegistry.getInstance().canSendPacket(packet, (ServerCommonPacketListener) this)) {
+ ci.cancel();
+ }
}
// This should be in ServerConfigurationPacketListenerImplMixin...
diff --git a/shearapi-network/src/main/resources/fabric.mod.json b/shearapi-network/src/main/resources/fabric.mod.json
index a13d489..446dd9e 100644
--- a/shearapi-network/src/main/resources/fabric.mod.json
+++ b/shearapi-network/src/main/resources/fabric.mod.json
@@ -33,7 +33,8 @@
"net/minecraft/class_8706": ["net/pillowmc/shearapi/network/injection/IServerCommonPacketListenerExtension"],
"net/minecraft/class_8735": ["net/pillowmc/shearapi/network/injection/IServerConfigurationPacketListenerExtension"],
"net/minecraft/class_2792": ["net/pillowmc/shearapi/network/injection/IServerGamePacketListenerExtension"],
- "net/minecraft/class_2540": ["net/pillowmc/shearapi/network/injection/IFriendlyByteBufExtension"]
+ "net/minecraft/class_2540": ["net/pillowmc/shearapi/network/injection/IFriendlyByteBufExtension"],
+ "net/minecraft/class_2539": ["net/pillowmc/shearapi/network/injection/IConnectionProtocolExtension"]
},
"modmenu": {
"parent": "shearapi",
diff --git a/shearapi-network/src/main/resources/shearapi-network.accesswidener b/shearapi-network/src/main/resources/shearapi-network.accesswidener
index 6983b0c..e0b04e2 100644
--- a/shearapi-network/src/main/resources/shearapi-network.accesswidener
+++ b/shearapi-network/src/main/resources/shearapi-network.accesswidener
@@ -1,3 +1,5 @@
accessWidener v1 named
accessible field net/minecraft/network/Connection channel Lio/netty/channel/Channel;
accessible method net/minecraft/server/network/ServerConfigurationPacketListenerImpl finishCurrentTask (Lnet/minecraft/server/network/ConfigurationTask$Type;)V
+accessible field net/minecraft/network/protocol/common/ServerboundCustomPayloadPacket KNOWN_TYPES Ljava/util/Map;
+accessible field net/minecraft/network/protocol/common/ClientboundCustomPayloadPacket KNOWN_TYPES Ljava/util/Map;
From 873d23460ba7e8823b4cf8212f1875769249c7c0 Mon Sep 17 00:00:00 2001
From: Hei Piao
Date: Sat, 12 Apr 2025 13:36:26 +0800
Subject: [PATCH 4/5] feat: move classes that deals with network out of
shearapi-withpillow
---
settings.gradle | 1 +
shearapi-fmlstuff/build.gradle | 13 +++++++
.../client/ShearAPIFMLStuffClient.java | 18 ++++-----
.../neoforge/event/ModMismatchEvent.java | 0
.../neoforge/network/ConfigSync.java | 0
.../network/configuration/SyncConfig.java | 0
.../network/payload/ConfigFilePayload.java | 0
.../shearapi/fmlstuff/ShearAPIFMLStuff.java | 19 +++++++++
.../assets/shearapi-fmlstuff/icon.png | Bin 0 -> 13899 bytes
.../src/main/resources/fabric.mod.json | 36 ++++++++++++++++++
shearapi-withpillow/build.gradle | 1 -
.../withpillow/ShearAPIWithPillow.java | 12 ------
.../src/main/resources/fabric.mod.json | 4 --
13 files changed, 78 insertions(+), 26 deletions(-)
create mode 100644 shearapi-fmlstuff/build.gradle
rename shearapi-withpillow/src/client/java/net/pillowmc/shearapi/withpillow/client/ShearAPIWithPillowClient.java => shearapi-fmlstuff/src/client/java/net/pillowmc/shearapi/fmlstuff/client/ShearAPIFMLStuffClient.java (72%)
rename {shearapi-withpillow => shearapi-fmlstuff}/src/main/java/net/neoforged/neoforge/event/ModMismatchEvent.java (100%)
rename {shearapi-withpillow => shearapi-fmlstuff}/src/main/java/net/neoforged/neoforge/network/ConfigSync.java (100%)
rename {shearapi-withpillow => shearapi-fmlstuff}/src/main/java/net/neoforged/neoforge/network/configuration/SyncConfig.java (100%)
rename {shearapi-withpillow => shearapi-fmlstuff}/src/main/java/net/neoforged/neoforge/network/payload/ConfigFilePayload.java (100%)
create mode 100644 shearapi-fmlstuff/src/main/java/net/pillowmc/shearapi/fmlstuff/ShearAPIFMLStuff.java
create mode 100644 shearapi-fmlstuff/src/main/resources/assets/shearapi-fmlstuff/icon.png
create mode 100644 shearapi-fmlstuff/src/main/resources/fabric.mod.json
diff --git a/settings.gradle b/settings.gradle
index 9b7af0c..3f5a83b 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -29,3 +29,4 @@ include("shearapi-conditions")
include("shearapi-network")
include("shearapi-holderset")
include("shearapi-resource")
+include("shearapi-fmlstuff")
diff --git a/shearapi-fmlstuff/build.gradle b/shearapi-fmlstuff/build.gradle
new file mode 100644
index 0000000..4e967b5
--- /dev/null
+++ b/shearapi-fmlstuff/build.gradle
@@ -0,0 +1,13 @@
+repositories {
+ maven {
+ url "https://maven.neoforged.net/releases/"
+ name "NeoForged Releases"
+ }
+}
+
+dependencies {
+ implementation "net.neoforged.fancymodloader:loader:${project.fancy_mod_loader_version}"
+ api project(path: ":shearapi-runtime", configuration: "namedElements")
+ api project(path: ":shearapi-withpillow", configuration: "namedElements")
+ api project(path: ":shearapi-network", configuration: "namedElements")
+}
diff --git a/shearapi-withpillow/src/client/java/net/pillowmc/shearapi/withpillow/client/ShearAPIWithPillowClient.java b/shearapi-fmlstuff/src/client/java/net/pillowmc/shearapi/fmlstuff/client/ShearAPIFMLStuffClient.java
similarity index 72%
rename from shearapi-withpillow/src/client/java/net/pillowmc/shearapi/withpillow/client/ShearAPIWithPillowClient.java
rename to shearapi-fmlstuff/src/client/java/net/pillowmc/shearapi/fmlstuff/client/ShearAPIFMLStuffClient.java
index 1e58c0d..79b34d6 100644
--- a/shearapi-withpillow/src/client/java/net/pillowmc/shearapi/withpillow/client/ShearAPIWithPillowClient.java
+++ b/shearapi-fmlstuff/src/client/java/net/pillowmc/shearapi/fmlstuff/client/ShearAPIFMLStuffClient.java
@@ -1,4 +1,4 @@
-package net.pillowmc.shearapi.withpillow.client;
+package net.pillowmc.shearapi.fmlstuff.client;
import net.minecraft.client.Minecraft;
import net.neoforged.bus.api.SubscribeEvent;
@@ -13,21 +13,21 @@
import java.util.Optional;
-public class ShearAPIWithPillowClient {
- public static Class clazz = ShearAPIWithPillowClient.class;
+public class ShearAPIFMLStuffClient {
+ public static Class clazz = ShearAPIFMLStuffClient.class;
@SubscribeEvent
public static void onRegisterPayloadHandlerEvent(RegisterPayloadHandlerEvent event) {
if (!(ShearAPIRuntime.getRuntime() instanceof ShearAPIWithPillow)) {
return;
}
final IPayloadRegistrar registrar = event.registrar(ShearAPIRuntime.MOD_ID)
- .versioned(ShearAPIVersion.getSpec())
- .optional();
+ .versioned(ShearAPIVersion.getSpec())
+ .optional();
registrar
- .configuration(
- ConfigFilePayload.ID,
- ConfigFilePayload::new,
- handlers -> handlers.client(ShearAPIWithPillowClient::handleConfigFile));
+ .configuration(
+ ConfigFilePayload.ID,
+ ConfigFilePayload::new,
+ handlers -> handlers.client(ShearAPIFMLStuffClient::handleConfigFile));
}
private static void handleConfigFile(ConfigFilePayload payload, IPayloadContext context) {
diff --git a/shearapi-withpillow/src/main/java/net/neoforged/neoforge/event/ModMismatchEvent.java b/shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/event/ModMismatchEvent.java
similarity index 100%
rename from shearapi-withpillow/src/main/java/net/neoforged/neoforge/event/ModMismatchEvent.java
rename to shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/event/ModMismatchEvent.java
diff --git a/shearapi-withpillow/src/main/java/net/neoforged/neoforge/network/ConfigSync.java b/shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/ConfigSync.java
similarity index 100%
rename from shearapi-withpillow/src/main/java/net/neoforged/neoforge/network/ConfigSync.java
rename to shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/ConfigSync.java
diff --git a/shearapi-withpillow/src/main/java/net/neoforged/neoforge/network/configuration/SyncConfig.java b/shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/configuration/SyncConfig.java
similarity index 100%
rename from shearapi-withpillow/src/main/java/net/neoforged/neoforge/network/configuration/SyncConfig.java
rename to shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/configuration/SyncConfig.java
diff --git a/shearapi-withpillow/src/main/java/net/neoforged/neoforge/network/payload/ConfigFilePayload.java b/shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/payload/ConfigFilePayload.java
similarity index 100%
rename from shearapi-withpillow/src/main/java/net/neoforged/neoforge/network/payload/ConfigFilePayload.java
rename to shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/payload/ConfigFilePayload.java
diff --git a/shearapi-fmlstuff/src/main/java/net/pillowmc/shearapi/fmlstuff/ShearAPIFMLStuff.java b/shearapi-fmlstuff/src/main/java/net/pillowmc/shearapi/fmlstuff/ShearAPIFMLStuff.java
new file mode 100644
index 0000000..8346126
--- /dev/null
+++ b/shearapi-fmlstuff/src/main/java/net/pillowmc/shearapi/fmlstuff/ShearAPIFMLStuff.java
@@ -0,0 +1,19 @@
+package net.pillowmc.shearapi.fmlstuff;
+
+import net.neoforged.bus.api.SubscribeEvent;
+import net.neoforged.neoforge.network.configuration.SyncConfig;
+import net.neoforged.neoforge.network.event.OnGameConfigurationEvent;
+import net.neoforged.neoforge.network.payload.ConfigFilePayload;
+import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
+import net.pillowmc.shearapi.withpillow.ShearAPIWithPillow;
+
+public class ShearAPIFMLStuff {
+ public static Class clazz = ShearAPIFMLStuff.class;
+
+ @SubscribeEvent
+ public static void onGameConfigurationEvent(OnGameConfigurationEvent event) {
+ if (event.getListener().isConnected(ConfigFilePayload.ID) && ShearAPIRuntime.getRuntime() instanceof ShearAPIWithPillow) {
+ event.register(new SyncConfig(event.getListener()));
+ }
+ }
+}
diff --git a/shearapi-fmlstuff/src/main/resources/assets/shearapi-fmlstuff/icon.png b/shearapi-fmlstuff/src/main/resources/assets/shearapi-fmlstuff/icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..a1d73a6662ea8060ffad89e0f2235f4bd608d4e7
GIT binary patch
literal 13899
zcmeHuRZv}9u4JI#c1Qk}i)Yah(#h9`p-Ltwg@5RIjl7wz#k5Utj5L*&X@$ll$I
zf4lyH7%r;}DoN*0OWGQOE=x*D85nqz`nQrDcVwhB{>!I(v#}8`b0&?BM%V0C
z->0kHwZ{Dun<`C4Z2MRcLaZMOI;#@MoAvl(D)i?LSwF~u4?loE%n^WxT(=)Hpg#kT
zto;7>(f@kl|0O1dNMrRAV)ARZKg$Z6y`(zuVlY{8OHZdrSzr>yEXCCgj0XUbCCKCM
zq^l3fuW;T+(>^98JI5P>aVviiX8sg4H;<+@9|eL@;;!X58HC0@eIRyxeOM|+ErF5V
z%KXJb(I({$j@}o&Ld^jU#eeW1NB9v|N^N|7DNKJds&Vh_Z%G!1B@{!`5Cejl@IK+K
z2?Rdlnb^_C^=xc>?WKp0>GC{XKarKbX(to}6FU!!@GQBZ`H0Z+u$n%=FjmPCzjG>e`CQfIOoqh|Yo^)zp=)R$`Np{c1v^g|Sfh!_KdI4bqti`F5*shk4>
zk+c#H{UM@b28q4uszXbS7-t&8fi901{o2OYLPXt!d
zC){ipF-0onnV?E(e^f_MZ!83vVD3qiQPi=2k=&eX7K*1sWnIwvfGilZ@OTt6ybUK1
zq$l5`;p9Pl4hxv$7THhuj-FC~DL0~@?LYiaR3)FqC%7en$8eNLADE(5d(LO5-)c~Q
zy>>8rqg3Qmg|^pC-_*^_7Gaq_+fK4
zUbT@kv?QX~^$WQQ3h>fRti+_eH~bDZrtxD5g=X6e#}_m9-ygmkaHW%Fx%cK(?pB)X
z2mHeIk;3p7|EkPx8!v7yb?*Tmpp7)q|Bu#e1`s-q`5Xsy(Dg*Ee)mad-9ab*rOY_k
zI9uNhnZKC%YBIjE;xYnzzEp`!;cF+S<&fv>0XA#+><1R4@_MB68U2Sbi6M2D6oP~-
zHeNrlm;u>%b_{biwC3u&vgS$1&t{>GA>p_SOPL})#~5+h4!9lA9S84w#6>HKP9Qb=N3=d@`pfT$4H`w|MHbWL4-&zF#vi-L@hD96kQb>AMW@M
ziqeygT7e{@f!frbjxAZ0%Q&xB?K3I!E*5V_ySonM+2J(&n_dgfU&$@1fkeX}FgDvz
z4!U4M^*|T7yPM1e$RZYfEmsPN%kSbXJE$!Dgi)lv!U7BJbiuAM{n{T~jbC1`xk6y!
z9t^La*afTZ5+c^S~&4p(i87cJ#jQr}JvtgTF$Q
zN8Ue~D1y}^oP*`0c+;yOKf}baQEuCCyRL9KnDp0PDxv&gn-&OpKz)&+&JRh4*O<~^
zLUNb=U8jhHae>4bma`v;Xv>;<&F2QP&$m&0b0jv}`SN6xsm}3dQa+^!M8YQ~ry)E@
zvj~_7AO5gKt9T`)=lgW+C&y;ah|Ujx>cwuWM1mIg_pSS*w^O;^+RY?T3k6nS>Pq4G
zw_#&04S>`^QOIIx_MxW0d3!YDj?Pl493Wp%{eaY=BCeHdm#(R%`hh#Uho%&nLCDk6
z-f_hPNn7W!>sAutCWz5fIg+{t=9-(hKlwQ3*TRk)&c3sa(dA8Sk~*3y!Qi*#au%VJ
zc~}=4{HU;dmkV;Ej|Gf?MLiN?@eNH&E^6jAxXbBD)R@LC2MvL{B+l0wCld8jzEU2O
ztANZnT>Vw!lnLc|cqNeTc7IK&pI^iDlhLZO*UK?ND8GpGcJQ48u3!URSHSG~qwLs|
z={avpt3_qkh_2w)lOny5x(oEfO&xqjZL%QpaiSQgvMnM&bP)2oQ)l$&^#m
z-Kd_fy~KLe$@7y%+7y^9F`olzb=4-x>Ic0qw#jYW)?f&(bfwEWIAn8}^McVk8IOb?OW5CC&q9@(V|t>#~@(Z!TMD3pq`7Ggu+#
zz_s&ed$vm4STxP;aJlwrc$zyDp}UjZNw;Iqcp^WIpgfc6m1}
z3)thqU*4Mr`0rN{<-3QzYmQ^T&bJiKv(}>6ert$75HQ^7>VL~iM=so~t8}H?Yb=lx
z6cEf0>aWi0UIHvy4#&?8kyY8+(F;9a8l<{<%UeosByNVGy82dpthUe+csvu%G&QEK
z*Q#aU|BV4zRN#>hzhHRU3T=EdL2j;D`03L>
ztLd{n%M{C2Y%n%%|NZ|QY6hJmi;KMgA1TBir`E4odZm|r+|5;&ey6L2*${J_zU4=1
z)0X&4m-g@3rj!YRO!&mt8b>^?-!XP@Q+T-fg<~Ji9SqOQ1Www3+fM
z!M$idNy3eh18U-hSo_qv&{S_SEHi?-dl*5;O?9+FiN9@U6?G8Wo{s))(BLRsT=VLQ
zE@*IGiZWNx>UL;CYfMo)OA_$lKYxEtX)Bk=CX}HUloCdT#)6)W?HxZ_Xh{FT?ddx5
zE#cs4YSSfpzOJ8Z8kOtLk^|mpY;=?kq>`w&Z(MCXAGP+%;J;ZK<rcjK!P_Z+E}?s}iI6Ufo@Sz$P>D|}
z!TjpW(fEXQcDO-rLK8Cge|dlG0|Dh>dsedIIO%_ND(Ojj_DYBZ+%+q=VaY^loD!lz
zob*rO>jblCnQ007)a@nDI|5f|0H#aEI21r%KOfafH?a}ZQ&%CcF54Xx9Yw{@f78`R
zpj1}c%=V-BvdxpnX5b-io8bDkLM
zQ?b=1O}&qOtOy>k`4$0HgiyiS>f)OBdgPSYlDMH|@e`=IOCTt}gAK3@t?qN9fiP$7HkbM-_@rFR-?s
zDK%wkaWL0*ZRp_@j0Nx~RD5Cbu+jP%jWAK))u}n50@=_sN;}tD6PT+bNUWfuk9D(@
z=z-$UKPnZJ2cbf8im0p@8vvaF;2@{qpD2VBF3K%`oJg2W_-$n=5fj423eK=o?A~~S
zP}J}VSABJjS6p?CNd~aRXTky4!|;>XQhMe911oL*gzuOYQu(J|LSZ}Dl_Gg)+Um!F
zwOQ6}Z+}pR7=a_xk(Ac?E6?W~a=;;2zjjUg!;eO`Dp(l)3>cc^;>B6W?pOjLG|~F@
z0>SvE@;CIgl7BhZd{|3MUYuVDDEbE!Va!B@s4auSgdM@mIR$>*uTUf2!+<3Le%J
zgExyh<1~FARz{gj?c;>paDh}0p&C(h?aiy8#dD?`ztqjP5MaiSjgZ>;9hqxXQ`hq%
z+8oY4xha~$TS(9)4r$_$=;MY8yaq=#jHS^#jC9$+py$GaFA52@TWbM(z0LK6
z5WYNlsC&kqBy4P=QebTcLH6!_okquL3te}MX%qu2PC8j_;(7RP4w?irkuzX{R_t2!
z=T!ft1d7s)X)FhxPwkU1!glt_}mh4gMj}D1EH~Z`ppOV%MyEz+l9;
z9*nIr0gFHjtca?Wwg)*{QJts{Wm$pWT6V{rb>r>~>Egn#(3S}(FJ0s6G@HlrKmjuj
zsqGj=x0{|OcUiJ00m2EZYCWw5s(A4mk1HLP`R_6E0bx|<(q1wya@aa@qlq>>0)ltY
z+|ev|Cw8(6+-1e|%D-h3Dz0v-k0q$HGFx@gr2Yh^x$S4&Wf2p89El>lNW?(?oo%Orp6qhkGwB&8XKB367G)(fBpnN95NXX
zCdH>TT~(21G<$OOP(Y=5$fZPze+7ys5jq92D@iK%9NjRr3hM8vWpb7$S>BQ&B~y1A
z2QYVuqVdXVX&lGyVJ2clMu5a7Z1vuFTc`5&g1y(B2{%(=4iY+TJg}jV4?Du8;Ej3X
z_GBww7BKOr@jpSmt^B8-ApL(1ALF8nroIFJtvz6TvLptTZSO=l5`=;dM(f|6aM{
z3pFPuMFL;mmlTCjb2kC|MeklFReiLO)Fj_ULe$n~cDu`83=Iu467G?+nu`p_&a>6V
zdc~L6j&Y$J-b!S7DTQ_9t|0bL@0i;TP^M>iaN_5DLXl+Jd27==>E4@uLpJ`kTy^d~
zlxY&YNS?4X^lxD@3CHL$ZARvDhiGUgF?LzUFq7$l0njD>z>bWEV#Y{99Fr4vmzl7I
zO)`$dpNE|Z$1P~3>e8MjS|w3my{}90J*i`Om1{1BZ~L*31-Yt<>yT*R5LB^%nh>1N
z{+-?7E!kL=$xPQGDr3Y9+57{dytHb$4eR4R86O8?jkNsi1iSkeB7scP)+dHf%eIGB
zI3z*$Bqx+Hc{e>YK-hAAxn4_vN~txJU2{dE048D9nWNE!p0_Gcsqi&h6FY
zOgI*yHADIId8NPU(|p3tUV9Nn5{&Pj0j|S~*WXZx=C-F=B#NsGI>l80Cmmy&y1Zzv{XqIOn?xoF1z7Y9lrjJ-3}hUq-_k83T>nT)nm
zC?xOsKz4Xt&(!sNDo1bX?o=7V+A!-Uo5^r2Gd{8uygFF#9sct25dfrF6Im+i6*t4q
zK+w(Om1yDed7A_=%|{mnjY}z1T)2PAX7$}h@M`0d+1x5xiz?&S<@wx^33!xm62}U1
zU55=pdOA^3XtwZVDhEoB;Mrect)c&<=66
zzSceby^tbQ;75#KG-1~^QQ}GKr#4V3eLcWmS2kBHS!=PFdmUa=?d^GU)t7d%I7yXH
zFUcY|pLtI*#ij!5eH@&PhaeL|S$Q!{1KPAc4zaw02l}+uBk(^p$Bfj>YS{j*zr2Ye
z+v}WX`FrqWM1lY|Ejefp`uBA>t4p6cC3w01yo?w>w0GOnN{9sMr-&(VFbs0h`@EE_
z-m_?o3uQVVh0K)LKOWEd?R*x&2b}Zm>n2h3i9lS~zA8SUv$ZNz{MmimId3b4RT}{e
z%!I3BrQFVT`vb;uj47?P@86p`J?(WRoLCO6_f|{If03KoVP?a^?GLQm_t^Ur>&qzX
zN2vr%k@bO^Gv%zofx5PbffgMTc8%5pr4jd`dc^3nF?&dK`=0<@kWmsSvxbasTa8KN
zPkf17Z>eGOs4bK9q9mmPaxCH7B_o*YL^#H`n1knNwFFzQJ+IsxM%>OD@b?6Gs@%H@
zMv^)*vk^&p%xoDK6oscXCC*mhMVFZ4kjx;HGRqc+z|}87Du80p@q*Ehl@m3
zCFAW7V?IabH1xggqf}CR-@WA0@ZMj;C%k9Hg3ig#YlLo1GAPSl+U8|BNhsLU|e|?keynl(a^&;t+W=Yqhs(
zCey?E!vZ4?aZ_O3jCCN{EgzzMy=VGt%ZXAY(;DGb
zt`5Wm0T`%ZnO!{r(OJXwz$r7-o?1<@Qh#LcbGoM&DMfkpN15|g-%Lpo6sqjnzkt36
znv~2sFW$ywO%Y)auNSm-k;kJE-KSfkRw8?>F%YZ{C$r59=7O5WCajovEbVV@YXs3S
z@J^f^P%?$4sHtn{;8XYcNm;Gd4{UiJhyN!Gsk4`X%C
z&~KLjHmJX<>Y8HGJ=#1ZW8z2=6~aLAzQvqk*017o`TLbZN7fFiW^vtPAB@`Jr!!-7
z)oO{Vc<=rZN?V6U-|yzLC_wr|h>32fKAHlEFru+O!q2!A#(0fgur+BRpOa)OS)4!4
zy^S65yOmzlv>pfv_5-B23aYkm9(@E#uwt!k;&yB{P~Tn&)fz+2y_-pdfpkuDQ}lF_
zf6&G)Sz#lh!CZdU({CXh{$ti{#I-b{O753?RysKj{eVS5ONqqh?5pO6iH8~8h~ia}
z2j(b$FAhl@tsQfZ-o*@+TW2DP%4CPvb=PndY$2!0={?~H@!NaKc8ohoSo
zr!rwPE+jlob-{D=1m?6Q-VwLIy7_(36mQk6M}k8688^RmPrhLE0FuC$?z}}?AL{j
z^OYmZLF>p21cal6(@2+Wn`z_w$N^iniU2v#EG(V(f19X}T~oTk275{Fricd14Rda}
z`%pzBYV$;74hlFxTIoU`Ab|mP2R}ZUL^bfccQfC^zD>EHP!D-L9{W6T@7DTH!{6<_
zFAPmp2ELKRGlT(rJ&Qff+c&n)zt3^o{(-|x4>zpVG`L~U)r*8N4xW?9E}SRtIM59;
z5ER@ChR=<7_8B9=*+>#9oF}-tVO{`
z{`odmm*&&uNtq2-cAXXOJHR@LN)A-)m4LV@c47#~eC~!|Ty~MV?6d-iJg{?F{}h^C
zt?++jWObjSjYKf?28p;U(-TRB|%AV53mM_(sq
z@DOtfc?A1Y9_YUS(#@atyY2quCoPw3|*=*xOE;m?B_h_mv-*A~ABQT*wgxr0l*zC9GT}
zt`q_jm0?`*4F;xb^^z&=x~)s$t&3I!&XViF_Xhv!A`9iegevSvLf8V*)fzmBU?zej
zWPRvil&+u;H}$3#t&dmr_2O&-@*0Xzy?F12RulO9d(`5q|2~i?G?KbF>Ws0}pY6a8
z`iR{UUVb<3I<+B9YEU%;AcpuT``9m#hg25F?bRqubG6T#d(dccjEiVQ)0xd(EB7vl
zn$dH(*e&Q_cL(dGjvt2=o07ch!VZEP*N-goX!G(I0~LSgJVCxLfYvWjismH@Q{+%3
zzdRs!D5B`jNZ6x3w6p!p5`1ccRhtBeoyke9QoB
z;f%YgBq;kdDsym#y6OCwDH7&@^0PE!ah~$v1DrutlR-1}*!s9%w%&2&OCVP5!50+`
z`_FeE5Z2%KS%6%Ba&~4MOkSO(E%TBe&C5bD(y-K|1N!MWyqFz`)KdY-V33E>Zyo2`
z?Zl93i(#3d)O|bKuuh`Y_QcY%LWwO0ZvIMmGlwU0&~wjq`6}xp9zfT{0M)DPn+iE%
zPN_y#%f1R|cQmRn>&2ZBilvBy$5NdJl0?`is?bqwE+wx}q7jB#XY5b8g3SdxJW&gu
zKU5TIIUf=%RIRP71Vov&)UI$0B&}~W$K}Oe-sS3Tx5BQu+TB0@eph=^?Bm$B3Vk%C(X=N>
z=W`%MWXr-ufeL&Nx3g)U?08$wcnu3NThZ#Bk{X@31CYp(M
zcRP*MMh_tvCH90Vyj+lMGP(^B-(QV@JjP~NX=OtQ%^NWi8yd&Sr5)#NgV`Uq17i%q
zgVs;M8fEv*O>2@XFL-78Fk&YswBGkLIw>ywl=8zW${^h@Wj$aO5S2nScEyYNp-|b9
zv$~<>lsC~twL>koiiJ_$f=MTX+@6v6)mJr7sz(iSFDf{MOAK<&PnJRRJ&~S56Fp#b
z3QQ4s2U*idNLn?%T4%G>HPx27&x;#HD%<#O=WWqT3VZ%_|7j>Z&TM!vh7oE^2){lc
zvg&y=GJ7jtQeyp|Sqm;~=i}8$ziD#k!H6E1M5~^7CHok5l
zB4H1DmTld{+5)Rzh^!DPG@Vj8+2(j3E382@#aaw17Jy{4a)uiI-0w&puV&xMixw*j
z^I_Ixf47_ebZO@Luf$v1y-L{G`46kq3w(qqT{L;dFibBhjG|mjM@w6Z*ZJq#N|Vlj
z-#jWH21hK9K3+gJ8c+#p@p3;?u;%@4$}4ktxjQY0szH%2R$nXNwmkX4&F)Z0XTU|L
zsMg8dLz=3(XZm-;2h5n!SIJRSr3s>{z#Iitcr!sN4=0NnmLOJQ}^5jk=1ECE@Hui8A#_Ee3EM%P?o|P#J
zh-zL(23p~j;W=kmkO^F%d?cf6behha`Wo6R>u*2O`6UiEnP&j_Hd26hx4^=hVnQMR+5@L=zTGkPs69S*IQ^I?edj9ZbMB#*7wY)I1#|?
z82TCiCV-gp%u7EnUdoPtM__Wd4z%K0MK?>L*+%|EK@dA_;eo$pDR(lL@2H
z1(K{LJn)o_6=66ef_~I7!sNxutSE$2V$OeMYC6li?v=;vCD+>i#$dg#;ZMw|93(hO
zeM96@-DR;}<-ywd=aE7bx=H|lpW#i;9&;jC!%+_YO(mPoGxX!3D$e-Y$zucwq5%vu
zEDC=DDLnm
zQc2gITu6MD;&ORZXZWnKaSkI9LizzD(nWJSh$&J$to+l8%{VGpX^<5f~+8Ye04F9sUMcO7b)6Cm|v|@jwQ{T-Ci0?*SRdW_<
z>$imxW3WcMm#0F#n=wdVIx+g4*g{qC7AYt9Y|^K8QI!
z*3LE0D<`K5?qWd0-HcP|=x*rn4J?P4n5FDK!pvLYU=2;ZvWC9}W)yEh!{L|cY3iBE
zlX63C^C&bAdV)~_nGTlS`6z+v%u7lo9cZYBWENwZJ$kg)>n+&={k-ar;M<x;9hq$_`eA5s@bW1=d*WNy
z{39QH#PsFK=}MKp4MLA@lV4tiO3aj_l?-Nh;JMqpDp>QSm>KJZ)@fo>B=z&~)B275
zylUB|^&?KGaRuV@Xcb8Kc#@OI9=G|V^iZ*aX?5bRaN)#=Fget)lHsk>v(weBQ>$`W
znMvhp=xSDvCF6M>A}AQ8p&QFBOc*7M$VY;|?&G{IHExwgxmIaX+w1o(_Ja`Sh>791
zURy|Z*0%=9dnHHl<@$KfPMU1xv_1B6^N$LR;t)=V@zTTqvh}MCL%-OXyie%^8vVK?
zI$=UTR1IkgjscPwWb5!>naBLz{gfDAs|oim73((|h?-+XDB5tBp|*NIy9YpO5|fR;
zWB`*;jZa?k=zFD%$GH6YytZdsE4q>1DY>SFMN?&S21Ppy$WfM>_ZR9e5Y>zpy*`ID
z;I|5UupL3QaiLA4?N`vSt#TpUUCv&?4(VA^I;)3GoP9Y!et`m?1!B<(k&K<)Kc
zA4HN0p8SgoAj`{U6Eca$FzL&&@%_NTwSjJoH*;k4YH#Mnzcu}fQXdS2`=b(Q{nk7r
zL6{;kj-FiX1k7
z?tZB=ik2Z|uf!9td@sXDA*
zPaiKjoT|1&W7O~*6EWvrj|fu)!Lj*p!@cG1);7r8hCsFdjrd5Xus>Jnuxpg29Ofh9
zX;VR>kb_bP&v8=Kg~56IaSa@oqYe6=Eler(WrW2SRroE+MCQspRrS!f(kK5FV((X7cu9_(O|n1=Q!GM
ztjQR$l9*rt)AdfN(ozQyo!9y>=9=+=#uCs^|CP}yNt>{vMVo(!cF1H7;=60%9$z&1vtBhy{p-IWc8KuxJd_BK8Cvf
zE_upU!inC+h$s>yrk9xpg8((eCc~#F4>5yhFFDfwddvK5snIHtAq*&SJ^g`;Dd;f{
zH9kV&lBSsSx9qsAW!g{z968^DtTxno>=XsLD8Qh5`Ne!UappDHh(BFarfoncp0;`Q
zQV2>KFOrScyxhloUcZOKbVRb&UTz{Pzd>c9m1K~;ES#T2Ehv!~q*rbV?`Hc!rLAC8
zGNd&OKz_|qod{8gn>B_|NLo=__E$^$e0BH6n~0eAVHR!20;OWjZ7^4lZp1^y#cLZN
z<8XXN&0JyTp-)n3dXLRB!lo^t!@}~w&wQGU38}h?Q9-n-L{<#c%xCP2-o|rt9n|Yh
zAD*Ha)XdVOkZ4Ln>qVFHeQe%JmX&!wp^Ar9OCU+rpZ#ua@`2O{Tta);3A1{ij*HPC
zuD=7haP(wmEsSyg)}Wvpo^HmgR+(1(yGh!%Uh+(J^GIZ)%*2Q~KDK0L4A$+YZFw_T
zwEC2pmIBw92+*hH4?oP!Y`V{OA`n@U+GlY16;0k-#9_vNsI-&-$vc;dN_rO|wA`O!
zeZ7b_iS!62eDxE?iI0pjh+$l-ke$v?EjB8{f0)PhP~dCL`1VSHD)b{9IaeFHO9xl?Cg`fFkx1?9%ZA5CzJZ0+uQgMz_nmgB>Ht{_)1BlZVA
zj|Vwqyk8^=1}^5
WOGS*{p@8vSeQ7Z
zm9!*g5k>e$ppU*RpHM!^h<{ntpXB~UlXc3i)x>iU>j+SRV-6)3$~cZS7jr{z-J7*}
zCHrRiE>gB*>$4e9QKGErkf`_v`&Er@_BoSFk5@^|S^s3Ub)l}>`xkXxZ-k^fu(7}e
z^#-Y-}xUrGlh=)nVd6KmX{Bcgabwk-3ay_vHq&2(w6TY65X3L3(utO#SSDSNa
z5dVnb9_xvDn%5B=u}17`-1z~-L-{&H(qmLm>;-#hakKL5PKL6IG6hFT%i%*KG;kF7
z)S?1nQ7M->CA|^*%M=VX1zYUG;%v`7+m-qdmOW<@_L_)CYLx*o=g*bFS(6Fu&{?`y
zh|&3rb4DYBmVpub{7ZwG}Y6evH4sGQX>^F~kuS
zqZ+5DE7%Zs(Y=9PxHS*;&R1PP7*$W#rHsFA-oq~3!W%Mlu
zA);@@Q+Q^AJ?(pNhcI@e^!L4Qy}w`@t3L}a&U3k%u0XW$*b{nioE?oM2=tA<`+#O+
z&@QX{Fv47|ypXUJp|=-p&hDwJOYxV~%J~KR0@o2XO?~AutljF(&%Ufl9e3zL+ms)P
z$a)64Jj+PQH5D^(9I!iiE&;Qwutgf1uP0}NMMT9d%Pe+2K6-VjBV(Hs7kWuECx!@?~kOf1zuK8nW{Gye*M
z%y#rX%KQn9NuaEHr&99K@
z{%aB5_c}Ay-C`5L>idKqQZs{C`AwI7uD!7cX@Cp^;!@7~F6l2%vQ6`s;@TMQ+LI8t
zibjG>(Xs(1m9vc7AjktoI-Ka?fl&ZTDai7hz0j4kazuR#EaW86_JxImZZ^mSAIXrm
z)4s``O;zqNZ-1vw>(d!be_*M=zqdLb)VEv46lq1676QKfQVX2bRAF#*90=h+9*ACU
z!zCIB^w^~TVd*B=&`BX$0iOAm`pXlg2;>x?8p)>P^GQKc=5PZCvljR*8~U?|*1K}4
zBHsVm5BdfeGMPzdJ&gw;d&B;NxnGe;ET-Jb;)#l25sl@q^B%0%lgYIGrK^D|UdD|6TO||DJvphK*tMBFaqv
S0(?6RBqOOHQ6XmF|9=2|mMORZ
literal 0
HcmV?d00001
diff --git a/shearapi-fmlstuff/src/main/resources/fabric.mod.json b/shearapi-fmlstuff/src/main/resources/fabric.mod.json
new file mode 100644
index 0000000..c9a5604
--- /dev/null
+++ b/shearapi-fmlstuff/src/main/resources/fabric.mod.json
@@ -0,0 +1,36 @@
+{
+ "schemaVersion": 1,
+ "id": "shearapi-fmlstuff",
+ "version": "${version}",
+ "name": "Shear API (FML Stuff)",
+ "description": "Deal with stuff things if FML installed",
+ "authors": [
+ "PillowMC"
+ ],
+ "contact": {
+ "homepage": "https://github.com/PillowMC/ShearAPI",
+ "sources": "https://github.com/PillowMC/ShearAPI"
+ },
+ "license": "LGPL-2.1",
+ "icon": "assets/shearapi-fmlstuff/icon.png",
+ "environment": "*",
+ "depends": {
+ "fabricloader": ">=0.15.6",
+ "minecraft": "~1.20.4",
+ "java": ">=17",
+ "fabric-api": "*",
+ "shearapi-runtime": "~${version}",
+ "shearapi-network": "~${version}",
+ "shearapi-withpillow": "~${version}"
+ },
+ "entrypoints": {
+ "shearapi-runtime:client_mod_bus_subscriber": ["net.pillowmc.shearapi.fmlstuff.client.ShearAPIFMLStuffClient::clazz"],
+ "shearapi-runtime:mod_bus_subscriber": ["net.pillowmc.shearapi.fmlstuff.ShearAPIFMLStuff::clazz"]
+ },
+ "custom": {
+ "modmenu": {
+ "parent": "shearapi",
+ "badges": ["library"]
+ }
+ }
+}
diff --git a/shearapi-withpillow/build.gradle b/shearapi-withpillow/build.gradle
index fd95694..d7df97c 100644
--- a/shearapi-withpillow/build.gradle
+++ b/shearapi-withpillow/build.gradle
@@ -9,5 +9,4 @@ dependencies {
implementation "net.neoforged.fancymodloader:loader:${project.fancy_mod_loader_version}"
api project(path: ":shearapi-runtime", configuration: "namedElements")
api project(path: ":shearapi-withoutpillow", configuration: "namedElements")
- api project(path: ":shearapi-network", configuration: "namedElements")
}
diff --git a/shearapi-withpillow/src/main/java/net/pillowmc/shearapi/withpillow/ShearAPIWithPillow.java b/shearapi-withpillow/src/main/java/net/pillowmc/shearapi/withpillow/ShearAPIWithPillow.java
index 78e2f9e..0676729 100644
--- a/shearapi-withpillow/src/main/java/net/pillowmc/shearapi/withpillow/ShearAPIWithPillow.java
+++ b/shearapi-withpillow/src/main/java/net/pillowmc/shearapi/withpillow/ShearAPIWithPillow.java
@@ -1,25 +1,13 @@
package net.pillowmc.shearapi.withpillow;
import net.neoforged.bus.api.Event;
-import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.ModList;
import net.neoforged.fml.ModLoader;
import net.neoforged.fml.loading.FMLLoader;
-import net.neoforged.neoforge.network.configuration.SyncConfig;
-import net.neoforged.neoforge.network.event.OnGameConfigurationEvent;
-import net.neoforged.neoforge.network.payload.ConfigFilePayload;
import net.pillowmc.shearapi.runtime.IModBusEvent;
import net.pillowmc.shearapi.withoutpillow.ShearAPIWithoutPillow;
public class ShearAPIWithPillow extends ShearAPIWithoutPillow {
- public static Class clazz = ShearAPIWithPillow.class;
-
- @SubscribeEvent
- public static void onGameConfigurationEvent(OnGameConfigurationEvent event) {
- if (event.getListener().isConnected(ConfigFilePayload.ID)) {
- event.register(new SyncConfig(event.getListener()));
- }
- }
@Override
public boolean isProduction() {
diff --git a/shearapi-withpillow/src/main/resources/fabric.mod.json b/shearapi-withpillow/src/main/resources/fabric.mod.json
index ec6c066..8f7e6bc 100644
--- a/shearapi-withpillow/src/main/resources/fabric.mod.json
+++ b/shearapi-withpillow/src/main/resources/fabric.mod.json
@@ -21,10 +21,6 @@
"fabric-api": "*",
"shearapi-runtime": "~${version}"
},
- "entrypoints": {
- "shearapi-runtime:client_mod_bus_subscriber": ["net.pillowmc.shearapi.withpillow.client.ShearAPIWithPillowClient::clazz"],
- "shearapi-runtime:mod_bus_subscriber": ["net.pillowmc.shearapi.withpillow.ShearAPIWithPillow::clazz"]
- },
"mixins": [
"shearapi-withpillow.mixins.json"
],
From 2fb9af001837a98194c93118077a4fc8bad55480 Mon Sep 17 00:00:00 2001
From: Hei Piao
Date: Fri, 2 May 2025 21:26:21 +0800
Subject: [PATCH 5/5] wip: port a little more for shearapi-network
---
.../client/ShearAPIFMLStuffClient.java | 67 +++++++++++++++-
.../network/configuration/SyncRegistries.java | 2 +-
.../payload/FrozenRegistryPayload.java | 0
.../FrozenRegistrySyncCompletedPayload.java | 0
.../FrozenRegistrySyncStartPayload.java | 0
.../shearapi/fmlstuff/ShearAPIFMLStuff.java | 34 ++++++++
.../src/main/resources/fabric.mod.json | 1 +
.../handlers/ClientPayloadHandler.java | 65 +--------------
.../network/client/DualStackUtilsClient.java | 28 +++++++
.../network/client/ShearAPINetworkClient.java | 30 ++-----
.../network/ConfigurationInitialization.java | 52 +++++-------
.../neoforge/network/DualStackUtils.java | 23 +-----
.../neoforge/network/PacketDistributor.java | 13 +--
.../SyncTierSortingRegistry.java | 70 ++++++++--------
.../filters/GenericPacketSplitter.java | 3 +-
.../VanillaConnectionNetworkFilter.java | 22 +++--
.../handlers/ServerPayloadHandler.java | 58 ++++++--------
.../NetworkComponentNegotiator.java | 8 +-
.../payload/TierSortingRegistryPayload.java | 80 +++++++++----------
...ierSortingRegistrySyncCompletePayload.java | 64 +++++++--------
.../IServerGamePacketListenerExtension.java | 2 +-
.../src/main/resources/fabric.mod.json | 4 +-
.../neoforge/registries/RegistryManager.java | 6 +-
.../registries/ShearAPIRegistries.java | 13 +++
.../shearapi-registries.accesswidener | 3 +
.../pillowmc/shearapi/runtime/IRuntime.java | 3 +
.../utils/mixin/client/MinecraftMixin.java | 17 +++-
.../utils/mixin/client/UtilsMixin.java | 21 +++++
.../shearapi-utils.client.mixin.json | 5 +-
.../pillowmc/shearapi/utils/IClientLike.java | 4 +-
.../net/pillowmc/shearapi/utils/Utils.java | 4 +
.../withoutpillow/ShearAPIWithoutPillow.java | 7 ++
.../withpillow/ShearAPIWithPillow.java | 10 +++
33 files changed, 416 insertions(+), 303 deletions(-)
rename {shearapi-network => shearapi-fmlstuff}/src/main/java/net/neoforged/neoforge/network/configuration/SyncRegistries.java (97%)
rename {shearapi-network => shearapi-fmlstuff}/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistryPayload.java (100%)
rename {shearapi-network => shearapi-fmlstuff}/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistrySyncCompletedPayload.java (100%)
rename {shearapi-network => shearapi-fmlstuff}/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistrySyncStartPayload.java (100%)
create mode 100644 shearapi-network/src/client/java/net/pillowmc/shearapi/network/client/DualStackUtilsClient.java
create mode 100644 shearapi-utils/src/client/java/net/pillowmc/shearapi/utils/mixin/client/UtilsMixin.java
diff --git a/shearapi-fmlstuff/src/client/java/net/pillowmc/shearapi/fmlstuff/client/ShearAPIFMLStuffClient.java b/shearapi-fmlstuff/src/client/java/net/pillowmc/shearapi/fmlstuff/client/ShearAPIFMLStuffClient.java
index 79b34d6..4af4f38 100644
--- a/shearapi-fmlstuff/src/client/java/net/pillowmc/shearapi/fmlstuff/client/ShearAPIFMLStuffClient.java
+++ b/shearapi-fmlstuff/src/client/java/net/pillowmc/shearapi/fmlstuff/client/ShearAPIFMLStuffClient.java
@@ -1,20 +1,43 @@
package net.pillowmc.shearapi.fmlstuff.client;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import net.fabricmc.api.ClientModInitializer;
import net.minecraft.client.Minecraft;
+import net.minecraft.network.chat.Component;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.resources.ResourceLocation;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.config.ConfigTracker;
import net.neoforged.neoforge.network.event.RegisterPayloadHandlerEvent;
+import net.neoforged.neoforge.network.handlers.ClientPayloadHandler;
+import net.neoforged.neoforge.network.handling.ConfigurationPayloadContext;
import net.neoforged.neoforge.network.handling.IPayloadContext;
import net.neoforged.neoforge.network.payload.ConfigFilePayload;
+import net.neoforged.neoforge.network.payload.FrozenRegistryPayload;
+import net.neoforged.neoforge.network.payload.FrozenRegistrySyncCompletedPayload;
+import net.neoforged.neoforge.network.payload.FrozenRegistrySyncStartPayload;
import net.neoforged.neoforge.network.registration.IPayloadRegistrar;
+import net.pillowmc.shearapi.fmlstuff.ShearAPIFMLStuff;
import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
import net.pillowmc.shearapi.runtime.ShearAPIVersion;
import net.pillowmc.shearapi.withpillow.ShearAPIWithPillow;
+import java.util.Map;
import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
-public class ShearAPIFMLStuffClient {
+public class ShearAPIFMLStuffClient implements ClientModInitializer {
public static Class clazz = ShearAPIFMLStuffClient.class;
+ private static final Map synchronizedRegistries = Maps.newConcurrentMap();
+ private static final Set toSynchronize = Sets.newConcurrentHashSet();
+
+ @Override
+ public void onInitializeClient() {
+ ShearAPIFMLStuff.clientHandleRegistrySyncCompleted = ShearAPIFMLStuffClient::handleRegistrySyncCompleted;
+ }
+
@SubscribeEvent
public static void onRegisterPayloadHandlerEvent(RegisterPayloadHandlerEvent event) {
if (!(ShearAPIRuntime.getRuntime() instanceof ShearAPIWithPillow)) {
@@ -24,6 +47,14 @@ public static void onRegisterPayloadHandlerEvent(RegisterPayloadHandlerEvent eve
.versioned(ShearAPIVersion.getSpec())
.optional();
registrar
+ .configuration(
+ FrozenRegistrySyncStartPayload.ID,
+ FrozenRegistrySyncStartPayload::new,
+ handlers -> handlers.client(ShearAPIFMLStuffClient::handleRegistrySyncStart))
+ .configuration(
+ FrozenRegistryPayload.ID,
+ FrozenRegistryPayload::new,
+ handlers -> handlers.client(ShearAPIFMLStuffClient::handleFrozenRegistry))
.configuration(
ConfigFilePayload.ID,
ConfigFilePayload::new,
@@ -37,4 +68,38 @@ private static void handleConfigFile(ConfigFilePayload payload, IPayloadContext
).ifPresent(mc -> mc.acceptSyncedConfig(payload.contents()));
}
}
+
+ public static void handleFrozenRegistry(FrozenRegistryPayload payload, ConfigurationPayloadContext context) {
+ synchronizedRegistries.put(payload.registryName(), payload.snapshot());
+ toSynchronize.remove(payload.registryName());
+ }
+
+ public static void handleRegistrySyncStart(FrozenRegistrySyncStartPayload payload, ConfigurationPayloadContext context) {
+ toSynchronize.addAll(payload.toAccess());
+ synchronizedRegistries.clear();
+ }
+
+ public static void handleRegistrySyncCompleted(FrozenRegistrySyncCompletedPayload payload, ConfigurationPayloadContext context) {
+ if (!toSynchronize.isEmpty()) {
+ context.packetHandler().disconnect(Component.translatable("neoforge.network.registries.sync.missing", this.toSynchronize.stream().map(Object::toString).collect(Collectors.joining(", "))));
+ return;
+ }
+
+ context.workHandler().submitAsync(() -> {
+ //This method normally returns missing entries, but we just accept what the server send us and ignore the rest.
+ Set> keysUnknownToClient = RegistryManager.applySnapshot(synchronizedRegistries, false, false);
+ if (!keysUnknownToClient.isEmpty()) {
+ context.packetHandler().disconnect(Component.translatable("neoforge.network.registries.sync.server-with-unknown-keys", keysUnknownToClient.stream().map(Object::toString).collect(Collectors.joining(", "))));
+ return;
+ }
+
+ toSynchronize.clear();
+ synchronizedRegistries.clear();
+ }).exceptionally(e -> {
+ context.packetHandler().disconnect(Component.translatable("neoforge.network.registries.sync.failed", e.getMessage()));
+ return null;
+ }).thenAccept(v -> {
+ context.replyHandler().send(new FrozenRegistrySyncCompletedPayload());
+ });
+ }
}
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/configuration/SyncRegistries.java b/shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/configuration/SyncRegistries.java
similarity index 97%
rename from shearapi-network/src/main/java/net/neoforged/neoforge/network/configuration/SyncRegistries.java
rename to shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/configuration/SyncRegistries.java
index 8374471..9a000bc 100644
--- a/shearapi-network/src/main/java/net/neoforged/neoforge/network/configuration/SyncRegistries.java
+++ b/shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/configuration/SyncRegistries.java
@@ -24,7 +24,7 @@
@ApiStatus.Internal
public record SyncRegistries() implements ICustomConfigurationTask {
private static final ResourceLocation ID = new ResourceLocation(ShearAPIRuntime.MOD_ID, "sync_registries");
- public static final Type TYPE = new Type(ID);
+ public static final Type TYPE = new Type(ID.toString());
@Override
public void run(Consumer sender) {
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistryPayload.java b/shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistryPayload.java
similarity index 100%
rename from shearapi-network/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistryPayload.java
rename to shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistryPayload.java
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistrySyncCompletedPayload.java b/shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistrySyncCompletedPayload.java
similarity index 100%
rename from shearapi-network/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistrySyncCompletedPayload.java
rename to shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistrySyncCompletedPayload.java
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistrySyncStartPayload.java b/shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistrySyncStartPayload.java
similarity index 100%
rename from shearapi-network/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistrySyncStartPayload.java
rename to shearapi-fmlstuff/src/main/java/net/neoforged/neoforge/network/payload/FrozenRegistrySyncStartPayload.java
diff --git a/shearapi-fmlstuff/src/main/java/net/pillowmc/shearapi/fmlstuff/ShearAPIFMLStuff.java b/shearapi-fmlstuff/src/main/java/net/pillowmc/shearapi/fmlstuff/ShearAPIFMLStuff.java
index 8346126..6d5b766 100644
--- a/shearapi-fmlstuff/src/main/java/net/pillowmc/shearapi/fmlstuff/ShearAPIFMLStuff.java
+++ b/shearapi-fmlstuff/src/main/java/net/pillowmc/shearapi/fmlstuff/ShearAPIFMLStuff.java
@@ -2,18 +2,52 @@
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.neoforge.network.configuration.SyncConfig;
+import net.neoforged.neoforge.network.configuration.SyncRegistries;
import net.neoforged.neoforge.network.event.OnGameConfigurationEvent;
+import net.neoforged.neoforge.network.event.RegisterPayloadHandlerEvent;
+import net.neoforged.neoforge.network.handling.ConfigurationPayloadContext;
+import net.neoforged.neoforge.network.handling.IConfigurationPayloadHandler;
import net.neoforged.neoforge.network.payload.ConfigFilePayload;
+import net.neoforged.neoforge.network.payload.FrozenRegistryPayload;
+import net.neoforged.neoforge.network.payload.FrozenRegistrySyncCompletedPayload;
+import net.neoforged.neoforge.network.payload.FrozenRegistrySyncStartPayload;
+import net.neoforged.neoforge.network.registration.IPayloadRegistrar;
import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
+import net.pillowmc.shearapi.runtime.ShearAPIVersion;
import net.pillowmc.shearapi.withpillow.ShearAPIWithPillow;
public class ShearAPIFMLStuff {
public static Class clazz = ShearAPIFMLStuff.class;
+ public static IConfigurationPayloadHandler clientHandleRegistrySyncCompleted;
@SubscribeEvent
public static void onGameConfigurationEvent(OnGameConfigurationEvent event) {
+ if (event.getListener().isConnected(FrozenRegistrySyncStartPayload.ID) &&
+ event.getListener().isConnected(FrozenRegistryPayload.ID) &&
+ event.getListener().isConnected(FrozenRegistrySyncCompletedPayload.ID)) {
+ event.register(new SyncRegistries());
+ }
if (event.getListener().isConnected(ConfigFilePayload.ID) && ShearAPIRuntime.getRuntime() instanceof ShearAPIWithPillow) {
event.register(new SyncConfig(event.getListener()));
}
}
+ @SubscribeEvent
+ public static void onRegisterPayloadHandlerEvent(RegisterPayloadHandlerEvent event) {
+ if (!(ShearAPIRuntime.getRuntime() instanceof ShearAPIWithPillow)) {
+ return;
+ }
+ final IPayloadRegistrar registrar = event.registrar(ShearAPIRuntime.MOD_ID)
+ .versioned(ShearAPIVersion.getSpec())
+ .optional();
+ registrar
+ .configuration(
+ FrozenRegistrySyncCompletedPayload.ID,
+ FrozenRegistrySyncCompletedPayload::new,
+ handlers -> handlers.client(clientHandleRegistrySyncCompleted)
+ .server(ShearAPIFMLStuff::handleRegistrySyncCompleted));
+ }
+
+ public static void handleRegistrySyncCompleted(FrozenRegistrySyncCompletedPayload payload, ConfigurationPayloadContext context) {
+ context.taskCompletedHandler().onTaskCompleted(SyncRegistries.TYPE);
+ }
}
diff --git a/shearapi-fmlstuff/src/main/resources/fabric.mod.json b/shearapi-fmlstuff/src/main/resources/fabric.mod.json
index c9a5604..bc50548 100644
--- a/shearapi-fmlstuff/src/main/resources/fabric.mod.json
+++ b/shearapi-fmlstuff/src/main/resources/fabric.mod.json
@@ -24,6 +24,7 @@
"shearapi-withpillow": "~${version}"
},
"entrypoints": {
+ "client": ["net.pillowmc.shearapi.fmlstuff.client.ShearAPIFMLStuffClient"],
"shearapi-runtime:client_mod_bus_subscriber": ["net.pillowmc.shearapi.fmlstuff.client.ShearAPIFMLStuffClient::clazz"],
"shearapi-runtime:mod_bus_subscriber": ["net.pillowmc.shearapi.fmlstuff.ShearAPIFMLStuff::clazz"]
},
diff --git a/shearapi-network/src/client/java/net/neoforged/neoforge/network/handlers/ClientPayloadHandler.java b/shearapi-network/src/client/java/net/neoforged/neoforge/network/handlers/ClientPayloadHandler.java
index 95a7878..f89c7c3 100644
--- a/shearapi-network/src/client/java/net/neoforged/neoforge/network/handlers/ClientPayloadHandler.java
+++ b/shearapi-network/src/client/java/net/neoforged/neoforge/network/handlers/ClientPayloadHandler.java
@@ -5,39 +5,21 @@
package net.neoforged.neoforge.network.handlers;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
import io.netty.buffer.Unpooled;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.MenuScreens;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.gui.screens.inventory.MenuAccess;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
-import net.minecraft.resources.ResourceKey;
-import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.MenuType;
-import net.neoforged.neoforge.common.TierSortingRegistry;
import net.neoforged.neoforge.common.world.AuxiliaryLightManager;
import net.neoforged.neoforge.common.world.LevelChunkAuxiliaryLightManager;
-import net.neoforged.neoforge.network.ConfigSync;
-import net.neoforged.neoforge.network.handling.ConfigurationPayloadContext;
-import net.neoforged.neoforge.network.handling.IPayloadContext;
import net.neoforged.neoforge.network.handling.PlayPayloadContext;
import net.neoforged.neoforge.network.payload.AdvancedContainerSetDataPayload;
import net.neoforged.neoforge.network.payload.AdvancedOpenScreenPayload;
import net.neoforged.neoforge.network.payload.AuxiliaryLightDataPayload;
-import net.neoforged.neoforge.network.payload.ConfigFilePayload;
-import net.neoforged.neoforge.network.payload.FrozenRegistryPayload;
-import net.neoforged.neoforge.network.payload.FrozenRegistrySyncCompletedPayload;
-import net.neoforged.neoforge.network.payload.FrozenRegistrySyncStartPayload;
-import net.neoforged.neoforge.network.payload.TierSortingRegistryPayload;
-import net.neoforged.neoforge.registries.RegistryManager;
-import net.neoforged.neoforge.registries.RegistrySnapshot;
import org.jetbrains.annotations.ApiStatus;
@ApiStatus.Internal
@@ -48,52 +30,11 @@ public static ClientPayloadHandler getInstance() {
return INSTANCE;
}
- private final Set toSynchronize = Sets.newConcurrentHashSet();
- private final Map synchronizedRegistries = Maps.newConcurrentMap();
-
private ClientPayloadHandler() {}
- public void handle(FrozenRegistryPayload payload, ConfigurationPayloadContext context) {
- synchronizedRegistries.put(payload.registryName(), payload.snapshot());
- toSynchronize.remove(payload.registryName());
- }
-
- public void handle(FrozenRegistrySyncStartPayload payload, ConfigurationPayloadContext context) {
- this.toSynchronize.addAll(payload.toAccess());
- this.synchronizedRegistries.clear();
- }
-
- public void handle(FrozenRegistrySyncCompletedPayload payload, ConfigurationPayloadContext context) {
- if (!this.toSynchronize.isEmpty()) {
- context.packetHandler().disconnect(Component.translatable("neoforge.network.registries.sync.missing", this.toSynchronize.stream().map(Object::toString).collect(Collectors.joining(", "))));
- return;
- }
-
- context.workHandler().submitAsync(() -> {
- //This method normally returns missing entries, but we just accept what the server send us and ignore the rest.
- Set> keysUnknownToClient = RegistryManager.applySnapshot(synchronizedRegistries, false, false);
- if (!keysUnknownToClient.isEmpty()) {
- context.packetHandler().disconnect(Component.translatable("neoforge.network.registries.sync.server-with-unknown-keys", keysUnknownToClient.stream().map(Object::toString).collect(Collectors.joining(", "))));
- return;
- }
-
- this.toSynchronize.clear();
- this.synchronizedRegistries.clear();
- }).exceptionally(e -> {
- context.packetHandler().disconnect(Component.translatable("neoforge.network.registries.sync.failed", e.getMessage()));
- return null;
- }).thenAccept(v -> {
- context.replyHandler().send(new FrozenRegistrySyncCompletedPayload());
- });
- }
-
- public void handle(ConfigFilePayload payload, IPayloadContext context) {
- ConfigSync.INSTANCE.receiveSyncedConfig(payload.contents(), payload.fileName());
- }
-
- public void handle(TierSortingRegistryPayload payload, IPayloadContext context) {
- TierSortingRegistry.handleSync(payload, context);
- }
+// public void handle(TierSortingRegistryPayload payload, IPayloadContext context) {
+// TierSortingRegistry.handleSync(payload, context);
+// }
public void handle(AdvancedOpenScreenPayload msg, PlayPayloadContext context) {
context.workHandler().submitAsync(() -> {
diff --git a/shearapi-network/src/client/java/net/pillowmc/shearapi/network/client/DualStackUtilsClient.java b/shearapi-network/src/client/java/net/pillowmc/shearapi/network/client/DualStackUtilsClient.java
new file mode 100644
index 0000000..d176779
--- /dev/null
+++ b/shearapi-network/src/client/java/net/pillowmc/shearapi/network/client/DualStackUtilsClient.java
@@ -0,0 +1,28 @@
+package net.pillowmc.shearapi.network.client;
+
+import net.minecraft.client.multiplayer.resolver.ResolvedServerAddress;
+import net.minecraft.client.multiplayer.resolver.ServerAddress;
+import net.minecraft.client.multiplayer.resolver.ServerNameResolver;
+import net.neoforged.neoforge.network.DualStackUtils;
+
+import java.net.InetSocketAddress;
+import java.util.Optional;
+
+public class DualStackUtilsClient {
+
+ /**
+ * Resolve the address and see if Java and the OS return an IPv6 or IPv4 one, then let Netty know
+ * accordingly (it doesn't understand the {@code java.net.preferIPv6Addresses=system} property).
+ *
+ * @param hostAddress The address you want to check
+ * @return true if IPv6, false if IPv4
+ */
+ public static boolean checkIPv6(final String hostAddress) {
+ final Optional hostAddr = ServerNameResolver.DEFAULT
+ .resolveAddress(ServerAddress.parseString(hostAddress))
+ .map(ResolvedServerAddress::asInetSocketAddress);
+
+ if (hostAddr.isPresent()) return DualStackUtils.checkIPv6(hostAddr.get().getAddress());
+ else return false;
+ }
+}
diff --git a/shearapi-network/src/client/java/net/pillowmc/shearapi/network/client/ShearAPINetworkClient.java b/shearapi-network/src/client/java/net/pillowmc/shearapi/network/client/ShearAPINetworkClient.java
index 61304d8..ce3653a 100644
--- a/shearapi-network/src/client/java/net/pillowmc/shearapi/network/client/ShearAPINetworkClient.java
+++ b/shearapi-network/src/client/java/net/pillowmc/shearapi/network/client/ShearAPINetworkClient.java
@@ -3,7 +3,6 @@
import net.fabricmc.api.ClientModInitializer;
import net.neoforged.neoforge.network.event.RegisterPayloadHandlerEvent;
import net.neoforged.neoforge.network.handlers.ClientPayloadHandler;
-import net.neoforged.neoforge.network.handlers.ServerPayloadHandler;
import net.neoforged.neoforge.network.payload.*;
import net.neoforged.neoforge.network.registration.IPayloadRegistrar;
import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
@@ -17,27 +16,14 @@ public void onInitializeClient() {
.versioned(ShearAPIVersion.getSpec())
.optional();
registrar
- .common(
- TierSortingRegistryPayload.ID,
- TierSortingRegistryPayload::new,
- handlers -> handlers.client(ClientPayloadHandler.getInstance()::handle))
- .configuration(
- FrozenRegistrySyncStartPayload.ID,
- FrozenRegistrySyncStartPayload::new,
- handlers -> handlers.client(ClientPayloadHandler.getInstance()::handle))
- .configuration(
- FrozenRegistryPayload.ID,
- FrozenRegistryPayload::new,
- handlers -> handlers.client(ClientPayloadHandler.getInstance()::handle))
- .configuration(
- FrozenRegistrySyncCompletedPayload.ID,
- FrozenRegistrySyncCompletedPayload::new,
- handlers -> handlers.client(ClientPayloadHandler.getInstance()::handle)
- .server(ServerPayloadHandler.getInstance()::handle))
- .configuration(
- TierSortingRegistrySyncCompletePayload.ID,
- TierSortingRegistrySyncCompletePayload::new,
- handlers -> handlers.server(ServerPayloadHandler.getInstance()::handle))
+// .common(
+// TierSortingRegistryPayload.ID,
+// TierSortingRegistryPayload::new,
+// handlers -> handlers.client(ClientPayloadHandler.getInstance()::handle))
+// .configuration(
+// TierSortingRegistrySyncCompletePayload.ID,
+// TierSortingRegistrySyncCompletePayload::new,
+// handlers -> handlers.server(ServerPayloadHandler.getInstance()::handle))
.play(
AdvancedOpenScreenPayload.ID,
AdvancedOpenScreenPayload::new,
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/ConfigurationInitialization.java b/shearapi-network/src/main/java/net/neoforged/neoforge/network/ConfigurationInitialization.java
index 5b2a00e..07f2be1 100644
--- a/shearapi-network/src/main/java/net/neoforged/neoforge/network/ConfigurationInitialization.java
+++ b/shearapi-network/src/main/java/net/neoforged/neoforge/network/ConfigurationInitialization.java
@@ -1,31 +1,21 @@
-/*
- * Copyright (c) NeoForged and contributors
- * SPDX-License-Identifier: LGPL-2.1-only
- */
-
-package net.neoforged.neoforge.network;
-
-import net.neoforged.bus.api.SubscribeEvent;
-import net.neoforged.neoforge.network.configuration.SyncRegistries;
-import net.neoforged.neoforge.network.configuration.SyncTierSortingRegistry;
-import net.neoforged.neoforge.network.event.OnGameConfigurationEvent;
-import net.neoforged.neoforge.network.payload.FrozenRegistryPayload;
-import net.neoforged.neoforge.network.payload.FrozenRegistrySyncCompletedPayload;
-import net.neoforged.neoforge.network.payload.FrozenRegistrySyncStartPayload;
-import org.jetbrains.annotations.ApiStatus;
-
-@ApiStatus.Internal
-public class ConfigurationInitialization {
- public static Class clazz = ConfigurationInitialization.class;
- @SubscribeEvent
- private static void configureModdedClient(OnGameConfigurationEvent event) {
- if (event.getListener().isConnected(FrozenRegistrySyncStartPayload.ID) &&
- event.getListener().isConnected(FrozenRegistryPayload.ID) &&
- event.getListener().isConnected(FrozenRegistrySyncCompletedPayload.ID)) {
- event.register(new SyncRegistries());
- }
-
- //These two can always be registered they detect the listener connection type internally and will skip themselves.
- event.register(new SyncTierSortingRegistry(event.getListener()));
- }
-}
+///*
+// * Copyright (c) NeoForged and contributors
+// * SPDX-License-Identifier: LGPL-2.1-only
+// */
+//
+//package net.neoforged.neoforge.network;
+//
+//import net.neoforged.bus.api.SubscribeEvent;
+//import net.neoforged.neoforge.network.configuration.SyncTierSortingRegistry;
+//import net.neoforged.neoforge.network.event.OnGameConfigurationEvent;
+//import org.jetbrains.annotations.ApiStatus;
+//
+//@ApiStatus.Internal
+//public class ConfigurationInitialization {
+// public static Class clazz = ConfigurationInitialization.class;
+// @SubscribeEvent
+// private static void configureModdedClient(OnGameConfigurationEvent event) {
+// //These two can always be registered they detect the listener connection type internally and will skip themselves.
+// event.register(new SyncTierSortingRegistry(event.getListener()));
+// }
+//}
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/DualStackUtils.java b/shearapi-network/src/main/java/net/neoforged/neoforge/network/DualStackUtils.java
index 40ce896..5f18564 100644
--- a/shearapi-network/src/main/java/net/neoforged/neoforge/network/DualStackUtils.java
+++ b/shearapi-network/src/main/java/net/neoforged/neoforge/network/DualStackUtils.java
@@ -13,13 +13,8 @@
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
-import java.util.Optional;
import javax.annotation.Nullable;
-import net.minecraft.client.multiplayer.resolver.ResolvedServerAddress;
-import net.minecraft.client.multiplayer.resolver.ServerAddress;
-import net.minecraft.client.multiplayer.resolver.ServerNameResolver;
import net.minecraft.util.HttpUtil;
-import net.neoforged.neoforge.common.NeoForge;
import org.jetbrains.annotations.ApiStatus;
import org.slf4j.Logger;
@@ -37,22 +32,6 @@ public class DualStackUtils {
@ApiStatus.Internal
public static void initialise() {}
- /**
- * Resolve the address and see if Java and the OS return an IPv6 or IPv4 one, then let Netty know
- * accordingly (it doesn't understand the {@code java.net.preferIPv6Addresses=system} property).
- *
- * @param hostAddress The address you want to check
- * @return true if IPv6, false if IPv4
- */
- public static boolean checkIPv6(final String hostAddress) {
- final Optional hostAddr = ServerNameResolver.DEFAULT
- .resolveAddress(ServerAddress.parseString(hostAddress))
- .map(ResolvedServerAddress::asInetSocketAddress);
-
- if (hostAddr.isPresent()) return checkIPv6(hostAddr.get().getAddress());
- else return false;
- }
-
/**
* Checks if an address is an IPv6 one or an IPv4 one, lets Netty know accordingly and returns the result.
*
@@ -123,7 +102,7 @@ public static InetAddress getLocalAddress() {
/**
* Used for the "Open to LAN" feature.
- *
+ *
* @return The multicast group to use for LAN discovery - IPv6 if available, IPv4 otherwise.
*/
public static String getMulticastGroup() {
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/PacketDistributor.java b/shearapi-network/src/main/java/net/neoforged/neoforge/network/PacketDistributor.java
index e6d404c..ecb9f8f 100644
--- a/shearapi-network/src/main/java/net/neoforged/neoforge/network/PacketDistributor.java
+++ b/shearapi-network/src/main/java/net/neoforged/neoforge/network/PacketDistributor.java
@@ -12,7 +12,6 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
-import net.minecraft.client.Minecraft;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.PacketFlow;
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
@@ -27,7 +26,9 @@
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.LevelChunk;
+import net.pillowmc.shearapi.utils.IClientLike;
import net.pillowmc.shearapi.utils.ServerUtils;
+import net.pillowmc.shearapi.utils.Utils;
/**
* Means to distribute packets in various ways
@@ -111,7 +112,7 @@ public TargetPoint(final ServerPlayer excluded, final double x, final double y,
/**
* A target point without excluded entity
- *
+ *
* @param x X
* @param y Y
* @param z Z
@@ -129,7 +130,7 @@ public TargetPoint(final double x, final double y, final double z, final double
/**
* Helper to build a TargetPoint without excluded Entity
- *
+ *
* @param x X
* @param y Y
* @param z Z
@@ -167,7 +168,7 @@ public void send(CustomPacketPayload... payloads) {
for (CustomPacketPayload payload : payloads) {
packets.add(new ClientboundCustomPayloadPacket(payload));
}
- this.send(new ClientboundBundlePacket(packets));
+ this.send(new ClientboundBundlePacket((Iterable>)(Object) packets));
} else if (payloads.length == 1) {
this.send(new ClientboundCustomPayloadPacket(payloads[0]));
}
@@ -197,7 +198,7 @@ public PacketDistributor(Function, Consumer>> fun
/**
* Apply the supplied value to the specific distributor to generate an instance for sending packets to.
- *
+ *
* @param input The input to apply
* @return A curried instance
*/
@@ -229,7 +230,7 @@ private Consumer> playerListAll() {
}
private Consumer> clientToServer() {
- return p -> Objects.requireNonNull(Minecraft.getInstance().getConnection()).send(p);
+ return p -> Utils.getClient().ifPresent(c -> c.shearAPI$sendPacket(p));
}
private Consumer> playerListPointConsumer(final TargetPoint targetPoint) {
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/configuration/SyncTierSortingRegistry.java b/shearapi-network/src/main/java/net/neoforged/neoforge/network/configuration/SyncTierSortingRegistry.java
index d6e8d5f..8a8e03f 100644
--- a/shearapi-network/src/main/java/net/neoforged/neoforge/network/configuration/SyncTierSortingRegistry.java
+++ b/shearapi-network/src/main/java/net/neoforged/neoforge/network/configuration/SyncTierSortingRegistry.java
@@ -1,35 +1,35 @@
-/*
- * Copyright (c) NeoForged and contributors
- * SPDX-License-Identifier: LGPL-2.1-only
- */
-
-package net.neoforged.neoforge.network.configuration;
-
-import java.util.function.Consumer;
-import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
-import net.minecraft.network.protocol.configuration.ServerConfigurationPacketListener;
-import net.minecraft.resources.ResourceLocation;
-import net.neoforged.neoforge.common.TierSortingRegistry;
-import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
-import org.jetbrains.annotations.ApiStatus;
-
-/**
- * Syncs the tier sorting registry to the client
- *
- * @param listener the listener to indicate the check if it is a vanilla connection
- */
-@ApiStatus.Internal
-public record SyncTierSortingRegistry(ServerConfigurationPacketListener listener) implements ICustomConfigurationTask {
- private static final ResourceLocation ID = new ResourceLocation(ShearAPIRuntime.MOD_ID, "sync_tier_sorting");
- public static final Type TYPE = new Type(ID);
-
- @Override
- public void run(Consumer sender) {
- TierSortingRegistry.sync(listener(), sender);
- }
-
- @Override
- public Type type() {
- return TYPE;
- }
-}
+///*
+// * Copyright (c) NeoForged and contributors
+// * SPDX-License-Identifier: LGPL-2.1-only
+// */
+//
+//package net.neoforged.neoforge.network.configuration;
+//
+//import java.util.function.Consumer;
+//import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
+//import net.minecraft.network.protocol.configuration.ServerConfigurationPacketListener;
+//import net.minecraft.resources.ResourceLocation;
+//import net.neoforged.neoforge.common.TierSortingRegistry;
+//import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
+//import org.jetbrains.annotations.ApiStatus;
+//
+///**
+// * Syncs the tier sorting registry to the client
+// *
+// * @param listener the listener to indicate the check if it is a vanilla connection
+// */
+//@ApiStatus.Internal
+//public record SyncTierSortingRegistry(ServerConfigurationPacketListener listener) implements ICustomConfigurationTask {
+// private static final ResourceLocation ID = new ResourceLocation(ShearAPIRuntime.MOD_ID, "sync_tier_sorting");
+// public static final Type TYPE = new Type(ID.toString());
+//
+// @Override
+// public void run(Consumer sender) {
+// TierSortingRegistry.sync(listener(), sender);
+// }
+//
+// @Override
+// public Type type() {
+// return TYPE;
+// }
+//}
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/filters/GenericPacketSplitter.java b/shearapi-network/src/main/java/net/neoforged/neoforge/network/filters/GenericPacketSplitter.java
index b02ef66..17ddcb2 100644
--- a/shearapi-network/src/main/java/net/neoforged/neoforge/network/filters/GenericPacketSplitter.java
+++ b/shearapi-network/src/main/java/net/neoforged/neoforge/network/filters/GenericPacketSplitter.java
@@ -27,7 +27,6 @@
import net.minecraft.network.protocol.common.ClientboundCustomPayloadPacket;
import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket;
import net.neoforged.bus.api.SubscribeEvent;
-import net.neoforged.fml.common.Mod;
import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
import net.neoforged.neoforge.network.connection.ConnectionPhase;
import net.neoforged.neoforge.network.connection.ConnectionType;
@@ -43,9 +42,9 @@
/**
* A generic packet splitter that can be used to split packets that are too large to be sent in one go.
*/
-@Mod.EventBusSubscriber(modid = ShearAPIRuntime.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
@ApiStatus.Internal
public class GenericPacketSplitter extends MessageToMessageEncoder> implements DynamicChannelHandler {
+ public static Class clazz = GenericPacketSplitter.class;
private static final Logger LOGGER = LogManager.getLogger();
private static final int MAX_PACKET_SIZE = CompressionDecoder.MAXIMUM_UNCOMPRESSED_LENGTH;
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/filters/VanillaConnectionNetworkFilter.java b/shearapi-network/src/main/java/net/neoforged/neoforge/network/filters/VanillaConnectionNetworkFilter.java
index 2885b07..aa3b5ae 100644
--- a/shearapi-network/src/main/java/net/neoforged/neoforge/network/filters/VanillaConnectionNetworkFilter.java
+++ b/shearapi-network/src/main/java/net/neoforged/neoforge/network/filters/VanillaConnectionNetworkFilter.java
@@ -9,9 +9,12 @@
import com.mojang.brigadier.tree.RootCommandNode;
import com.mojang.logging.LogUtils;
import io.netty.channel.ChannelHandler;
+
+import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import net.minecraft.commands.CommandBuildContext;
@@ -33,7 +36,7 @@
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagNetworkSerialization;
import net.neoforged.neoforge.network.connection.ConnectionType;
-import net.neoforged.neoforge.registries.RegistryManager;
+import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
import org.slf4j.Logger;
/**
@@ -51,7 +54,7 @@ public VanillaConnectionNetworkFilter(ConnectionType connectionType) {
ImmutableMap.>, BiConsumer, List super Packet>>>>builder()
.put(handler(ClientboundUpdateAttributesPacket.class, VanillaConnectionNetworkFilter::filterEntityProperties))
.put(handler(ClientboundCommandsPacket.class, VanillaConnectionNetworkFilter::filterCommandList))
- .put(handler(ClientboundUpdateTagsPacket.class, VanillaConnectionNetworkFilter::filterCustomTagTypes))
+ .putAll(getFilterCustomTagTypes().stream().toList())
.build());
this.connectionType = connectionType;
@@ -95,6 +98,11 @@ private static ClientboundCommandsPacket filterCommandList(ClientboundCommandsPa
return new ClientboundCommandsPacket(newRoot);
}
+ private static Optional>, BiConsumer, List super Packet>>>>> getFilterCustomTagTypes() {
+ if (!ShearAPIRuntime.getRuntime().isModLoaded("shearapi-registries")) return Optional.empty();
+ return Optional.of(handler(ClientboundUpdateTagsPacket.class, VanillaConnectionNetworkFilter::filterCustomTagTypes));
+ }
+
/**
* Filters out custom tag types that the vanilla client won't recognize.
* It prevents a rare error from logging and reduces the packet size
@@ -107,8 +115,12 @@ private static ClientboundUpdateTagsPacket filterCustomTagTypes(ClientboundUpdat
}
private static boolean isVanillaRegistry(ResourceLocation location) {
- // Checks if the registry name is contained within the static view of both BuiltInRegistries and VanillaRegistries
- return RegistryManager.getVanillaRegistryKeys().contains(location)
- || VanillaRegistries.DATAPACK_REGISTRY_KEYS.stream().anyMatch(k -> k.location().equals(location));
+ try {
+ return (Boolean)Class.forName("net.pillowmc.shearapi.registries.ShearAPIRegistries")
+ .getMethod("isVanillaRegistry", ResourceLocation.class)
+ .invoke(null, location);
+ } catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException | InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
}
}
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/handlers/ServerPayloadHandler.java b/shearapi-network/src/main/java/net/neoforged/neoforge/network/handlers/ServerPayloadHandler.java
index ee1d298..572871c 100644
--- a/shearapi-network/src/main/java/net/neoforged/neoforge/network/handlers/ServerPayloadHandler.java
+++ b/shearapi-network/src/main/java/net/neoforged/neoforge/network/handlers/ServerPayloadHandler.java
@@ -1,32 +1,26 @@
-/*
- * Copyright (c) NeoForged and contributors
- * SPDX-License-Identifier: LGPL-2.1-only
- */
-
-package net.neoforged.neoforge.network.handlers;
-
-import net.neoforged.neoforge.network.configuration.SyncRegistries;
-import net.neoforged.neoforge.network.configuration.SyncTierSortingRegistry;
-import net.neoforged.neoforge.network.handling.ConfigurationPayloadContext;
-import net.neoforged.neoforge.network.payload.FrozenRegistrySyncCompletedPayload;
-import net.neoforged.neoforge.network.payload.TierSortingRegistrySyncCompletePayload;
-import org.jetbrains.annotations.ApiStatus;
-
-@ApiStatus.Internal
-public class ServerPayloadHandler {
- private static final ServerPayloadHandler INSTANCE = new ServerPayloadHandler();
-
- public static ServerPayloadHandler getInstance() {
- return INSTANCE;
- }
-
- private ServerPayloadHandler() {}
-
- public void handle(FrozenRegistrySyncCompletedPayload payload, ConfigurationPayloadContext context) {
- context.taskCompletedHandler().onTaskCompleted(SyncRegistries.TYPE);
- }
-
- public void handle(TierSortingRegistrySyncCompletePayload payload, ConfigurationPayloadContext context) {
- context.taskCompletedHandler().onTaskCompleted(SyncTierSortingRegistry.TYPE);
- }
-}
+///*
+// * Copyright (c) NeoForged and contributors
+// * SPDX-License-Identifier: LGPL-2.1-only
+// */
+//
+//package net.neoforged.neoforge.network.handlers;
+//
+//import net.neoforged.neoforge.network.configuration.SyncTierSortingRegistry;
+//import net.neoforged.neoforge.network.handling.ConfigurationPayloadContext;
+//import net.neoforged.neoforge.network.payload.TierSortingRegistrySyncCompletePayload;
+//import org.jetbrains.annotations.ApiStatus;
+//
+//@ApiStatus.Internal
+//public class ServerPayloadHandler {
+// private static final ServerPayloadHandler INSTANCE = new ServerPayloadHandler();
+//
+// public static ServerPayloadHandler getInstance() {
+// return INSTANCE;
+// }
+//
+// private ServerPayloadHandler() {}
+//
+// public void handle(TierSortingRegistrySyncCompletePayload payload, ConfigurationPayloadContext context) {
+// context.taskCompletedHandler().onTaskCompleted(SyncTierSortingRegistry.TYPE);
+// }
+//}
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/negotiation/NetworkComponentNegotiator.java b/shearapi-network/src/main/java/net/neoforged/neoforge/network/negotiation/NetworkComponentNegotiator.java
index 15abfda..6ea9ad0 100644
--- a/shearapi-network/src/main/java/net/neoforged/neoforge/network/negotiation/NetworkComponentNegotiator.java
+++ b/shearapi-network/src/main/java/net/neoforged/neoforge/network/negotiation/NetworkComponentNegotiator.java
@@ -14,7 +14,7 @@
import java.util.Optional;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
-import net.neoforged.fml.ModList;
+import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.VisibleForTesting;
@@ -80,7 +80,7 @@ public static NegotiationResult negotiate(List serve
final Map failureReasons = new HashMap<>();
client.forEach(c -> {
Component channelFailureReason = Component.translatable("neoforge.network.negotiation.failure.missing.client.server");
- String modDisplayName = ModList.get().getModContainerById(c.id().getNamespace()).map(mc -> mc.getModInfo().getDisplayName()).orElse("");
+ String modDisplayName = ShearAPIRuntime.getRuntime().getModDisplayName(c.id().getNamespace()).orElse("");
failureReasons.put(c.id(), modDisplayName.isEmpty() ? channelFailureReason : Component.translatable("neoforge.network.negotiation.failure.mod", modDisplayName, channelFailureReason));
});
return new NegotiationResult(List.of(), false, failureReasons);
@@ -90,7 +90,7 @@ public static NegotiationResult negotiate(List serve
final Map failureReasons = new HashMap<>();
server.forEach(c -> {
Component channelFailureReason = Component.translatable("neoforge.network.negotiation.failure.missing.server.client");
- String modDisplayName = ModList.get().getModContainerById(c.id().getNamespace()).map(mc -> mc.getModInfo().getDisplayName()).orElse("");
+ String modDisplayName = ShearAPIRuntime.getRuntime().getModDisplayName(c.id().getNamespace()).orElse("");
failureReasons.put(c.id(), modDisplayName.isEmpty() ? channelFailureReason : Component.translatable("neoforge.network.negotiation.failure.mod", modDisplayName, channelFailureReason));
});
return new NegotiationResult(List.of(), false, failureReasons);
@@ -101,7 +101,7 @@ public static NegotiationResult negotiate(List serve
for (Table.Cell match : matches.cellSet()) {
final NegotiableNetworkComponent serverComponent = match.getColumnKey();
final NegotiableNetworkComponent clientComponent = match.getValue();
- final String modDisplayName = ModList.get().getModContainerById(serverComponent.id().getNamespace()).map(mc -> mc.getModInfo().getDisplayName()).orElse("");
+ String modDisplayName = ShearAPIRuntime.getRuntime().getModDisplayName(serverComponent.id().getNamespace()).orElse("");
Optional serverToClientComparison = validateComponent(serverComponent, clientComponent, "client");
if (serverToClientComparison.isPresent() && !serverToClientComparison.get().success()) {
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/payload/TierSortingRegistryPayload.java b/shearapi-network/src/main/java/net/neoforged/neoforge/network/payload/TierSortingRegistryPayload.java
index da71f81..f1f2c2f 100644
--- a/shearapi-network/src/main/java/net/neoforged/neoforge/network/payload/TierSortingRegistryPayload.java
+++ b/shearapi-network/src/main/java/net/neoforged/neoforge/network/payload/TierSortingRegistryPayload.java
@@ -1,40 +1,40 @@
-/*
- * Copyright (c) NeoForged and contributors
- * SPDX-License-Identifier: LGPL-2.1-only
- */
-
-package net.neoforged.neoforge.network.payload;
-
-import java.util.List;
-import net.minecraft.network.FriendlyByteBuf;
-import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
-import net.minecraft.resources.ResourceLocation;
-import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
-import org.jetbrains.annotations.ApiStatus;
-
-/**
- * The payload for the tier sorting registry packet.
- *
- * This payload is used to send the tier order to the client.
- *
- *
- * @param tiers The tiers in order.
- */
-@ApiStatus.Internal
-public record TierSortingRegistryPayload(List tiers) implements CustomPacketPayload {
- public static final ResourceLocation ID = new ResourceLocation(ShearAPIRuntime.MOD_ID, "tier_sorting");
-
- public TierSortingRegistryPayload(FriendlyByteBuf buf) {
- this(buf.readList(FriendlyByteBuf::readResourceLocation));
- }
-
- @Override
- public void write(FriendlyByteBuf buf) {
- buf.writeCollection(tiers(), FriendlyByteBuf::writeResourceLocation);
- }
-
- @Override
- public ResourceLocation id() {
- return ID;
- }
-}
+///*
+// * Copyright (c) NeoForged and contributors
+// * SPDX-License-Identifier: LGPL-2.1-only
+// */
+//
+//package net.neoforged.neoforge.network.payload;
+//
+//import java.util.List;
+//import net.minecraft.network.FriendlyByteBuf;
+//import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
+//import net.minecraft.resources.ResourceLocation;
+//import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
+//import org.jetbrains.annotations.ApiStatus;
+//
+///**
+// * The payload for the tier sorting registry packet.
+// *
+// * This payload is used to send the tier order to the client.
+// *
+// *
+// * @param tiers The tiers in order.
+// */
+//@ApiStatus.Internal
+//public record TierSortingRegistryPayload(List tiers) implements CustomPacketPayload {
+// public static final ResourceLocation ID = new ResourceLocation(ShearAPIRuntime.MOD_ID, "tier_sorting");
+//
+// public TierSortingRegistryPayload(FriendlyByteBuf buf) {
+// this(buf.readList(FriendlyByteBuf::readResourceLocation));
+// }
+//
+// @Override
+// public void write(FriendlyByteBuf buf) {
+// buf.writeCollection(tiers(), FriendlyByteBuf::writeResourceLocation);
+// }
+//
+// @Override
+// public ResourceLocation id() {
+// return ID;
+// }
+//}
diff --git a/shearapi-network/src/main/java/net/neoforged/neoforge/network/payload/TierSortingRegistrySyncCompletePayload.java b/shearapi-network/src/main/java/net/neoforged/neoforge/network/payload/TierSortingRegistrySyncCompletePayload.java
index 19fd02c..4d4c81f 100644
--- a/shearapi-network/src/main/java/net/neoforged/neoforge/network/payload/TierSortingRegistrySyncCompletePayload.java
+++ b/shearapi-network/src/main/java/net/neoforged/neoforge/network/payload/TierSortingRegistrySyncCompletePayload.java
@@ -1,32 +1,32 @@
-/*
- * Copyright (c) NeoForged and contributors
- * SPDX-License-Identifier: LGPL-2.1-only
- */
-
-package net.neoforged.neoforge.network.payload;
-
-import net.minecraft.network.FriendlyByteBuf;
-import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
-import net.minecraft.resources.ResourceLocation;
-import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
-import org.jetbrains.annotations.ApiStatus;
-
-/**
- * This payload is sent by the server to the client when the tier sorting registry has been fully synced.
- */
-@ApiStatus.Internal
-public record TierSortingRegistrySyncCompletePayload() implements CustomPacketPayload {
- public static final ResourceLocation ID = new ResourceLocation(ShearAPIRuntime.MOD_ID, "tier_sorting_registry_sync_complete");
-
- public TierSortingRegistrySyncCompletePayload(FriendlyByteBuf buf) {
- this();
- }
-
- @Override
- public void write(FriendlyByteBuf buf) {}
-
- @Override
- public ResourceLocation id() {
- return ID;
- }
-}
+///*
+// * Copyright (c) NeoForged and contributors
+// * SPDX-License-Identifier: LGPL-2.1-only
+// */
+//
+//package net.neoforged.neoforge.network.payload;
+//
+//import net.minecraft.network.FriendlyByteBuf;
+//import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
+//import net.minecraft.resources.ResourceLocation;
+//import net.pillowmc.shearapi.runtime.ShearAPIRuntime;
+//import org.jetbrains.annotations.ApiStatus;
+//
+///**
+// * This payload is sent by the server to the client when the tier sorting registry has been fully synced.
+// */
+//@ApiStatus.Internal
+//public record TierSortingRegistrySyncCompletePayload() implements CustomPacketPayload {
+// public static final ResourceLocation ID = new ResourceLocation(ShearAPIRuntime.MOD_ID, "tier_sorting_registry_sync_complete");
+//
+// public TierSortingRegistrySyncCompletePayload(FriendlyByteBuf buf) {
+// this();
+// }
+//
+// @Override
+// public void write(FriendlyByteBuf buf) {}
+//
+// @Override
+// public ResourceLocation id() {
+// return ID;
+// }
+//}
diff --git a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerGamePacketListenerExtension.java b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerGamePacketListenerExtension.java
index 5582cd1..82478a7 100644
--- a/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerGamePacketListenerExtension.java
+++ b/shearapi-network/src/main/java/net/pillowmc/shearapi/network/injection/IServerGamePacketListenerExtension.java
@@ -45,6 +45,6 @@ default void sendBundled(Iterable payloads) {
packets.add(new ClientboundCustomPayloadPacket(payload));
}
- self().send(new ClientboundBundlePacket(packets));
+ self().send(new ClientboundBundlePacket((List>)(Object) packets));
}
}
diff --git a/shearapi-network/src/main/resources/fabric.mod.json b/shearapi-network/src/main/resources/fabric.mod.json
index 446dd9e..af7b157 100644
--- a/shearapi-network/src/main/resources/fabric.mod.json
+++ b/shearapi-network/src/main/resources/fabric.mod.json
@@ -25,7 +25,9 @@
"accessWidener": "shearapi-network.accesswidener",
"entrypoints": {
"client": ["net.pillowmc.shearapi.network.client.ShearAPINetworkClient"],
- "shearapi-runtime:mod_bus_subscriber": ["net.neoforged.neoforge.network.ConfigurationInitialization::clazz"]
+ "shearapi-runtime:mod_bus_subscriber": [
+ "net.neoforged.neoforge.network.filters.GenericPacketSplitter::clazz"
+ ]
},
"mixins": ["shearapi-network.mixins.json"],
"custom": {
diff --git a/shearapi-registries/src/main/java/net/neoforged/neoforge/registries/RegistryManager.java b/shearapi-registries/src/main/java/net/neoforged/neoforge/registries/RegistryManager.java
index 832070b..32b1eec 100644
--- a/shearapi-registries/src/main/java/net/neoforged/neoforge/registries/RegistryManager.java
+++ b/shearapi-registries/src/main/java/net/neoforged/neoforge/registries/RegistryManager.java
@@ -232,9 +232,9 @@ public static void postNewRegistryEvent() {
// return list;
// }
//
-// public static Set getVanillaRegistryKeys() {
-// return vanillaRegistryKeys;
-// }
+ public static Set getVanillaRegistryKeys() {
+ return vanillaRegistryKeys;
+ }
public enum SnapshotType {
/**
diff --git a/shearapi-registries/src/main/java/net/pillowmc/shearapi/registries/ShearAPIRegistries.java b/shearapi-registries/src/main/java/net/pillowmc/shearapi/registries/ShearAPIRegistries.java
index 659d1d2..775633b 100644
--- a/shearapi-registries/src/main/java/net/pillowmc/shearapi/registries/ShearAPIRegistries.java
+++ b/shearapi-registries/src/main/java/net/pillowmc/shearapi/registries/ShearAPIRegistries.java
@@ -2,7 +2,12 @@
import com.chocohead.mm.api.ClassTinkerers;
import net.fabricmc.api.ModInitializer;
+import net.minecraft.core.Registry;
+import net.minecraft.core.RegistrySetBuilder;
import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.data.registries.VanillaRegistries;
+import net.minecraft.resources.ResourceKey;
+import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraft.world.level.levelgen.DebugLevelSource;
import net.neoforged.neoforge.registries.GameData;
@@ -11,11 +16,13 @@
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodInsnNode;
+import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
public class ShearAPIRegistries implements ModInitializer {
+ private static final List extends ResourceKey extends Registry>>> VANILLA_REGISTRIES_DATAPACK_REGISTRY_KEYS = VanillaRegistries.BUILDER.entries.stream().map(RegistrySetBuilder.RegistryStub::key).toList()
@Override
public void onInitialize() {
RegistryManager.postNewRegistryEvent();
@@ -27,4 +34,10 @@ public static void initValidStatesInDebugLevelSource() {
DebugLevelSource.GRID_WIDTH = Mth.ceil(Mth.sqrt(DebugLevelSource.ALL_BLOCKS.size()));
DebugLevelSource.GRID_HEIGHT = Mth.ceil((float)DebugLevelSource.ALL_BLOCKS.size() / (float)DebugLevelSource.GRID_WIDTH);
}
+
+ public static boolean isVanillaRegistry(ResourceLocation location) {
+ // Checks if the registry name is contained within the static view of both BuiltInRegistries and VanillaRegistries
+ return RegistryManager.getVanillaRegistryKeys().contains(location)
+ || VANILLA_REGISTRIES_DATAPACK_REGISTRY_KEYS.stream().anyMatch(k -> k.location().equals(location));
+ }
}
diff --git a/shearapi-registries/src/main/resources/shearapi-registries.accesswidener b/shearapi-registries/src/main/resources/shearapi-registries.accesswidener
index eb018c2..9f2f379 100644
--- a/shearapi-registries/src/main/resources/shearapi-registries.accesswidener
+++ b/shearapi-registries/src/main/resources/shearapi-registries.accesswidener
@@ -13,3 +13,6 @@ mutable field net/minecraft/world/level/levelgen/DebugLevelSource GRID_HEIGHT I
#accessible class net/minecraft/core/RegistrySynchronization$NetworkedRegistryData
accessible method net/minecraft/core/RegistrySynchronization$NetworkedRegistryData (Lnet/minecraft/resources/ResourceKey;Lcom/mojang/serialization/Codec;)V
accessible method net/minecraft/core/Holder$Reference bindValue (Ljava/lang/Object;)V
+accessible field net/minecraft/core/RegistrySetBuilder entries Ljava/util/List;
+accessible class net/minecraft/core/RegistrySetBuilder$RegistryStub
+accessible field net/minecraft/data/registries/VanillaRegistries BUILDER Lnet/minecraft/core/RegistrySetBuilder;
diff --git a/shearapi-runtime/src/main/java/net/pillowmc/shearapi/runtime/IRuntime.java b/shearapi-runtime/src/main/java/net/pillowmc/shearapi/runtime/IRuntime.java
index 215cbe9..aa030de 100644
--- a/shearapi-runtime/src/main/java/net/pillowmc/shearapi/runtime/IRuntime.java
+++ b/shearapi-runtime/src/main/java/net/pillowmc/shearapi/runtime/IRuntime.java
@@ -3,6 +3,8 @@
import net.neoforged.bus.api.Event;
import net.neoforged.bus.api.IEventBus;
+import java.util.Optional;
+
public interface IRuntime {
boolean isLoadingStateVaild();
boolean isProduction();
@@ -10,4 +12,5 @@ public interface IRuntime {
void postModBusEvent(T event);
IEventBus getModBus();
boolean isModLoaded(String modid);
+ Optional getModDisplayName(String modid);
}
diff --git a/shearapi-utils/src/client/java/net/pillowmc/shearapi/utils/mixin/client/MinecraftMixin.java b/shearapi-utils/src/client/java/net/pillowmc/shearapi/utils/mixin/client/MinecraftMixin.java
index babb386..508f73c 100644
--- a/shearapi-utils/src/client/java/net/pillowmc/shearapi/utils/mixin/client/MinecraftMixin.java
+++ b/shearapi-utils/src/client/java/net/pillowmc/shearapi/utils/mixin/client/MinecraftMixin.java
@@ -2,17 +2,32 @@
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
+import net.minecraft.client.multiplayer.ClientPacketListener;
+import net.minecraft.network.Connection;
+import net.minecraft.network.protocol.Packet;
import net.minecraft.world.level.Level;
import net.pillowmc.shearapi.utils.IClientLike;
+import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
+import java.util.Objects;
+
@Mixin(Minecraft.class)
-public class MinecraftMixin implements IClientLike {
+public abstract class MinecraftMixin implements IClientLike {
@Shadow
public ClientLevel level;
+ @Shadow
+ @Nullable
+ public abstract ClientPacketListener getConnection();
+
+ @Override
+ public void shearAPI$sendPacket(Packet> packet) {
+ Objects.requireNonNull(this.getConnection()).send(packet);
+ }
+
@Override
public Level shearAPI$getClientLevel() {
return level;
diff --git a/shearapi-utils/src/client/java/net/pillowmc/shearapi/utils/mixin/client/UtilsMixin.java b/shearapi-utils/src/client/java/net/pillowmc/shearapi/utils/mixin/client/UtilsMixin.java
new file mode 100644
index 0000000..768276d
--- /dev/null
+++ b/shearapi-utils/src/client/java/net/pillowmc/shearapi/utils/mixin/client/UtilsMixin.java
@@ -0,0 +1,21 @@
+package net.pillowmc.shearapi.utils.mixin.client;
+
+import net.minecraft.client.Minecraft;
+import net.pillowmc.shearapi.utils.IClientLike;
+import net.pillowmc.shearapi.utils.Utils;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Overwrite;
+
+import java.util.Optional;
+
+@Mixin(value = Utils.class, remap = false)
+public class UtilsMixin {
+ /**
+ * @author heipiao233
+ * @reason Get client.
+ */
+ @Overwrite
+ public static Optional getClient() {
+ return Optional.of((IClientLike) Minecraft.getInstance());
+ }
+}
diff --git a/shearapi-utils/src/client/resources/shearapi-utils.client.mixin.json b/shearapi-utils/src/client/resources/shearapi-utils.client.mixin.json
index 448e531..c33c70a 100644
--- a/shearapi-utils/src/client/resources/shearapi-utils.client.mixin.json
+++ b/shearapi-utils/src/client/resources/shearapi-utils.client.mixin.json
@@ -7,5 +7,8 @@
],
"injectors": {
"defaultRequire": 1
- }
+ },
+ "mixins": [
+ "client.UtilsMixin"
+ ]
}
diff --git a/shearapi-utils/src/main/java/net/pillowmc/shearapi/utils/IClientLike.java b/shearapi-utils/src/main/java/net/pillowmc/shearapi/utils/IClientLike.java
index a892ade..a24e4d9 100644
--- a/shearapi-utils/src/main/java/net/pillowmc/shearapi/utils/IClientLike.java
+++ b/shearapi-utils/src/main/java/net/pillowmc/shearapi/utils/IClientLike.java
@@ -1,12 +1,14 @@
package net.pillowmc.shearapi.utils;
+import net.minecraft.network.protocol.Packet;
import net.minecraft.server.TickTask;
import net.minecraft.util.thread.BlockableEventLoop;
import net.minecraft.world.level.Level;
public interface IClientLike {
Level shearAPI$getClientLevel();
+ void shearAPI$sendPacket(Packet> packet);
default BlockableEventLoop super TickTask> intoBlockableEventLoop() {
- return (BlockableEventLoop super TickTask>)(Object) this;
+ return (BlockableEventLoop super TickTask>) this;
}
}
diff --git a/shearapi-utils/src/main/java/net/pillowmc/shearapi/utils/Utils.java b/shearapi-utils/src/main/java/net/pillowmc/shearapi/utils/Utils.java
index 2eaee39..8fd0ec1 100644
--- a/shearapi-utils/src/main/java/net/pillowmc/shearapi/utils/Utils.java
+++ b/shearapi-utils/src/main/java/net/pillowmc/shearapi/utils/Utils.java
@@ -10,4 +10,8 @@ public enum Utils {;
public static Optional> getItemHolder(Item item) {
return BuiltInRegistries.ITEM.getResourceKey(item).flatMap(BuiltInRegistries.ITEM::getHolder);
}
+
+ public static Optional getClient() {
+ return Optional.empty();
+ }
}
diff --git a/shearapi-withoutpillow/src/main/java/net/pillowmc/shearapi/withoutpillow/ShearAPIWithoutPillow.java b/shearapi-withoutpillow/src/main/java/net/pillowmc/shearapi/withoutpillow/ShearAPIWithoutPillow.java
index 013d570..262d68f 100644
--- a/shearapi-withoutpillow/src/main/java/net/pillowmc/shearapi/withoutpillow/ShearAPIWithoutPillow.java
+++ b/shearapi-withoutpillow/src/main/java/net/pillowmc/shearapi/withoutpillow/ShearAPIWithoutPillow.java
@@ -7,6 +7,8 @@
import net.pillowmc.shearapi.runtime.IModBusEvent;
import net.pillowmc.shearapi.runtime.IRuntime;
+import java.util.Optional;
+
public class ShearAPIWithoutPillow implements IRuntime {
private final IEventBus MODBUS = BusBuilder.builder().markerType(IModBusEvent.class).build();
@@ -39,4 +41,9 @@ public void postModBusEvent(T event) {
public boolean isModLoaded(String modid) {
return FabricLoader.getInstance().isModLoaded(modid);
}
+
+ @Override
+ public Optional getModDisplayName(String modid) {
+ return FabricLoader.getInstance().getModContainer(modid).map(m -> m.getMetadata().getName());
+ }
}
diff --git a/shearapi-withpillow/src/main/java/net/pillowmc/shearapi/withpillow/ShearAPIWithPillow.java b/shearapi-withpillow/src/main/java/net/pillowmc/shearapi/withpillow/ShearAPIWithPillow.java
index 0676729..f1caaca 100644
--- a/shearapi-withpillow/src/main/java/net/pillowmc/shearapi/withpillow/ShearAPIWithPillow.java
+++ b/shearapi-withpillow/src/main/java/net/pillowmc/shearapi/withpillow/ShearAPIWithPillow.java
@@ -1,5 +1,6 @@
package net.pillowmc.shearapi.withpillow;
+import net.fabricmc.loader.api.FabricLoader;
import net.neoforged.bus.api.Event;
import net.neoforged.fml.ModList;
import net.neoforged.fml.ModLoader;
@@ -7,6 +8,8 @@
import net.pillowmc.shearapi.runtime.IModBusEvent;
import net.pillowmc.shearapi.withoutpillow.ShearAPIWithoutPillow;
+import java.util.Optional;
+
public class ShearAPIWithPillow extends ShearAPIWithoutPillow {
@Override
@@ -39,4 +42,11 @@ public void postModBusEvent(T event) {
public boolean isModLoaded(String modid) {
return ModList.get().isLoaded(modid);
}
+
+
+ @Override
+ public Optional getModDisplayName(String modid) {
+ return super.getModDisplayName(modid)
+ .or(() -> ModList.get().getModContainerById(modid).map(m -> m.getModInfo().getDisplayName()));
+ }
}