diff --git a/libraries/networking/networking-client-mcb1.0-mcb1.4_01/build.gradle b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/build.gradle new file mode 100644 index 00000000..1b28a68b --- /dev/null +++ b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/build.gradle @@ -0,0 +1,4 @@ +setUpModule(project, + 'entrypoints-client-mca1.0.6-mc12w30e', + 'lifecycle-events-client-mcb1.3-1750-mcb1.7.3' +) diff --git a/libraries/networking/networking-client-mcb1.0-mcb1.4_01/gradle.properties b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/gradle.properties new file mode 100644 index 00000000..46bbb243 --- /dev/null +++ b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/gradle.properties @@ -0,0 +1,7 @@ +environment = client +min_mc_version = b1.0 +max_mc_version = b1.4_01 +mc_version_range = >=1.0.0-beta.0 <=1.0.0-beta.4.1 + +feather_build = 12 +nests_build = 1 diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java similarity index 100% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java rename to libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java similarity index 100% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java rename to libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java similarity index 100% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java rename to libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java similarity index 100% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java rename to libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java diff --git a/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java new file mode 100644 index 00000000..a23c4df4 --- /dev/null +++ b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java @@ -0,0 +1,73 @@ +package net.ornithemc.osl.networking.impl; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.client.network.handler.ClientNetworkHandler; +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; + +public class CustomPayloadPacket extends Packet { + + public String channel; + public int size; + public byte[] data; + + public CustomPayloadPacket() { + } + + public CustomPayloadPacket(String channel, byte[] data) { + this.channel = channel; + this.data = data; + if (data != null) { + this.size = data.length; + if (this.size > Short.MAX_VALUE) { + throw new IllegalArgumentException("Payload may not be larger than 32k"); + } + } + } + + // the IOException has been stripped from the read/write methods + // by the obfuscator, thus we catch it and re-throw it as a + // runtime exception - it will be caught in Connection#read anyhow + + @Override + public void read(DataInputStream input) { + try { + this.channel = input.readUTF(); + this.size = input.readShort(); + if (this.size > 0 && this.size < Short.MAX_VALUE) { + this.data = new byte[this.size]; + input.readFully(this.data); + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void write(DataOutputStream output) { + try { + output.writeUTF(this.channel); + output.writeShort(this.size); + if (this.data != null) { + output.write(this.data); + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void handle(PacketHandler handler) { + ClientPlayNetworkingImpl.handle((ClientNetworkHandler)handler, this); + } + + @Override + public int getSize() { + return 2 + this.channel.length() * 2 + 2 + this.size; + } +} diff --git a/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java new file mode 100644 index 00000000..3288d684 --- /dev/null +++ b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java @@ -0,0 +1,53 @@ +package net.ornithemc.osl.networking.impl; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.Set; + +import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; + +public class HandshakePayload implements CustomPayload { + + public static final String CHANNEL = "OSL|Handshake"; + + public Set channels; + + public HandshakePayload() { + } + + public HandshakePayload(Set channels) { + this.channels = channels; + } + + public static HandshakePayload client() { + return new HandshakePayload(ClientPlayNetworkingImpl.LISTENERS.keySet()); + } + + public static HandshakePayload server() { + throw new UnsupportedOperationException(); + } + + @Override + public void read(DataInputStream input) throws IOException { + channels = new LinkedHashSet<>(); + int channelCount = input.readInt(); + + if (channelCount > 0) { + for (int i = 0; i < channelCount; i++) { + channels.add(input.readUTF()); + } + } + } + + @Override + public void write(DataOutputStream output) throws IOException { + output.writeInt(channels.size()); + + for (String channel : channels) { + output.writeUTF(channel); + } + } +} diff --git a/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..6dbdb0bd --- /dev/null +++ b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,37 @@ +package net.ornithemc.osl.networking.impl; + +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.lifecycle.api.MinecraftEvents; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.interfaces.mixin.IClientNetworkHandler; +import net.ornithemc.osl.networking.impl.mixin.common.PacketAccessor; + +public class Networking implements ModInitializer, ClientModInitializer { + + @Override + public void init() { + PacketAccessor.register(Constants.CUSTOM_PAYLOAD_PACKET_ID, CustomPayloadPacket.class); + } + + @Override + public void initClient() { + MinecraftEvents.START.register(minecraft -> { + ClientPlayNetworkingImpl.setUp(minecraft); + }); + MinecraftEvents.STOP.register(minecraft -> { + ClientPlayNetworkingImpl.destroy(minecraft); + }); + ClientPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + // send channel registration data as a response to receiving server channel registration data + ClientPlayNetworking.doSend(HandshakePayload.CHANNEL, HandshakePayload.client()); + + ((IClientNetworkHandler)handler).osl$networking$registerServerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); + + return true; + }); + } +} diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java similarity index 100% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java rename to libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IClientNetworkHandler.java b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IClientNetworkHandler.java similarity index 100% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IClientNetworkHandler.java rename to libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IClientNetworkHandler.java diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java similarity index 100% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java rename to libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/HandshakePacketMixin.java b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/HandshakePacketMixin.java similarity index 100% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/HandshakePacketMixin.java rename to libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/HandshakePacketMixin.java diff --git a/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java new file mode 100644 index 00000000..ccc94437 --- /dev/null +++ b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java @@ -0,0 +1,15 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import net.minecraft.network.packet.Packet; + +@Mixin(Packet.class) +public interface PacketAccessor { + + @Invoker("register") + public static void register(int id, Class type) { + throw new AssertionError(); + } +} diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/resources/osl.networking.mixins.json b/libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/resources/osl.networking.mixins.json similarity index 100% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/resources/osl.networking.mixins.json rename to libraries/networking/networking-client-mcb1.0-mcb1.4_01/src/main/resources/osl.networking.mixins.json diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/build.gradle b/libraries/networking/networking-client-mcb1.5-mc11w48a/build.gradle similarity index 100% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/build.gradle rename to libraries/networking/networking-client-mcb1.5-mc11w48a/build.gradle diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/gradle.properties b/libraries/networking/networking-client-mcb1.5-mc11w48a/gradle.properties similarity index 51% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/gradle.properties rename to libraries/networking/networking-client-mcb1.5-mc11w48a/gradle.properties index 272f12b9..e5b1e666 100644 --- a/libraries/networking/networking-client-mcb1.0-mc11w48a/gradle.properties +++ b/libraries/networking/networking-client-mcb1.5-mc11w48a/gradle.properties @@ -1,7 +1,7 @@ environment = client -min_mc_version = b1.0 +min_mc_version = b1.5 max_mc_version = 11w48a -mc_version_range = >=1.0.0-beta.0 <=1.1-alpha.11.48.a +mc_version_range = >=1.0.0-beta.5 <=1.1-alpha.11.48.a feather_build = 12 nests_build = 1 diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java similarity index 100% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java rename to libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java similarity index 100% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java rename to libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java diff --git a/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java new file mode 100644 index 00000000..f0963ed6 --- /dev/null +++ b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java @@ -0,0 +1,70 @@ +package net.ornithemc.osl.networking.api.client; + +import java.util.function.Consumer; + +import net.minecraft.client.Minecraft; + +import net.ornithemc.osl.core.api.events.Event; + +/** + * Events related to the client side of a client-server connection. + */ +public class ClientConnectionEvents { + + /** + * This event is fired after a successful login occurs. + * + *

+ * Note that channel registration happens after login, + * and until then data cannot safely be sent to the server. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ClientConnectionEvents.LOGIN.register(minecraft -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event> LOGIN = Event.consumer(); + /** + * This event is fired after login, once channel registration is complete. + * + *

+ * This marks the moment data can safely be sent to the server. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ClientConnectionEvents.PLAY_READY.register(minecraft -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event> PLAY_READY = Event.consumer(); + /** + * This event is fired when the client disconnects from the server. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ClientConnectionEvents.DISCONNECT.register(minecraft -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event> DISCONNECT = Event.consumer(); + +} diff --git a/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java new file mode 100644 index 00000000..196fd1f1 --- /dev/null +++ b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java @@ -0,0 +1,155 @@ +package net.ornithemc.osl.networking.api.client; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.function.Supplier; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.network.handler.ClientNetworkHandler; + +import net.ornithemc.osl.core.api.util.function.IOConsumer; +import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; + +public final class ClientPlayNetworking { + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { + ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(String channel, StreamListener listener) { + ClientPlayNetworkingImpl.registerListener(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListenerRaw(String channel, ByteArrayListener listener) { + ClientPlayNetworkingImpl.registerListenerRaw(channel, listener); + } + + /** + * Remove the listener registered to the given channel. + */ + public static void unregisterListener(String channel) { + ClientPlayNetworkingImpl.unregisterListener(channel); + } + + /** + * Check whether the connection is ready for data to be sent to the server. + */ + public static boolean isPlayReady() { + return ClientPlayNetworkingImpl.isPlayReady(); + } + + /** + * Check whether the given channel is open for data to be sent through it. + * This method will return {@code false} if the client is not connected to a + * server, or if the server has no listeners for the given channel. + */ + public static boolean canSend(String channel) { + return ClientPlayNetworkingImpl.canSend(channel); + } + + /** + * Send a packet to the server through the given channel. The payload will + * only be written if the channel is open. + */ + public static void send(String channel, CustomPayload payload) { + ClientPlayNetworkingImpl.send(channel, payload); + } + + /** + * Send a packet to the server through the given channel. The writer will + * only be called if the channel is open. + */ + public static void send(String channel, IOConsumer writer) { + ClientPlayNetworkingImpl.send(channel, writer); + } + + /** + * Send a packet to the server through the given channel. + */ + public static void send(String channel, byte[] data) { + ClientPlayNetworkingImpl.send(channel, data); + } + + /** + * Send a packet to the server through the given channel, without checking + * whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the server. + */ + public static void doSend(String channel, CustomPayload payload) { + ClientPlayNetworkingImpl.doSend(channel, payload); + } + + /** + * Send a packet to the server through the given channel, without checking + * whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the server. + */ + public static void doSend(String channel, IOConsumer writer) { + ClientPlayNetworkingImpl.doSend(channel, writer); + } + + /** + * Send a packet to the server through the given channel, without checking + * whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the server. + */ + public static void doSend(String channel, byte[] data) { + ClientPlayNetworkingImpl.doSend(channel, data); + } + + public interface PayloadListener { + + /** + * Receive incoming data from the server. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(Minecraft minecraft, ClientNetworkHandler handler, T payload) throws IOException; + + } + + public interface StreamListener { + + /** + * Receive incoming data from the server. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(Minecraft minecraft, ClientNetworkHandler handler, DataInputStream data) throws IOException; + + } + + public interface ByteArrayListener { + + /** + * Receive incoming data from the server. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; + + } +} diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java similarity index 100% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java rename to libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java similarity index 100% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java rename to libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java similarity index 100% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java rename to libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java diff --git a/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java new file mode 100644 index 00000000..39243656 --- /dev/null +++ b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java @@ -0,0 +1,165 @@ +package net.ornithemc.osl.networking.impl.client; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Supplier; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.network.handler.ClientNetworkHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.core.api.util.function.IOConsumer; +import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.networking.api.DataStreams; +import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteArrayListener; +import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.PayloadListener; +import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.StreamListener; +import net.ornithemc.osl.networking.impl.CustomPayloadPacket; +import net.ornithemc.osl.networking.impl.interfaces.mixin.IClientNetworkHandler; + +public final class ClientPlayNetworkingImpl { + + private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); + + private static Minecraft minecraft; + + public static void setUp(Minecraft minecraft) { + if (ClientPlayNetworkingImpl.minecraft == minecraft) { + throw new IllegalStateException("tried to set up client networking when it was already set up!"); + } + + ClientPlayNetworkingImpl.minecraft = minecraft; + } + + public static void destroy(Minecraft minecraft) { + if (ClientPlayNetworkingImpl.minecraft != minecraft) { + throw new IllegalStateException("tried to destroy client networking when it was not set up!"); + } + + ClientPlayNetworkingImpl.minecraft = null; + } + + public static final Map LISTENERS = new LinkedHashMap<>(); + + public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { + registerListenerImpl(channel, (minecraft, handler, data) -> { + T payload = initializer.get(); + payload.read(DataStreams.input(data)); + + return listener.handle(minecraft, handler, payload); + }); + } + + public static void registerListener(String channel, StreamListener listener) { + registerListenerImpl(channel, (minecraft, handler, data) -> { + return listener.handle(minecraft, handler, DataStreams.input(data)); + }); + } + + public static void registerListenerRaw(String channel, ByteArrayListener listener) { + registerListenerImpl(channel, listener::handle); + } + + private static void registerListenerImpl(String channel, Listener listener) { + LISTENERS.compute(channel, (key, value) -> { + if (value != null) { + throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + } + + return listener; + }); + } + + public static void unregisterListener(String channel) { + LISTENERS.remove(channel); + } + + public static boolean handle(ClientNetworkHandler handler, CustomPayloadPacket packet) { + Listener listener = LISTENERS.get(packet.channel); + + if (listener != null) { + try { + return listener.handle(minecraft, handler, packet.data); + } catch (IOException e) { + LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); + return true; + } + } + + return false; + } + + public static boolean isPlayReady() { + IClientNetworkHandler handler = (IClientNetworkHandler)minecraft.getNetworkHandler(); + return handler != null && handler.osl$networking$isPlayReady(); + } + + public static boolean canSend(String channel) { + IClientNetworkHandler handler = (IClientNetworkHandler)minecraft.getNetworkHandler(); + return handler != null && handler.osl$networking$isRegisteredServerChannel(channel); + } + + public static void send(String channel, CustomPayload payload) { + if (canSend(channel)) { + doSend(channel, payload); + } + } + + public static void send(String channel, IOConsumer writer) { + if (canSend(channel)) { + doSend(channel, writer); + } + } + + public static void send(String channel, byte[] data) { + if (canSend(channel)) { + doSend(channel, data); + } + } + + public static void doSend(String channel, CustomPayload payload) { + sendPacket(makePacket(channel, payload)); + } + + public static void doSend(String channel, IOConsumer writer) { + sendPacket(makePacket(channel, writer)); + } + + public static void doSend(String channel, byte[] data) { + sendPacket(makePacket(channel, data)); + } + + private static Packet makePacket(String channel, CustomPayload payload) { + return makePacket(channel, payload::write); + } + + private static Packet makePacket(String channel, IOConsumer writer) { + try { + return new CustomPayloadPacket(channel, DataStreams.output(writer).toByteArray()); + } catch (IOException e) { + LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); + return null; + } + } + + private static Packet makePacket(String channel, byte[] data) { + return new CustomPayloadPacket(channel, data); + } + + private static void sendPacket(Packet packet) { + if (packet != null) { + minecraft.getNetworkHandler().sendPacket(packet); + } + } + + private interface Listener { + + boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; + + } +} diff --git a/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IClientNetworkHandler.java b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IClientNetworkHandler.java new file mode 100644 index 00000000..a4eb8c1c --- /dev/null +++ b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IClientNetworkHandler.java @@ -0,0 +1,13 @@ +package net.ornithemc.osl.networking.impl.interfaces.mixin; + +import java.util.Set; + +public interface IClientNetworkHandler { + + boolean osl$networking$isPlayReady(); + + void osl$networking$registerServerChannels(Set channels); + + boolean osl$networking$isRegisteredServerChannel(String channel); + +} diff --git a/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java new file mode 100644 index 00000000..16afa575 --- /dev/null +++ b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java @@ -0,0 +1,65 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.network.handler.ClientNetworkHandler; + +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.impl.interfaces.mixin.IClientNetworkHandler; + +@Mixin(ClientNetworkHandler.class) +public class ClientNetworkHandlerMixin implements IClientNetworkHandler { + + @Shadow @Final private Minecraft minecraft; + + /** + * Channels that the server is listening to. + */ + @Unique private Set serverChannels; + + @Inject( + method = "handleLogin", + at = @At( + value = "TAIL" + ) + ) + private void osl$networking$handleLogin(CallbackInfo ci) { + ClientConnectionEvents.LOGIN.invoker().accept(minecraft); + } + + @Inject( + method = "onDisconnect", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$handleDisconnect(CallbackInfo ci) { + ClientConnectionEvents.DISCONNECT.invoker().accept(minecraft); + serverChannels = null; + } + + @Override + public boolean osl$networking$isPlayReady() { + return serverChannels != null; + } + + @Override + public void osl$networking$registerServerChannels(Set channels) { + serverChannels = new LinkedHashSet<>(channels); + } + + @Override + public boolean osl$networking$isRegisteredServerChannel(String channel) { + return serverChannels != null && serverChannels.contains(channel); + } +} diff --git a/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/HandshakePacketMixin.java b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/HandshakePacketMixin.java new file mode 100644 index 00000000..d0a1bf15 --- /dev/null +++ b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/HandshakePacketMixin.java @@ -0,0 +1,27 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.network.packet.HandshakePacket; + +import net.ornithemc.osl.networking.impl.Constants; + +@Mixin(HandshakePacket.class) +public class HandshakePacketMixin { + + @Shadow private String protocol; + + @Inject( + method = "(Ljava/lang/String;)V", + at = @At( + value = "TAIL" + ) + ) + private void osl$networking$modifyHandshakeForOsl(CallbackInfo ci) { + protocol = Constants.OSL_HANDSHAKE_KEY; + } +} diff --git a/libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java similarity index 100% rename from libraries/networking/networking-client-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java rename to libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java diff --git a/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/resources/osl.networking.mixins.json b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/resources/osl.networking.mixins.json new file mode 100644 index 00000000..cfeee93a --- /dev/null +++ b/libraries/networking/networking-client-mcb1.5-mc11w48a/src/main/resources/osl.networking.mixins.json @@ -0,0 +1,18 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.ornithemc.osl.networking.impl.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "common.HandshakePacketMixin", + "common.PacketAccessor" + ], + "client": [ + "client.ClientNetworkHandlerMixin" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/build.gradle b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/build.gradle similarity index 100% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/build.gradle rename to libraries/networking/networking-server-mcb1.0-mcb1.4_01/build.gradle diff --git a/libraries/networking/networking-server-mcb1.0-mcb1.4_01/gradle.properties b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/gradle.properties new file mode 100644 index 00000000..ffbdb75b --- /dev/null +++ b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/gradle.properties @@ -0,0 +1,7 @@ +environment = server +min_mc_version = b1.0 +max_mc_version = b1.4_01 +mc_version_range = >=1.0.0-beta.0 <=1.0.0-beta.4.1 + +feather_build = 12 +nests_build = 1 diff --git a/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java new file mode 100644 index 00000000..237d7e67 --- /dev/null +++ b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java @@ -0,0 +1,13 @@ +package net.ornithemc.osl.networking.api; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public interface CustomPayload { + + void read(DataInputStream input) throws IOException; + + void write(DataOutputStream output) throws IOException; + +} diff --git a/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java new file mode 100644 index 00000000..f68e894c --- /dev/null +++ b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java @@ -0,0 +1,23 @@ +package net.ornithemc.osl.networking.api; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.ornithemc.osl.core.api.util.function.IOConsumer; + +public final class DataStreams { + + public static DataInputStream input(byte[] bytes) { + return new DataInputStream(new ByteArrayInputStream(bytes == null ? new byte[0] : bytes)); + } + + public static ByteArrayOutputStream output(IOConsumer writer) throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream os = new DataOutputStream(bos); + writer.accept(os); + return bos; + } +} diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java similarity index 100% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java rename to libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java similarity index 100% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java rename to libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java diff --git a/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java new file mode 100644 index 00000000..619c1125 --- /dev/null +++ b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java @@ -0,0 +1,73 @@ +package net.ornithemc.osl.networking.impl; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; +import net.minecraft.server.network.handler.ServerPlayNetworkHandler; + +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class CustomPayloadPacket extends Packet { + + public String channel; + public int size; + public byte[] data; + + public CustomPayloadPacket() { + } + + public CustomPayloadPacket(String channel, byte[] data) { + this.channel = channel; + this.data = data; + if (data != null) { + this.size = data.length; + if (this.size > Short.MAX_VALUE) { + throw new IllegalArgumentException("Payload may not be larger than 32k"); + } + } + } + + // the IOException has been stripped from the read/write methods + // by the obfuscator, thus we catch it and re-throw it as a + // runtime exception - it will be caught in Connection#read anyhow + + @Override + public void read(DataInputStream input) { + try { + this.channel = input.readUTF(); + this.size = input.readShort(); + if (this.size > 0 && this.size < Short.MAX_VALUE) { + this.data = new byte[this.size]; + input.readFully(this.data); + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void write(DataOutputStream output) { + try { + output.writeUTF(this.channel); + output.writeShort(this.size); + if (this.data != null) { + output.write(this.data); + } + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void handle(PacketHandler handler) { + ServerPlayNetworkingImpl.handle((ServerPlayNetworkHandler)handler, this); + } + + @Override + public int getSize() { + return 2 + this.channel.length() * 2 + 2 + this.size; + } +} diff --git a/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java new file mode 100644 index 00000000..faf5792b --- /dev/null +++ b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java @@ -0,0 +1,55 @@ +package net.ornithemc.osl.networking.impl; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.Set; + +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class HandshakePayload implements CustomPayload { + + public static final String CHANNEL = "OSL|Handshake"; + + public Set channels; + + public HandshakePayload() { + } + + public HandshakePayload(Set channels) { + this.channels = channels; + } + + public static HandshakePayload client() { + throw new UnsupportedOperationException(); + } + + public static HandshakePayload server() { + return new HandshakePayload(ServerPlayNetworkingImpl.LISTENERS.keySet()); + } + + @Override + public void read(DataInputStream input) throws IOException { + channels = new LinkedHashSet<>(); + int channelCount = input.readInt(); + + if (channelCount > 0) { + for (int i = 0; i < channelCount; i++) { + channels.add(input.readUTF()); + } + } + } + + @Override + public void write(DataOutputStream output) throws IOException { + output.writeInt(channels.size()); + + for (String channel : channels) { + output.writeUTF(channel); + } + } +} diff --git a/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..dffc3265 --- /dev/null +++ b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,30 @@ +package net.ornithemc.osl.networking.impl; + +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.lifecycle.api.MinecraftEvents; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.api.server.ServerPlayNetworking; +import net.ornithemc.osl.networking.impl.interfaces.mixin.IServerPlayNetworkHandler; +import net.ornithemc.osl.networking.impl.mixin.common.PacketAccessor; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class Networking implements ModInitializer { + + @Override + public void init() { + PacketAccessor.register(Constants.CUSTOM_PAYLOAD_PACKET_ID, CustomPayloadPacket.class); + + MinecraftEvents.START.register(server -> { + ServerPlayNetworkingImpl.setUp(server); + }); + MinecraftEvents.STOP.register(server -> { + ServerPlayNetworkingImpl.destroy(server); + }); + ServerPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + ((IServerPlayNetworkHandler)handler).osl$networking$registerClientChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + + return true; + }); + } +} diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IServerPlayNetworkHandler.java b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IServerPlayNetworkHandler.java similarity index 100% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IServerPlayNetworkHandler.java rename to libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IServerPlayNetworkHandler.java diff --git a/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java new file mode 100644 index 00000000..ccc94437 --- /dev/null +++ b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java @@ -0,0 +1,15 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import net.minecraft.network.packet.Packet; + +@Mixin(Packet.class) +public interface PacketAccessor { + + @Invoker("register") + public static void register(int id, Class type) { + throw new AssertionError(); + } +} diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerLoginNetworkHandlerMixin.java b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerLoginNetworkHandlerMixin.java similarity index 100% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerLoginNetworkHandlerMixin.java rename to libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerLoginNetworkHandlerMixin.java diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java similarity index 100% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java rename to libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java similarity index 100% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java rename to libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/resources/osl.networking.mixins.json b/libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/resources/osl.networking.mixins.json similarity index 100% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/resources/osl.networking.mixins.json rename to libraries/networking/networking-server-mcb1.0-mcb1.4_01/src/main/resources/osl.networking.mixins.json diff --git a/libraries/networking/networking-server-mcb1.5-mc11w48a/build.gradle b/libraries/networking/networking-server-mcb1.5-mc11w48a/build.gradle new file mode 100644 index 00000000..06957d1a --- /dev/null +++ b/libraries/networking/networking-server-mcb1.5-mc11w48a/build.gradle @@ -0,0 +1,4 @@ +setUpModule(project, + 'entrypoints-server-mcserver-a0.1.0-mc12w30e', + 'lifecycle-events-server-mcb1.4-1507-mc11w50a' +) diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/gradle.properties b/libraries/networking/networking-server-mcb1.5-mc11w48a/gradle.properties similarity index 51% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/gradle.properties rename to libraries/networking/networking-server-mcb1.5-mc11w48a/gradle.properties index a845d9a4..20fe3b40 100644 --- a/libraries/networking/networking-server-mcb1.0-mc11w48a/gradle.properties +++ b/libraries/networking/networking-server-mcb1.5-mc11w48a/gradle.properties @@ -1,7 +1,7 @@ environment = server -min_mc_version = b1.0 +min_mc_version = b1.5 max_mc_version = 11w48a -mc_version_range = >=1.0.0-beta.0 <=1.1-alpha.11.48.a +mc_version_range = >=1.0.0-beta.5 <=1.1-alpha.11.48.a feather_build = 12 nests_build = 1 diff --git a/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java new file mode 100644 index 00000000..237d7e67 --- /dev/null +++ b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java @@ -0,0 +1,13 @@ +package net.ornithemc.osl.networking.api; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public interface CustomPayload { + + void read(DataInputStream input) throws IOException; + + void write(DataOutputStream output) throws IOException; + +} diff --git a/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java new file mode 100644 index 00000000..f68e894c --- /dev/null +++ b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java @@ -0,0 +1,23 @@ +package net.ornithemc.osl.networking.api; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.ornithemc.osl.core.api.util.function.IOConsumer; + +public final class DataStreams { + + public static DataInputStream input(byte[] bytes) { + return new DataInputStream(new ByteArrayInputStream(bytes == null ? new byte[0] : bytes)); + } + + public static ByteArrayOutputStream output(IOConsumer writer) throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + DataOutputStream os = new DataOutputStream(bos); + writer.accept(os); + return bos; + } +} diff --git a/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java new file mode 100644 index 00000000..a6e60c20 --- /dev/null +++ b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java @@ -0,0 +1,71 @@ +package net.ornithemc.osl.networking.api.server; + +import java.util.function.BiConsumer; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; + +import net.ornithemc.osl.core.api.events.Event; + +/** + * Events related to the server side of a client-server connection. + */ +public class ServerConnectionEvents { + + /** + * This event is fired after a successful login occurs. + * + *

+ * Note that channel registration happens after login, + * and until then data cannot safely be sent to the client. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ServerConnectionEvents.LOGIN.register((server, player) -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event> LOGIN = Event.biConsumer(); + /** + * This event is fired after login, once channel registration is complete. + * + *

+ * This marks the moment data can safely be sent to the client. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ServerConnectionEvents.PLAY_READY.register((server, player) -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event> PLAY_READY = Event.biConsumer(); + /** + * This event is fired when a client disconnects from the server. + * + *

+ * Callbacks to this event should be registered in your mod's entrypoint, + * and can be done as follows: + * + *

+	 * {@code
+	 * ServerConnectionEvents.DISCONNECT.register((server, player) -> {
+	 * 	...
+	 * });
+	 * }
+	 * 
+ */ + public static final Event> DISCONNECT = Event.biConsumer(); + +} diff --git a/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java new file mode 100644 index 00000000..1987a584 --- /dev/null +++ b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java @@ -0,0 +1,318 @@ +package net.ornithemc.osl.networking.api.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.function.Supplier; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.server.network.handler.ServerPlayNetworkHandler; + +import net.ornithemc.osl.core.api.util.function.IOConsumer; +import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public final class ServerPlayNetworking { + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { + ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(String channel, StreamListener listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListenerRaw(String channel, ByteArrayListener listener) { + ServerPlayNetworkingImpl.registerListenerRaw(channel, listener); + } + + /** + * Remove the listener registered to the given channel. + */ + public static void unregisterListener(String channel) { + ServerPlayNetworkingImpl.unregisterListener(channel); + } + + /** + * Check whether the connection is ready for data to be sent to the client. + */ + public static boolean isPlayReady(ServerPlayerEntity player) { + return ServerPlayNetworkingImpl.isPlayReady(player); + } + + /** + * Check whether the given channel is open for data to be sent through it. + * This method will return {@code false} if the client has no listeners for + * the given channel. + */ + public static boolean canSend(ServerPlayerEntity player, String channel) { + return ServerPlayNetworkingImpl.canSend(player, channel); + } + + /** + * Send a packet to the given player through the given channel. The payload + * will only be written if the channel is open. + */ + public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { + ServerPlayNetworkingImpl.send(player, channel, payload); + } + + /** + * Send a packet to the given player through the given channel. The writer + * will only be called if the channel is open. + */ + public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { + ServerPlayNetworkingImpl.send(player, channel, writer); + } + + /** + * Send a packet to the given player through the given channel. + */ + public static void send(ServerPlayerEntity player, String channel, byte[] data) { + ServerPlayNetworkingImpl.send(player, channel, data); + } + + /** + * Send a packet to the given players through the given channel. The payload + * will only be written if the channel is open for at least one player. + */ + public static void send(Iterable players, String channel, CustomPayload payload) { + ServerPlayNetworkingImpl.send(players, channel, payload); + } + + /** + * Send a packet to the given players through the given channel. The writer + * will only be called if the channel is open for at least one player. + */ + public static void send(Iterable players, String channel, IOConsumer writer) { + ServerPlayNetworkingImpl.send(players, channel, writer); + } + + /** + * Send a packet to the given players through the given channel. + */ + public static void send(Iterable players, String channel, byte[] data) { + ServerPlayNetworkingImpl.send(players, channel, data); + } + + /** + * Send a packet to the players in the given dimension through the given + * channel. The payload will only be written if the channel is open for at + * least one player. + */ + public static void send(int dimension, String channel, CustomPayload payload) { + ServerPlayNetworkingImpl.send(dimension, channel, payload); + } + + /** + * Send a packet to the players in the given dimension through the given + * channel. The writer will only be called if the channel is open for at + * least one player. + */ + public static void send(int dimension, String channel, IOConsumer writer) { + ServerPlayNetworkingImpl.send(dimension, channel, writer); + } + + /** + * Send a packet to the players in the given dimension through the given + * channel. + */ + public static void send(int dimension, String channel, byte[] data) { + ServerPlayNetworkingImpl.send(dimension, channel, data); + } + + /** + * Send a packet to all players through the given channel. The payload will + * only be written if the channel is open for at least one player. + */ + public static void send(String channel, CustomPayload payload) { + ServerPlayNetworkingImpl.send(channel, payload); + } + + /** + * Send a packet to all players through the given channel. The writer will + * only be called if the channel is open for at least one player. + */ + public static void send(String channel, IOConsumer writer) { + ServerPlayNetworkingImpl.send(channel, writer); + } + + /** + * Send a packet to all players through the given channel. + */ + public static void send(String channel, byte[] data) { + ServerPlayNetworkingImpl.send(channel, data); + } + + /** + * Send a packet to the given player through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { + ServerPlayNetworkingImpl.doSend(player, channel, payload); + } + + /** + * Send a packet to the given player through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { + ServerPlayNetworkingImpl.doSend(player, channel, writer); + } + + /** + * Send a packet to the given player through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { + ServerPlayNetworkingImpl.doSend(player, channel, data); + } + + /** + * Send a packet to the given players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void doSend(Iterable players, String channel, CustomPayload payload) { + ServerPlayNetworkingImpl.doSend(players, channel, payload); + } + + /** + * Send a packet to the given players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void doSend(Iterable players, String channel, IOConsumer writer) { + ServerPlayNetworkingImpl.doSend(players, channel, writer); + } + + /** + * Send a packet to the given players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void doSend(Iterable players, String channel, byte[] data) { + ServerPlayNetworkingImpl.doSend(players, channel, data); + } + + /** + * Send a packet to the players in the given dimension through the given + * channel, without checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void doSend(int dimension, String channel, CustomPayload payload) { + ServerPlayNetworkingImpl.doSend(dimension, channel, payload); + } + + /** + * Send a packet to the players in the given dimension through the given + * channel, without checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void doSend(int dimension, String channel, IOConsumer writer) { + ServerPlayNetworkingImpl.doSend(dimension, channel, writer); + } + + /** + * Send a packet to the players in the given dimension through the given + * channel, without checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void doSend(int dimension, String channel, byte[] data) { + ServerPlayNetworkingImpl.doSend(dimension, channel, data); + } + + /** + * Send a packet to all players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void doSend(String channel, CustomPayload payload) { + ServerPlayNetworkingImpl.doSend(channel, payload); + } + + /** + * Send a packet to all players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void doSend(String channel, IOConsumer writer) { + ServerPlayNetworkingImpl.doSend(channel, writer); + } + + /** + * Send a packet to all players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void doSend(String channel, byte[] data) { + ServerPlayNetworkingImpl.doSend(channel, data); + } + + public interface PayloadListener { + + /** + * Receive incoming data from the client. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T payload) throws IOException; + + } + + public interface StreamListener { + + /** + * Receive incoming data from the client. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, DataInputStream data) throws IOException; + + } + + public interface ByteArrayListener { + + /** + * Receive incoming data from the client. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; + + } +} diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java similarity index 100% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java rename to libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java similarity index 100% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java rename to libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java similarity index 100% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java rename to libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java diff --git a/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IServerPlayNetworkHandler.java b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IServerPlayNetworkHandler.java new file mode 100644 index 00000000..1a97a535 --- /dev/null +++ b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IServerPlayNetworkHandler.java @@ -0,0 +1,17 @@ +package net.ornithemc.osl.networking.impl.interfaces.mixin; + +import java.util.Set; + +import net.minecraft.server.entity.living.player.ServerPlayerEntity; + +public interface IServerPlayNetworkHandler { + + ServerPlayerEntity osl$networking$getPlayer(); + + boolean osl$networking$isPlayReady(); + + void osl$networking$registerClientChannels(Set channels); + + boolean osl$networking$isRegisteredClientChannel(String channel); + +} diff --git a/libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java similarity index 100% rename from libraries/networking/networking-server-mcb1.0-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java rename to libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java diff --git a/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerLoginNetworkHandlerMixin.java b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerLoginNetworkHandlerMixin.java new file mode 100644 index 00000000..49834b26 --- /dev/null +++ b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerLoginNetworkHandlerMixin.java @@ -0,0 +1,62 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import net.minecraft.network.packet.HelloPacket; +import net.minecraft.network.packet.LoginPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.server.network.handler.ServerLoginNetworkHandler; + +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.Constants; +import net.ornithemc.osl.networking.impl.HandshakePayload; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +@Mixin(ServerLoginNetworkHandler.class) +public class ServerLoginNetworkHandlerMixin { + + @Shadow @Final private MinecraftServer server; + + /** + * is the client also running OSL? + */ + @Unique private boolean ornithe; + + @Inject( + method = "handleHello", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$handleHandshake(HelloPacket packet, CallbackInfo ci) { + if (Constants.OSL_HANDSHAKE_KEY.equals(packet.serverId)) { + ornithe = true; + } + } + + @Inject( + method = "acceptLogin", + locals = LocalCapture.CAPTURE_FAILHARD, + at = @At( + value = "TAIL" + ) + ) + private void osl$networking$handleLogin(LoginPacket packet, CallbackInfo ci, ServerPlayerEntity player) { + if (player != null) { + if (ornithe) { + // send channel registration data as soon as login occurs + ServerPlayNetworkingImpl.doSend(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + } + + ServerConnectionEvents.LOGIN.invoker().accept(server, player); + } + } +} diff --git a/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java new file mode 100644 index 00000000..591c6517 --- /dev/null +++ b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java @@ -0,0 +1,62 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.server.network.handler.ServerPlayNetworkHandler; + +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.interfaces.mixin.IServerPlayNetworkHandler; + +@Mixin(ServerPlayNetworkHandler.class) +public class ServerPlayNetworkHandlerMixin implements IServerPlayNetworkHandler { + + @Shadow @Final private MinecraftServer server; + @Shadow @Final private ServerPlayerEntity player; + + /** + * Channels that the client is listening to. + */ + @Unique private Set clientChannels; + + @Inject( + method = "onDisconnect", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$handleDisconnect(CallbackInfo ci) { + ServerConnectionEvents.DISCONNECT.invoker().accept(server, player); + clientChannels = null; + } + + @Override + public ServerPlayerEntity osl$networking$getPlayer() { + return player; + } + + @Override + public boolean osl$networking$isPlayReady() { + return clientChannels != null; + } + + @Override + public void osl$networking$registerClientChannels(Set channels) { + clientChannels = new LinkedHashSet<>(channels); + } + + @Override + public boolean osl$networking$isRegisteredClientChannel(String channel) { + return clientChannels != null && clientChannels.contains(channel); + } +} diff --git a/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java new file mode 100644 index 00000000..0fdf6c60 --- /dev/null +++ b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -0,0 +1,268 @@ +package net.ornithemc.osl.networking.impl.server; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.minecraft.network.packet.Packet; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.server.network.handler.ServerPlayNetworkHandler; + +import net.ornithemc.osl.core.api.util.function.IOConsumer; +import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.networking.api.DataStreams; +import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteArrayListener; +import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.PayloadListener; +import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.StreamListener; +import net.ornithemc.osl.networking.impl.CustomPayloadPacket; +import net.ornithemc.osl.networking.impl.interfaces.mixin.IServerPlayNetworkHandler; + +public final class ServerPlayNetworkingImpl { + + private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); + + private static MinecraftServer server; + + public static void setUp(MinecraftServer server) { + if (ServerPlayNetworkingImpl.server == server) { + throw new IllegalStateException("tried to set up server networking when it was already set up!"); + } + + ServerPlayNetworkingImpl.server = server; + } + + public static void destroy(MinecraftServer server) { + if (ServerPlayNetworkingImpl.server != server) { + throw new IllegalStateException("tried to destroy server networking when it was not set up!"); + } + + ServerPlayNetworkingImpl.server = null; + } + + public static final Map LISTENERS = new LinkedHashMap<>(); + + public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { + registerListenerImpl(channel, (server, handler, player, data) -> { + T payload = initializer.get(); + payload.read(DataStreams.input(data)); + + return listener.handle(server, handler, player, payload); + }); + } + + public static void registerListener(String channel, StreamListener listener) { + registerListenerImpl(channel, (server, handler, player, data) -> { + return listener.handle(server, handler, player, DataStreams.input(data)); + }); + } + + public static void registerListenerRaw(String channel, ByteArrayListener listener) { + registerListenerImpl(channel, listener::handle); + } + + private static void registerListenerImpl(String channel, Listener listener) { + LISTENERS.compute(channel, (key, value) -> { + if (value != null) { + throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + } + + return listener; + }); + } + + public static void unregisterListener(String channel) { + LISTENERS.remove(channel); + } + + public static boolean handle(ServerPlayNetworkHandler handler, CustomPayloadPacket packet) { + Listener listener = LISTENERS.get(packet.channel); + + if (listener != null) { + ServerPlayerEntity player = ((IServerPlayNetworkHandler)handler).osl$networking$getPlayer(); + + try { + return listener.handle(server, handler, player, packet.data); + } catch (IOException e) { + LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); + return true; + } + } + + return false; + } + + public static boolean isPlayReady(ServerPlayerEntity player) { + IServerPlayNetworkHandler handler = (IServerPlayNetworkHandler)player.networkHandler; + return handler != null && handler.osl$networking$isPlayReady(); + } + + public static boolean canSend(ServerPlayerEntity player, String channel) { + IServerPlayNetworkHandler handler = (IServerPlayNetworkHandler)player.networkHandler; + return handler != null && handler.osl$networking$isRegisteredClientChannel(channel); + } + + public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { + if (canSend(player, channel)) { + doSend(player, channel, payload); + } + } + + public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { + if (canSend(player, channel)) { + doSend(player, channel, writer); + } + } + + public static void send(ServerPlayerEntity player, String channel, byte[] data) { + if (canSend(player, channel)) { + doSend(player, channel, data); + } + } + + public static void send(Iterable players, String channel, CustomPayload payload) { + sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, payload)); + } + + public static void send(Iterable players, String channel, IOConsumer writer) { + sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, writer)); + } + + public static void send(Iterable players, String channel, byte[] data) { + sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); + } + + public static void send(int dimension, String channel, CustomPayload payload) { + doSend(collectPlayers(p -> p.dimensionId == dimension && canSend(p, channel)), channel, payload); + } + + public static void send(int dimension, String channel, IOConsumer writer) { + doSend(collectPlayers(p -> p.dimensionId == dimension && canSend(p, channel)), channel, writer); + } + + public static void send(int dimension, String channel, byte[] data) { + doSend(collectPlayers(p -> p.dimensionId == dimension && canSend(p, channel)),channel, data); + } + + public static void send(String channel, CustomPayload payload) { + doSend(collectPlayers(p -> canSend(p, channel)), channel, payload); + } + + public static void send(String channel, IOConsumer writer) { + doSend(collectPlayers(p -> canSend(p, channel)), channel, writer); + } + + public static void send(String channel, byte[] data) { + doSend(collectPlayers(p -> canSend(p, channel)), channel, data); + } + + public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { + sendPacket(player, makePacket(channel, payload)); + } + + public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { + sendPacket(player, makePacket(channel, writer)); + } + + public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { + sendPacket(player, makePacket(channel, data)); + } + + public static void doSend(Iterable players, String channel, CustomPayload payload) { + sendPacket(players, makePacket(channel, payload)); + } + + public static void doSend(Iterable players, String channel, IOConsumer writer) { + sendPacket(players, makePacket(channel, writer)); + } + + public static void doSend(Iterable players, String channel, byte[] data) { + sendPacket(players, makePacket(channel, data)); + } + + public static void doSend(int dimension, String channel, CustomPayload payload) { + doSend(collectPlayers(p -> p.dimensionId == dimension), channel, payload); + } + + public static void doSend(int dimension, String channel, IOConsumer writer) { + doSend(collectPlayers(p -> p.dimensionId == dimension), channel, writer); + } + + public static void doSend(int dimension, String channel, byte[] data) { + doSend(collectPlayers(p -> p.dimensionId == dimension),channel, data); + } + + public static void doSend(String channel, CustomPayload payload) { + doSend(collectPlayers(p -> true), channel, payload); + } + + public static void doSend(String channel, IOConsumer writer) { + doSend(collectPlayers(p -> true), channel, writer); + } + + public static void doSend(String channel, byte[] data) { + doSend(collectPlayers(p -> true), channel, data); + } + + @SuppressWarnings("unchecked") // thanks proguard + private static Iterable collectPlayers(Predicate filter) { + return collectPlayers(server.playerManager.players, filter); + } + + private static Iterable collectPlayers(Iterable src, Predicate filter) { + List players = new ArrayList<>(); + + for (ServerPlayerEntity player : src) { + if (filter.test(player)) { + players.add(player); + } + } + + return players; + } + + private static Packet makePacket(String channel, CustomPayload payload) { + return makePacket(channel, payload::write); + } + + private static Packet makePacket(String channel, IOConsumer writer) { + try { + return new CustomPayloadPacket(channel, DataStreams.output(writer).toByteArray()); + } catch (IOException e) { + LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); + return null; + } + } + + private static Packet makePacket(String channel, byte[] data) { + return new CustomPayloadPacket(channel, data); + } + + private static void sendPacket(ServerPlayerEntity player, Packet packet) { + if (packet != null) { + player.networkHandler.sendPacket(packet); + } + } + + private static void sendPacket(Iterable players, Packet packet) { + if (packet != null) { + for (ServerPlayerEntity player : players) { + sendPacket(player, packet); + } + } + } + + private interface Listener { + + boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; + + } +} diff --git a/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/resources/osl.networking.mixins.json b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/resources/osl.networking.mixins.json new file mode 100644 index 00000000..56dbde5c --- /dev/null +++ b/libraries/networking/networking-server-mcb1.5-mc11w48a/src/main/resources/osl.networking.mixins.json @@ -0,0 +1,18 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.ornithemc.osl.networking.impl.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "common.PacketAccessor", + "common.ServerLoginNetworkHandlerMixin", + "common.ServerPlayNetworkHandlerMixin" + ], + "client": [ + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/settings.gradle b/settings.gradle index a29cc1a0..5d1dbb80 100644 --- a/settings.gradle +++ b/settings.gradle @@ -76,12 +76,14 @@ include ':libraries:lifecycle-events:lifecycle-events-mc18w30a-mc18w50a' include ':libraries:lifecycle-events:lifecycle-events-mc19w04a-mc1.14.4' include ':libraries:networking' -include ':libraries:networking:networking-client-mcb1.0-mc11w48a' +include ':libraries:networking:networking-client-mcb1.0-mcb1.4_01' +include ':libraries:networking:networking-client-mcb1.5-mc11w48a' include ':libraries:networking:networking-client-mc11w49a-mc12w17a' include ':libraries:networking:networking-client-mc12w18a-mc12w19a' include ':libraries:networking:networking-client-mc12w21a-mc12w27a' include ':libraries:networking:networking-client-mc12w30a-mc12w30e' -include ':libraries:networking:networking-server-mcb1.0-mc11w48a' +include ':libraries:networking:networking-server-mcb1.0-mcb1.4_01' +include ':libraries:networking:networking-server-mcb1.5-mc11w48a' include ':libraries:networking:networking-server-mc11w49a-mc12w16a' include ':libraries:networking:networking-server-mc12w17a-mc12w17a' include ':libraries:networking:networking-server-mc12w18a-mc12w19a'