diff --git a/src/main/java/net/fabricmc/fabric/api/event/network/C2SPacketTypeCallback.java b/src/main/java/net/fabricmc/fabric/api/event/network/C2SPacketTypeCallback.java new file mode 100644 index 000000000..ecb93e7b1 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/api/event/network/C2SPacketTypeCallback.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.event.network; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.Identifier; + +import java.util.Collection; + +public interface C2SPacketTypeCallback { + static final Event REGISTERED = EventFactory.createArrayBacked( + C2SPacketTypeCallback.class, + (callbacks) -> (client, types) -> { + for (C2SPacketTypeCallback callback : callbacks) { + callback.accept(client, types); + } + } + ); + + static final Event UNREGISTERED = EventFactory.createArrayBacked( + C2SPacketTypeCallback.class, + (callbacks) -> (client, types) -> { + for (C2SPacketTypeCallback callback : callbacks) { + callback.accept(client, types); + } + } + ); + + void accept(PlayerEntity client, Collection types); +} diff --git a/src/main/java/net/fabricmc/fabric/api/event/network/S2CPacketTypeCallback.java b/src/main/java/net/fabricmc/fabric/api/event/network/S2CPacketTypeCallback.java new file mode 100644 index 000000000..44dd8b37f --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/api/event/network/S2CPacketTypeCallback.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.event.network; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.Identifier; + +import java.util.Collection; + +public interface S2CPacketTypeCallback { + static final Event REGISTERED = EventFactory.createArrayBacked( + S2CPacketTypeCallback.class, + (callbacks) -> (types) -> { + for (S2CPacketTypeCallback callback : callbacks) { + callback.accept(types); + } + } + ); + + static final Event UNREGISTERED = EventFactory.createArrayBacked( + S2CPacketTypeCallback.class, + (callbacks) -> (types) -> { + for (S2CPacketTypeCallback callback : callbacks) { + callback.accept(types); + } + } + ); + + void accept(Collection types); +} diff --git a/src/main/java/net/fabricmc/fabric/api/network/ClientSidePacketRegistry.java b/src/main/java/net/fabricmc/fabric/api/network/ClientSidePacketRegistry.java new file mode 100644 index 000000000..883854a28 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/api/network/ClientSidePacketRegistry.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.network; + +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import net.fabricmc.fabric.impl.network.ClientSidePacketRegistryImpl; +import net.minecraft.network.Packet; +import net.minecraft.util.Identifier; +import net.minecraft.util.PacketByteBuf; + +/** + * The client-side packet registry. + * + * It is used for: + * + * - registering client-side packet receivers (server -> client packets) + * - sending packets to the server (client -> server packets). + */ +public interface ClientSidePacketRegistry extends PacketRegistry { + static final ClientSidePacketRegistry INSTANCE = new ClientSidePacketRegistryImpl(); + + /** + * Check if the server declared the ability to receive a given packet ID + * using the vanilla "register/unregister" protocol. + * + * @param id The packet identifier. + * @return True if the server side declared a given packet identifier. + */ + boolean canServerReceive(Identifier id); + + /** + * Send a packet to the server. + + * @param packet The packet to be sent. + * @param completionListener Completion listener. Can be used to check for + * the success or failure of sending a given packet, among others. + */ + void sendToServer(Packet packet, GenericFutureListener> completionListener); + + /** + * Send an identifier/buffer-based packet to the server. + + * @param id The packet identifier. + * @param buf The packet byte buffer. + * @param completionListener Completion listener. Can be used to check for + * the success or failure of sending a given packet, among others. + */ + default void sendToServer(Identifier id, PacketByteBuf buf, GenericFutureListener> completionListener) { + sendToServer(toPacket(id, buf), completionListener); + } + + /** + * Send a packet to the server. + + * @param packet The packet to be sent. + */ + default void sendToServer(Packet packet) { + sendToServer(packet, null); + } + + /** + * Send an identifier/buffer-based packet to the server. + + * @param id The packet identifier. + * @param buf The packet byte buffer. + */ + default void sendToServer(Identifier id, PacketByteBuf buf) { + sendToServer(id, buf, null); + } +} diff --git a/src/main/java/net/fabricmc/fabric/api/network/CustomPayloadPacketRegistry.java b/src/main/java/net/fabricmc/fabric/api/network/CustomPayloadPacketRegistry.java deleted file mode 100644 index 8b7fd5cc6..000000000 --- a/src/main/java/net/fabricmc/fabric/api/network/CustomPayloadPacketRegistry.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2016, 2017, 2018 FabricMC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.fabricmc.fabric.api.network; - -import net.minecraft.util.Identifier; -import net.minecraft.util.PacketByteBuf; - -import java.util.Collection; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.BiConsumer; - -/** - * Registry for CustomPayload-based packet handling. You can use this - * to register your own CustomPayload packet handlers. - */ -public class CustomPayloadPacketRegistry { - public static final CustomPayloadPacketRegistry CLIENT = new CustomPayloadPacketRegistry(); - public static final CustomPayloadPacketRegistry SERVER = new CustomPayloadPacketRegistry(); - - protected final Map> consumerMap; - - protected CustomPayloadPacketRegistry() { - consumerMap = new LinkedHashMap<>(); - } - - /** - * Register a packet. - * - * @param id The packet Identifier. - * @param consumer The method used for handling the packet. - */ - public void register(Identifier id, BiConsumer consumer) { - if (consumerMap.containsKey(id)) { - // TODO: log warning - } - - consumerMap.put(id, consumer); - } - - /** - * Hook for accepting packets used in Fabric mixins. - * - * @param id The packet Identifier received. - * @param context The packet context provided. - * @param buf The packet data buffer received. - * @return Whether or not the packet was handled by this packet registry. - */ - public boolean accept(Identifier id, PacketContext context, PacketByteBuf buf) { - BiConsumer consumer = consumerMap.get(id); - if (consumer != null) { - try { - consumer.accept(context, buf); - } catch (Throwable t) { - // TODO: handle better - t.printStackTrace(); - } - return true; - } else { - return false; - } - } -} diff --git a/src/main/java/net/fabricmc/fabric/api/network/PacketConsumer.java b/src/main/java/net/fabricmc/fabric/api/network/PacketConsumer.java new file mode 100644 index 000000000..adc1a81d3 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/api/network/PacketConsumer.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.network; + +import net.minecraft.util.PacketByteBuf; + +/** + * Interface for receiving CustomPayload-based packets. + */ +@FunctionalInterface +public interface PacketConsumer { + /** + * Receive a CustomPayload-based packet. + * + * Please keep in mind that this CAN be called OUTSIDE of the main thread! + * Most game operations are not thread-safe, so you should look into using + * the thread task queue ({@link PacketContext#getTaskQueue()}) to split + * the "reading" (which should, but does not have to, happen off-thread) + * and "applying" (which, unless you know what you're doing, should happen + * on the main thread). + * + * @param context The context (receiving player, side, etc.) + * @param buffer The byte buffer containing the received packet data. + */ + void accept(PacketContext context, PacketByteBuf buffer); +} diff --git a/src/main/java/net/fabricmc/fabric/api/network/PacketRegistry.java b/src/main/java/net/fabricmc/fabric/api/network/PacketRegistry.java new file mode 100644 index 000000000..854c51e4b --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/api/network/PacketRegistry.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.network; + +import net.minecraft.network.Packet; +import net.minecraft.util.Identifier; +import net.minecraft.util.PacketByteBuf; + +public interface PacketRegistry { + /** + * Turn a (identifier, byte buffer) pair into a "custom payload" packet + * suitable for sending in the PacketRegistry's sending direction. + * + * @param id The identifier. + * @param buf The byte buffer. + * @return + */ + Packet toPacket(Identifier id, PacketByteBuf buf); + + /** + * Register a packet. + * + * @param id The packet Identifier. + * @param consumer The method used for handling the packet. + */ + void register(Identifier id, PacketConsumer consumer); + + /** + * Unregister a packet. + * + * @param id The packet Identifier. + */ + void unregister(Identifier id); +} diff --git a/src/main/java/net/fabricmc/fabric/api/network/ServerSidePacketRegistry.java b/src/main/java/net/fabricmc/fabric/api/network/ServerSidePacketRegistry.java new file mode 100644 index 000000000..6e1fbdd62 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/api/network/ServerSidePacketRegistry.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.network; + +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import net.fabricmc.fabric.api.server.PlayerStream; +import net.fabricmc.fabric.impl.network.ServerSidePacketRegistryImpl; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.Packet; +import net.minecraft.util.Identifier; +import net.minecraft.util.PacketByteBuf; + +/** + * The server-side packet registry. + * + * It is used for: + * + * - registering server-side packet receivers (client -> server packets) + * - sending packets to clients (server -> client packets). + * + * For iterating over clients in a server, see {@link PlayerStream}. + */ +public interface ServerSidePacketRegistry extends PacketRegistry { + static final ServerSidePacketRegistry INSTANCE = new ServerSidePacketRegistryImpl(); + + /** + * Check if a given client declared the ability to receive a given packet ID + * using the vanilla "register/unregister" protocol. + * + * @param id The packet identifier. + * @return True if the client side declared a given packet identifier. + */ + boolean canPlayerReceive(PlayerEntity player, Identifier id); + + /** + * Send a packet to a given client. + * + * @param player The given client. + * @param packet The packet to be sent. + * @param completionListener Completion listener. Can be used to check for + * the success or failure of sending a given packet, among others. + */ + void sendToPlayer(PlayerEntity player, Packet packet, GenericFutureListener> completionListener); + + /** + * Send an identifier/buffer-based packet to a given client. + * + * @param player The given client. + * @param id The packet identifier. + * @param buf The packet byte buffer. + * @param completionListener Completion listener. Can be used to check for + * the success or failure of sending a given packet, among others. + */ + default void sendToPlayer(PlayerEntity player, Identifier id, PacketByteBuf buf, GenericFutureListener> completionListener) { + sendToPlayer(player, toPacket(id, buf), completionListener); + } + + /** + * Send a packet to a given client. + * + * @param player The given client. + * @param packet The packet to be sent. + */ + default void sendToPlayer(PlayerEntity player, Packet packet) { + sendToPlayer(player, packet, null); + } + + /** + * Send an identifier/buffer-based packet to a given client. + * + * @param player The given client. + * @param id The packet identifier. + * @param buf The packet byte buffer. + */ + default void sendToPlayer(PlayerEntity player, Identifier id, PacketByteBuf buf) { + sendToPlayer(player, id, buf, null); + } +} diff --git a/src/main/java/net/fabricmc/fabric/api/server/PlayerStream.java b/src/main/java/net/fabricmc/fabric/api/server/PlayerStream.java new file mode 100644 index 000000000..66e34cb0c --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/api/server/PlayerStream.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.server; + +import net.fabricmc.fabric.impl.server.EntityTrackerStreamAccessor; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.EntityTracker; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraft.world.chunk.ChunkPos; + +import java.util.stream.Stream; + +/** + * Helper streams for looking up players on a server. + * + * In general, most of these methods will only function with a {@link ServerWorld} instance. + */ +public final class PlayerStream { + private PlayerStream() { + + } + + public static Stream all(MinecraftServer server) { + return server.getPlayerManager().getPlayerList().stream(); + } + + public static Stream world(World world) { + return world.players.stream(); + } + + public static Stream watching(World world, ChunkPos pos) { + if (!(world instanceof ServerWorld)) { + throw new RuntimeException("Only supported on ServerWorld!"); + } else { + // noinspection unchecked + return ((Stream) (Stream) ((ServerWorld) world).getChunkManager().getPlayersWatchingChunk(pos, false, false)); + } + } + + /** + * Warning: If the provided entity is a PlayerEntity themselves, it is not + * guaranteed by the contract that said PlayerEntity is included in the + * resulting stream. + */ + @SuppressWarnings("JavaDoc") + public static Stream watching(Entity entity) { + World world = entity.getEntityWorld(); + + if (world instanceof ServerWorld) { + EntityTracker tracker = ((ServerWorld) world).getEntityTracker(); + if (tracker instanceof EntityTrackerStreamAccessor) { + //noinspection unchecked + return ((Stream) (Stream) ((EntityTrackerStreamAccessor) tracker).fabric_getTrackingPlayers(entity)); + } + } + + // fallback + return watching(world, new ChunkPos((int) (entity.x / 16.0D), (int) (entity.z / 16.0D))); + } + + public static Stream watching(BlockEntity entity) { + return watching(entity.getWorld(), entity.getPos()); + } + + public static Stream watching(World world, BlockPos pos) { + return watching(world, new ChunkPos(pos)); + } + + public static Stream around(World world, Vec3d vector, double radius) { + double radiusSq = radius * radius; + return world(world).filter((p) -> p.squaredDistanceTo(vector) <= radiusSq); + } + + public static Stream around(World world, BlockPos pos, double radius) { + double radiusSq = radius * radius; + return world(world).filter((p) -> p.squaredDistanceToCenter(pos) <= radiusSq); + } +} \ No newline at end of file diff --git a/src/main/java/net/fabricmc/fabric/api/tags/FabricBlockTags.java b/src/main/java/net/fabricmc/fabric/api/tag/FabricBlockTags.java similarity index 96% rename from src/main/java/net/fabricmc/fabric/api/tags/FabricBlockTags.java rename to src/main/java/net/fabricmc/fabric/api/tag/FabricBlockTags.java index 7183bee4c..a8be94fcf 100644 --- a/src/main/java/net/fabricmc/fabric/api/tags/FabricBlockTags.java +++ b/src/main/java/net/fabricmc/fabric/api/tag/FabricBlockTags.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.api.tags; +package net.fabricmc.fabric.api.tag; import net.minecraft.block.Block; import net.minecraft.tag.Tag; diff --git a/src/main/java/net/fabricmc/fabric/api/tags/FabricItemTags.java b/src/main/java/net/fabricmc/fabric/api/tag/FabricItemTags.java similarity index 96% rename from src/main/java/net/fabricmc/fabric/api/tags/FabricItemTags.java rename to src/main/java/net/fabricmc/fabric/api/tag/FabricItemTags.java index a75f2e08f..ed1929ee0 100644 --- a/src/main/java/net/fabricmc/fabric/api/tags/FabricItemTags.java +++ b/src/main/java/net/fabricmc/fabric/api/tag/FabricItemTags.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.api.tags; +package net.fabricmc.fabric.api.tag; import net.minecraft.item.Item; import net.minecraft.tag.Tag; diff --git a/src/main/java/net/fabricmc/fabric/api/tags/TagDelegate.java b/src/main/java/net/fabricmc/fabric/api/tag/TagDelegate.java similarity index 96% rename from src/main/java/net/fabricmc/fabric/api/tags/TagDelegate.java rename to src/main/java/net/fabricmc/fabric/api/tag/TagDelegate.java index d333fc851..813f644b8 100644 --- a/src/main/java/net/fabricmc/fabric/api/tags/TagDelegate.java +++ b/src/main/java/net/fabricmc/fabric/api/tag/TagDelegate.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.api.tags; +package net.fabricmc.fabric.api.tag; import net.minecraft.tag.Tag; import net.minecraft.util.Identifier; diff --git a/src/main/java/net/fabricmc/fabric/api/tags/TagRegistry.java b/src/main/java/net/fabricmc/fabric/api/tag/TagRegistry.java similarity index 97% rename from src/main/java/net/fabricmc/fabric/api/tags/TagRegistry.java rename to src/main/java/net/fabricmc/fabric/api/tag/TagRegistry.java index b989bc164..b03e21c7e 100644 --- a/src/main/java/net/fabricmc/fabric/api/tags/TagRegistry.java +++ b/src/main/java/net/fabricmc/fabric/api/tag/TagRegistry.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package net.fabricmc.fabric.api.tags; +package net.fabricmc.fabric.api.tag; import net.minecraft.block.Block; import net.minecraft.item.Item; diff --git a/src/main/java/net/fabricmc/fabric/impl/FabricAPIClientInitializer.java b/src/main/java/net/fabricmc/fabric/impl/FabricAPIClientInitializer.java index 33457179d..1bf2b03c2 100644 --- a/src/main/java/net/fabricmc/fabric/impl/FabricAPIClientInitializer.java +++ b/src/main/java/net/fabricmc/fabric/impl/FabricAPIClientInitializer.java @@ -17,15 +17,15 @@ package net.fabricmc.fabric.impl; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; import net.fabricmc.fabric.impl.client.gui.ScreenProviderRegistryImpl; -import net.fabricmc.fabric.api.network.CustomPayloadPacketRegistry; import net.fabricmc.fabric.impl.registry.RegistrySyncManager; import net.minecraft.client.MinecraftClient; public class FabricAPIClientInitializer implements ClientModInitializer { @Override public void onInitializeClient() { - CustomPayloadPacketRegistry.CLIENT.register(RegistrySyncManager.ID, (ctx, buf) -> { + ClientSidePacketRegistry.INSTANCE.register(RegistrySyncManager.ID, (ctx, buf) -> { // if not hosting server, apply packet RegistrySyncManager.receivePacket(ctx, buf, !MinecraftClient.getInstance().isInSingleplayer()); }); diff --git a/src/main/java/net/fabricmc/fabric/impl/client/gui/ScreenProviderRegistryImpl.java b/src/main/java/net/fabricmc/fabric/impl/client/gui/ScreenProviderRegistryImpl.java index 51e5e73e2..a45b09faf 100644 --- a/src/main/java/net/fabricmc/fabric/impl/client/gui/ScreenProviderRegistryImpl.java +++ b/src/main/java/net/fabricmc/fabric/impl/client/gui/ScreenProviderRegistryImpl.java @@ -19,8 +19,9 @@ package net.fabricmc.fabric.impl.client.gui; import net.fabricmc.fabric.api.client.screen.ContainerScreenFactory; import net.fabricmc.fabric.api.client.screen.ScreenProviderRegistry; import net.fabricmc.fabric.api.container.ContainerFactory; +import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; import net.fabricmc.fabric.impl.container.ContainerProviderImpl; -import net.fabricmc.fabric.api.network.CustomPayloadPacketRegistry; +import net.fabricmc.fabric.impl.network.PacketTypes; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.ContainerScreen; import net.minecraft.container.Container; @@ -40,7 +41,6 @@ public class ScreenProviderRegistryImpl implements ScreenProviderRegistry { private static final Logger LOGGER = LogManager.getLogger(); - private static final Identifier OPEN_CONTAINER = new Identifier("fabric", "open_container"); private static final Map> FACTORIES = new HashMap<>(); public void registerFactory(Identifier identifier, ContainerFactory factory) { @@ -63,7 +63,7 @@ public class ScreenProviderRegistryImpl implements ScreenProviderRegistry { } public void init() { - CustomPayloadPacketRegistry.CLIENT.register(OPEN_CONTAINER, (packetContext, packetByteBuf) -> { + ClientSidePacketRegistry.INSTANCE.register(PacketTypes.OPEN_CONTAINER, (packetContext, packetByteBuf) -> { Identifier identifier = packetByteBuf.readIdentifier(); int syncId = packetByteBuf.readUnsignedByte(); MinecraftClient.getInstance().execute(() -> { diff --git a/src/main/java/net/fabricmc/fabric/impl/container/ContainerProviderImpl.java b/src/main/java/net/fabricmc/fabric/impl/container/ContainerProviderImpl.java index b68c5d4a3..d10ed6dc0 100644 --- a/src/main/java/net/fabricmc/fabric/impl/container/ContainerProviderImpl.java +++ b/src/main/java/net/fabricmc/fabric/impl/container/ContainerProviderImpl.java @@ -19,6 +19,7 @@ package net.fabricmc.fabric.impl.container; import io.netty.buffer.Unpooled; import net.fabricmc.fabric.api.container.ContainerFactory; import net.fabricmc.fabric.api.container.ContainerProviderRegistry; +import net.fabricmc.fabric.impl.network.PacketTypes; import net.minecraft.client.network.packet.CustomPayloadClientPacket; import net.minecraft.container.Container; import net.minecraft.entity.player.PlayerEntity; @@ -41,7 +42,6 @@ public class ContainerProviderImpl implements ContainerProviderRegistry { private static final Logger LOGGER = LogManager.getLogger(); - private static final Identifier OPEN_CONTAINER = new Identifier("fabric", "open_container"); private static final Map> FACTORIES = new HashMap<>(); @Override @@ -71,7 +71,7 @@ public class ContainerProviderImpl implements ContainerProviderRegistry { buf.writeByte(syncId); writer.accept(buf); - player.networkHandler.sendPacket(new CustomPayloadClientPacket(OPEN_CONTAINER, buf)); + player.networkHandler.sendPacket(new CustomPayloadClientPacket(PacketTypes.OPEN_CONTAINER, buf)); PacketByteBuf clonedBuf = new PacketByteBuf(buf.duplicate()); clonedBuf.readIdentifier(); @@ -91,6 +91,7 @@ public class ContainerProviderImpl implements ContainerProviderRegistry { LOGGER.error("No container factory found for {}!", identifier.toString()); return null; } + //noinspection unchecked return (C) factory.create(syncId, identifier, player, buf); } } diff --git a/src/main/java/net/fabricmc/fabric/impl/network/ClientSidePacketRegistryImpl.java b/src/main/java/net/fabricmc/fabric/impl/network/ClientSidePacketRegistryImpl.java new file mode 100644 index 000000000..b91ccd373 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/impl/network/ClientSidePacketRegistryImpl.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.network; + +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import net.fabricmc.fabric.api.event.network.S2CPacketTypeCallback; +import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; +import net.fabricmc.fabric.api.network.PacketContext; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.network.Packet; +import net.minecraft.server.network.packet.CustomPayloadServerPacket; +import net.minecraft.util.Identifier; +import net.minecraft.util.PacketByteBuf; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; + +public class ClientSidePacketRegistryImpl extends PacketRegistryImpl implements ClientSidePacketRegistry { + private final Collection serverPayloadIds = new HashSet<>(); + + public static void invalidateRegisteredIdList() { + ((ClientSidePacketRegistryImpl) ClientSidePacketRegistry.INSTANCE).serverPayloadIds.clear(); + } + + @Override + public boolean canServerReceive(Identifier id) { + return serverPayloadIds.contains(id); + } + + @Override + public void sendToServer(Packet packet, GenericFutureListener> completionListener) { + ClientPlayNetworkHandler handler = MinecraftClient.getInstance().getNetworkHandler(); + if (handler != null) { + if (completionListener == null) { + // stay closer to the vanilla codepath + handler.sendPacket(packet); + } else { + handler.getClientConnection().sendPacket(packet, completionListener); + } + } else { + // TODO: log warning + } + } + + @Override + public Packet toPacket(Identifier id, PacketByteBuf buf) { + return new CustomPayloadServerPacket(id, buf); + } + + @Override + protected void onRegister(Identifier id) { + ClientPlayNetworkHandler handler = MinecraftClient.getInstance().getNetworkHandler(); + if (handler != null) { + handler.sendPacket(createRegisterTypePacket(PacketTypes.REGISTER, Collections.singleton(id))); + } + } + + @Override + protected void onUnregister(Identifier id) { + ClientPlayNetworkHandler handler = MinecraftClient.getInstance().getNetworkHandler(); + if (handler != null) { + handler.sendPacket(createRegisterTypePacket(PacketTypes.UNREGISTER, Collections.singleton(id))); + } + } + + @Override + protected Collection getIdCollectionFor(PacketContext context) { + return serverPayloadIds; + } + + @Override + protected void onReceivedRegisterPacket(PacketContext context, Collection ids) { + S2CPacketTypeCallback.REGISTERED.invoker().accept(ids); + } + + @Override + protected void onReceivedUnregisterPacket(PacketContext context, Collection ids) { + S2CPacketTypeCallback.UNREGISTERED.invoker().accept(ids); + } +} diff --git a/src/main/java/net/fabricmc/fabric/impl/network/SPacketCustomPayloadAccessor.java b/src/main/java/net/fabricmc/fabric/impl/network/CustomPayloadC2SPacketAccessor.java similarity index 94% rename from src/main/java/net/fabricmc/fabric/impl/network/SPacketCustomPayloadAccessor.java rename to src/main/java/net/fabricmc/fabric/impl/network/CustomPayloadC2SPacketAccessor.java index 6e14a35e3..7c66a87c9 100644 --- a/src/main/java/net/fabricmc/fabric/impl/network/SPacketCustomPayloadAccessor.java +++ b/src/main/java/net/fabricmc/fabric/impl/network/CustomPayloadC2SPacketAccessor.java @@ -23,7 +23,7 @@ import net.minecraft.util.PacketByteBuf; * Helper interface containing getters for SPacketCustomPayload * which were omitted from the compiled game. */ -public interface SPacketCustomPayloadAccessor { +public interface CustomPayloadC2SPacketAccessor { Identifier getChannel(); PacketByteBuf getData(); } diff --git a/src/main/java/net/fabricmc/fabric/impl/network/PacketRegistryImpl.java b/src/main/java/net/fabricmc/fabric/impl/network/PacketRegistryImpl.java new file mode 100644 index 000000000..96b7e4ef7 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/impl/network/PacketRegistryImpl.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.network; + +import io.netty.buffer.Unpooled; +import net.fabricmc.fabric.api.network.PacketConsumer; +import net.fabricmc.fabric.api.network.PacketContext; +import net.fabricmc.fabric.api.network.PacketRegistry; +import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; +import net.minecraft.network.Packet; +import net.minecraft.util.Identifier; +import net.minecraft.util.PacketByteBuf; + +import java.util.*; + +public abstract class PacketRegistryImpl implements PacketRegistry { + protected final Map consumerMap; + + PacketRegistryImpl() { + consumerMap = new LinkedHashMap<>(); + } + + public static Packet createInitialRegisterPacket(PacketRegistry registry) { + PacketRegistryImpl impl = (PacketRegistryImpl) registry; + return impl.createRegisterTypePacket(PacketTypes.REGISTER, impl.consumerMap.keySet()); + } + + @Override + public void register(Identifier id, PacketConsumer consumer) { + boolean isNew = true; + if (consumerMap.containsKey(id)) { + // TODO: log warning + isNew = false; + } + + consumerMap.put(id, consumer); + if (isNew) { + onRegister(id); + } + } + + @Override + public void unregister(Identifier id) { + consumerMap.remove(id); + onUnregister(id); + } + + protected abstract void onRegister(Identifier id); + protected abstract void onUnregister(Identifier id); + protected abstract Collection getIdCollectionFor(PacketContext context); + protected abstract void onReceivedRegisterPacket(PacketContext context, Collection ids); + protected abstract void onReceivedUnregisterPacket(PacketContext context, Collection ids); + + protected Packet createRegisterTypePacket(Identifier id, Collection ids) { + PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); + for (Identifier a : ids) { + buf.writeString(a.toString()); + } + return toPacket(id, buf); + } + + /** + * Hook for accepting packets used in Fabric mixins. + * + * @param id The packet Identifier received. + * @param context The packet context provided. + * @param buf The packet data buffer received. + * @return Whether or not the packet was handled by this packet registry. + */ + public boolean accept(Identifier id, PacketContext context, PacketByteBuf buf) { + if (id.equals(PacketTypes.REGISTER) || id.equals(PacketTypes.UNREGISTER)) { + Collection ids = new HashSet<>(); + while (buf.readerIndex() < buf.writerIndex() /* TODO: check correctness */) { + Identifier newId = new Identifier(buf.readString(32767)); + ids.add(newId); + } + + Collection target = getIdCollectionFor(context); + if (id.equals(PacketTypes.UNREGISTER)) { + target.removeAll(ids); + onReceivedUnregisterPacket(context, ids); + } else { + target.addAll(ids); + onReceivedRegisterPacket(context, ids); + } + return false; // continue execution for other mods + } + + PacketConsumer consumer = consumerMap.get(id); + if (consumer != null) { + try { + consumer.accept(context, buf); + } catch (Throwable t) { + // TODO: handle better + t.printStackTrace(); + } + return true; + } else { + return false; + } + } +} diff --git a/src/main/java/net/fabricmc/fabric/impl/network/PacketTypes.java b/src/main/java/net/fabricmc/fabric/impl/network/PacketTypes.java new file mode 100644 index 000000000..c9f3fa502 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/impl/network/PacketTypes.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.network; + +import net.minecraft.util.Identifier; + +public final class PacketTypes { + static final Identifier BRAND = new Identifier("minecraft:brand"); + static final Identifier REGISTER = new Identifier("minecraft:register"); + static final Identifier UNREGISTER = new Identifier("minecraft:unregister"); + + public static final Identifier OPEN_CONTAINER = new Identifier("fabric", "container/open"); +} diff --git a/src/main/java/net/fabricmc/fabric/impl/network/ServerSidePacketRegistryImpl.java b/src/main/java/net/fabricmc/fabric/impl/network/ServerSidePacketRegistryImpl.java new file mode 100644 index 000000000..686d37673 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/impl/network/ServerSidePacketRegistryImpl.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.network; + +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; +import net.fabricmc.fabric.api.event.network.C2SPacketTypeCallback; +import net.fabricmc.fabric.api.network.PacketContext; +import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; +import net.fabricmc.fabric.api.server.PlayerStream; +import net.fabricmc.loader.FabricLoader; +import net.minecraft.client.network.packet.CustomPayloadClientPacket; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.Packet; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; +import net.minecraft.util.PacketByteBuf; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.WeakHashMap; + +public class ServerSidePacketRegistryImpl extends PacketRegistryImpl implements ServerSidePacketRegistry { + private final WeakHashMap> playerPayloadIds = new WeakHashMap<>(); + + @Override + public boolean canPlayerReceive(PlayerEntity player, Identifier id) { + Collection ids = playerPayloadIds.get(player); + if (ids != null) { + return ids.contains(id); + } else { + return false; + } + } + + @Override + public void sendToPlayer(PlayerEntity player, Packet packet, GenericFutureListener> completionListener) { + if (!(player instanceof ServerPlayerEntity)) { + throw new RuntimeException("Can only send to ServerPlayerEntities!"); + } else { + ((ServerPlayerEntity) player).networkHandler.sendPacket(packet, completionListener); + } + } + + @Override + public Packet toPacket(Identifier id, PacketByteBuf buf) { + return new CustomPayloadClientPacket(id, buf); + } + + @Override + protected void onRegister(Identifier id) { + MinecraftServer server = FabricLoader.INSTANCE.getEnvironmentHandler().getServerInstance(); + if (server != null) { + Packet packet = createRegisterTypePacket(PacketTypes.REGISTER, Collections.singleton(id)); + PlayerStream.all(server).forEach((p) -> sendToPlayer(p, packet)); + } + } + + @Override + protected void onUnregister(Identifier id) { + MinecraftServer server = FabricLoader.INSTANCE.getEnvironmentHandler().getServerInstance(); + if (server != null) { + Packet packet = createRegisterTypePacket(PacketTypes.UNREGISTER, Collections.singleton(id)); + PlayerStream.all(server).forEach((p) -> sendToPlayer(p, packet)); + } + } + + @Override + protected Collection getIdCollectionFor(PacketContext context) { + return playerPayloadIds.computeIfAbsent(context.getPlayer(), (p) -> new HashSet<>()); + } + + @Override + protected void onReceivedRegisterPacket(PacketContext context, Collection ids) { + C2SPacketTypeCallback.REGISTERED.invoker().accept(context.getPlayer(), ids); + } + + @Override + protected void onReceivedUnregisterPacket(PacketContext context, Collection ids) { + C2SPacketTypeCallback.UNREGISTERED.invoker().accept(context.getPlayer(), ids); + } +} diff --git a/src/main/java/net/fabricmc/fabric/impl/registry/RegistrySyncManager.java b/src/main/java/net/fabricmc/fabric/impl/registry/RegistrySyncManager.java index 8120280e1..cdd4d1838 100644 --- a/src/main/java/net/fabricmc/fabric/impl/registry/RegistrySyncManager.java +++ b/src/main/java/net/fabricmc/fabric/impl/registry/RegistrySyncManager.java @@ -21,8 +21,9 @@ import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import net.fabricmc.fabric.api.network.PacketContext; -import net.minecraft.client.network.packet.CustomPayloadClientPacket; +import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.Packet; import net.minecraft.util.Identifier; import net.minecraft.util.PacketByteBuf; import net.minecraft.util.registry.IdRegistry; @@ -43,12 +44,11 @@ public final class RegistrySyncManager { } - public static CustomPayloadClientPacket createPacket() { + public static Packet createPacket() { PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); buf.writeCompoundTag(toTag(true)); - CustomPayloadClientPacket packet = new CustomPayloadClientPacket(ID, buf); - return packet; + return ServerSidePacketRegistry.INSTANCE.toPacket(ID, buf); } public static void receivePacket(PacketContext context, PacketByteBuf buf, boolean accept) { @@ -120,4 +120,13 @@ public final class RegistrySyncManager { } } } + + public static void unmap() throws RemapException { + for (Identifier registryId : Registry.REGISTRIES.keys()) { + ModifiableRegistry registry = Registry.REGISTRIES.get(registryId); + if (registry instanceof RemappableRegistry) { + ((RemappableRegistry) registry).unmap(); + } + } + } } diff --git a/src/main/java/net/fabricmc/fabric/impl/server/EntityTrackerEntryStreamAccessor.java b/src/main/java/net/fabricmc/fabric/impl/server/EntityTrackerEntryStreamAccessor.java new file mode 100644 index 000000000..5482d3111 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/impl/server/EntityTrackerEntryStreamAccessor.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.server; + +import net.minecraft.entity.Entity; +import net.minecraft.server.network.ServerPlayerEntity; + +import java.util.stream.Stream; + +public interface EntityTrackerEntryStreamAccessor { + Stream fabric_getTrackingPlayers(); +} diff --git a/src/main/java/net/fabricmc/fabric/impl/server/EntityTrackerStreamAccessor.java b/src/main/java/net/fabricmc/fabric/impl/server/EntityTrackerStreamAccessor.java new file mode 100644 index 000000000..102dc466b --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/impl/server/EntityTrackerStreamAccessor.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.impl.server; + +import net.minecraft.entity.Entity; +import net.minecraft.server.network.ServerPlayerEntity; + +import java.util.stream.Stream; + +public interface EntityTrackerStreamAccessor { + Stream fabric_getTrackingPlayers(Entity entity); +} diff --git a/src/main/java/net/fabricmc/fabric/mixin/entity/MixinEntityTracker.java b/src/main/java/net/fabricmc/fabric/mixin/entity/MixinEntityTracker.java index 8a40c45dd..a284998e3 100644 --- a/src/main/java/net/fabricmc/fabric/mixin/entity/MixinEntityTracker.java +++ b/src/main/java/net/fabricmc/fabric/mixin/entity/MixinEntityTracker.java @@ -17,16 +17,25 @@ package net.fabricmc.fabric.mixin.entity; import net.fabricmc.fabric.api.entity.EntityTrackingRegistry; +import net.fabricmc.fabric.impl.server.EntityTrackerEntryStreamAccessor; +import net.fabricmc.fabric.impl.server.EntityTrackerStreamAccessor; import net.minecraft.entity.Entity; import net.minecraft.server.network.EntityTracker; +import net.minecraft.server.network.EntityTrackerEntry; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.IntHashMap; 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 java.util.stream.Stream; + @Mixin(EntityTracker.class) -public abstract class MixinEntityTracker { +public abstract class MixinEntityTracker implements EntityTrackerStreamAccessor { + @Shadow + private IntHashMap trackedEntitiesById; @Shadow public abstract void add(Entity var1, int var2, int var3, boolean var4); @@ -40,4 +49,14 @@ public abstract class MixinEntityTracker { } } } + + @Override + public Stream fabric_getTrackingPlayers(Entity entity) { + EntityTrackerEntry entry = trackedEntitiesById.get(entity.getEntityId()); + if (entry != null) { + return ((EntityTrackerEntryStreamAccessor) entry).fabric_getTrackingPlayers(); + } else { + return Stream.empty(); + } + } } diff --git a/src/main/java/net/fabricmc/fabric/mixin/entity/MixinEntityTrackerEntry.java b/src/main/java/net/fabricmc/fabric/mixin/entity/MixinEntityTrackerEntry.java new file mode 100644 index 000000000..278f6423e --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/mixin/entity/MixinEntityTrackerEntry.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.entity; + +import net.fabricmc.fabric.impl.server.EntityTrackerEntryStreamAccessor; +import net.minecraft.server.network.EntityTrackerEntry; +import net.minecraft.server.network.ServerPlayerEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Set; +import java.util.stream.Stream; + +@Mixin(EntityTrackerEntry.class) +public class MixinEntityTrackerEntry implements EntityTrackerEntryStreamAccessor { + @Shadow + private Set trackingPlayers; + + @Override + public Stream fabric_getTrackingPlayers() { + return trackingPlayers.stream(); + } +} diff --git a/src/main/java/net/fabricmc/fabric/mixin/networking/MixinClientPlayNetworkHandler.java b/src/main/java/net/fabricmc/fabric/mixin/networking/MixinClientPlayNetworkHandler.java index 1e14ae653..cff4985d5 100644 --- a/src/main/java/net/fabricmc/fabric/mixin/networking/MixinClientPlayNetworkHandler.java +++ b/src/main/java/net/fabricmc/fabric/mixin/networking/MixinClientPlayNetworkHandler.java @@ -16,13 +16,23 @@ package net.fabricmc.fabric.mixin.networking; +import com.mojang.authlib.GameProfile; import net.fabricmc.api.EnvType; -import net.fabricmc.fabric.api.network.CustomPayloadPacketRegistry; +import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; import net.fabricmc.fabric.api.network.PacketContext; +import net.fabricmc.fabric.impl.network.ClientSidePacketRegistryImpl; +import net.fabricmc.fabric.impl.network.PacketRegistryImpl; +import net.minecraft.class_2901; import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.Screen; import net.minecraft.client.network.ClientPlayNetworkHandler; import net.minecraft.client.network.packet.CustomPayloadClientPacket; +import net.minecraft.client.network.packet.GameJoinClientPacket; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.Packet; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.util.ThreadTaskQueue; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -31,13 +41,21 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(ClientPlayNetworkHandler.class) -public class MixinClientPlayNetworkHandler implements PacketContext { +public abstract class MixinClientPlayNetworkHandler implements PacketContext { @Shadow private MinecraftClient client; + @Shadow + public abstract void sendPacket(Packet var1); + + @Inject(at = @At("RETURN"), method = "onGameJoin") + public void onGameJoin(GameJoinClientPacket packet, CallbackInfo info) { + sendPacket(PacketRegistryImpl.createInitialRegisterPacket(ClientSidePacketRegistry.INSTANCE)); + } + @Inject(method = "onCustomPayload", at = @At("HEAD"), cancellable = true) public void onCustomPayload(CustomPayloadClientPacket packet, CallbackInfo info) { - if (CustomPayloadPacketRegistry.CLIENT.accept(packet.getChannel(), this, packet.getData())) { + if (((ClientSidePacketRegistryImpl) ClientSidePacketRegistry.INSTANCE).accept(packet.getChannel(), this, packet.getData())) { info.cancel(); } } diff --git a/src/main/java/net/fabricmc/fabric/mixin/networking/MixinSPacketCustomPayload.java b/src/main/java/net/fabricmc/fabric/mixin/networking/MixinCustomPayloadC2SPacket.java similarity index 87% rename from src/main/java/net/fabricmc/fabric/mixin/networking/MixinSPacketCustomPayload.java rename to src/main/java/net/fabricmc/fabric/mixin/networking/MixinCustomPayloadC2SPacket.java index a44f0aad2..d6c08db92 100644 --- a/src/main/java/net/fabricmc/fabric/mixin/networking/MixinSPacketCustomPayload.java +++ b/src/main/java/net/fabricmc/fabric/mixin/networking/MixinCustomPayloadC2SPacket.java @@ -16,7 +16,7 @@ package net.fabricmc.fabric.mixin.networking; -import net.fabricmc.fabric.impl.network.SPacketCustomPayloadAccessor; +import net.fabricmc.fabric.impl.network.CustomPayloadC2SPacketAccessor; import net.minecraft.server.network.packet.CustomPayloadServerPacket; import net.minecraft.util.Identifier; import net.minecraft.util.PacketByteBuf; @@ -24,7 +24,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @Mixin(CustomPayloadServerPacket.class) -public class MixinSPacketCustomPayload implements SPacketCustomPayloadAccessor { +public class MixinCustomPayloadC2SPacket implements CustomPayloadC2SPacketAccessor { @Shadow private Identifier channel; @Shadow diff --git a/src/main/java/net/fabricmc/fabric/mixin/networking/MixinServerPlayNetworkHandler.java b/src/main/java/net/fabricmc/fabric/mixin/networking/MixinServerPlayNetworkHandler.java index 2877a2db4..5e36e199e 100644 --- a/src/main/java/net/fabricmc/fabric/mixin/networking/MixinServerPlayNetworkHandler.java +++ b/src/main/java/net/fabricmc/fabric/mixin/networking/MixinServerPlayNetworkHandler.java @@ -17,9 +17,10 @@ package net.fabricmc.fabric.mixin.networking; import net.fabricmc.api.EnvType; -import net.fabricmc.fabric.api.network.CustomPayloadPacketRegistry; import net.fabricmc.fabric.api.network.PacketContext; -import net.fabricmc.fabric.impl.network.SPacketCustomPayloadAccessor; +import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; +import net.fabricmc.fabric.impl.network.CustomPayloadC2SPacketAccessor; +import net.fabricmc.fabric.impl.network.ServerSidePacketRegistryImpl; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayNetworkHandler; @@ -41,9 +42,9 @@ public class MixinServerPlayNetworkHandler implements PacketContext { @Inject(method = "onCustomPayload", at = @At("HEAD"), cancellable = true) public void onCustomPayload(CustomPayloadServerPacket packet, CallbackInfo info) { - SPacketCustomPayloadAccessor accessor = ((SPacketCustomPayloadAccessor) packet); + CustomPayloadC2SPacketAccessor accessor = ((CustomPayloadC2SPacketAccessor) packet); - if (CustomPayloadPacketRegistry.SERVER.accept(accessor.getChannel(), this, accessor.getData())) { + if (((ServerSidePacketRegistryImpl) ServerSidePacketRegistry.INSTANCE).accept(accessor.getChannel(), this, accessor.getData())) { info.cancel(); } } diff --git a/src/main/java/net/fabricmc/fabric/mixin/registry/MixinServerPlayNetworkHandler.java b/src/main/java/net/fabricmc/fabric/mixin/registry/MixinServerPlayNetworkHandler.java index 506c65645..8845caf62 100644 --- a/src/main/java/net/fabricmc/fabric/mixin/registry/MixinServerPlayNetworkHandler.java +++ b/src/main/java/net/fabricmc/fabric/mixin/registry/MixinServerPlayNetworkHandler.java @@ -16,6 +16,9 @@ package net.fabricmc.fabric.mixin.registry; +import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; +import net.fabricmc.fabric.impl.network.PacketRegistryImpl; +import net.fabricmc.fabric.impl.network.ServerSidePacketRegistryImpl; import net.fabricmc.fabric.impl.registry.RegistrySyncManager; import net.minecraft.network.ClientConnection; import net.minecraft.network.Packet; @@ -36,6 +39,8 @@ public abstract class MixinServerPlayNetworkHandler { @Inject(method = "", at = @At("RETURN")) public void init(MinecraftServer server, ClientConnection connection, ServerPlayerEntity player, CallbackInfo info) { // TODO: If integrated and local, don't send the packet (it's ignored) + // TODO: Refactor out into network + move registry hook to event + sendPacket(PacketRegistryImpl.createInitialRegisterPacket(ServerSidePacketRegistry.INSTANCE)); sendPacket(RegistrySyncManager.createPacket()); } } diff --git a/src/main/java/net/fabricmc/fabric/mixin/registry/client/MixinMinecraftClient.java b/src/main/java/net/fabricmc/fabric/mixin/registry/client/MixinMinecraftClient.java new file mode 100644 index 000000000..b843f9265 --- /dev/null +++ b/src/main/java/net/fabricmc/fabric/mixin/registry/client/MixinMinecraftClient.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016, 2017, 2018 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.mixin.registry.client; + +import net.fabricmc.fabric.impl.network.ClientSidePacketRegistryImpl; +import net.fabricmc.fabric.impl.registry.RegistrySyncManager; +import net.fabricmc.fabric.impl.registry.RemapException; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.Screen; +import org.apache.logging.log4j.Logger; +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(MinecraftClient.class) +public class MixinMinecraftClient { + @Shadow + private static Logger LOGGER; + + // Unmap the registry before loading a new SP/MP setup. + @Inject(at = @At("RETURN"), method = "method_18096") + public void method_18096(Screen screen_1, CallbackInfo info) { + ClientSidePacketRegistryImpl.invalidateRegisteredIdList(); + + try { + RegistrySyncManager.unmap(); + } catch (RemapException e) { + LOGGER.warn("Failed to unmap Fabric registries!", e); + } + } +} \ No newline at end of file diff --git a/src/main/resources/net.fabricmc.fabric.mixins.client.json b/src/main/resources/net.fabricmc.fabric.mixins.client.json index ad2e862f2..a56d34921 100644 --- a/src/main/resources/net.fabricmc.fabric.mixins.client.json +++ b/src/main/resources/net.fabricmc.fabric.mixins.client.json @@ -21,6 +21,7 @@ "registry.client.MixinBlockColorMap", "registry.client.MixinItemColorMap", "registry.client.MixinItemModelMap", + "registry.client.MixinMinecraftClient", "registry.client.MixinParticleManager", "resources.MixinKeyedResourceReloadListener$Client", "resources.MixinMinecraftGame" diff --git a/src/main/resources/net.fabricmc.fabric.mixins.common.json b/src/main/resources/net.fabricmc.fabric.mixins.common.json index f20eaeeef..187747337 100644 --- a/src/main/resources/net.fabricmc.fabric.mixins.common.json +++ b/src/main/resources/net.fabricmc.fabric.mixins.common.json @@ -9,6 +9,7 @@ "commands.MixinServerCommandManager", "container.MixinServerPlayerEntity", "entity.MixinEntityTracker", + "entity.MixinEntityTrackerEntry", "events.objectbuilder.MixinBlock", "events.objectbuilder.MixinItem", "events.playerinteraction.MixinServerPlayNetworkHandler", @@ -20,8 +21,8 @@ "item.MixinAbstractFurnaceBlockEntity", "itemgroup.MixinItemGroup", "misc.MixinCrashReport", + "networking.MixinCustomPayloadC2SPacket", "networking.MixinServerPlayNetworkHandler", - "networking.MixinSPacketCustomPayload", "registry.MixinBootstrap", "registry.MixinIdList", "registry.MixinIdRegistry",