mirror of
https://github.com/FabricMC/fabric.git
synced 2024-11-14 19:25:23 -05:00
23w31a
This commit is contained in:
parent
f4b7e42468
commit
86b12645b9
104 changed files with 2489 additions and 1188 deletions
|
@ -21,18 +21,18 @@ import java.util.Map;
|
|||
import java.util.function.Consumer;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
import net.fabricmc.fabric.api.container.ContainerFactory;
|
||||
import net.fabricmc.fabric.api.container.ContainerProviderRegistry;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.fabricmc.fabric.mixin.container.ServerPlayerEntityAccessor;
|
||||
|
||||
public class ContainerProviderImpl implements ContainerProviderRegistry {
|
||||
|
@ -87,7 +87,7 @@ public class ContainerProviderImpl implements ContainerProviderRegistry {
|
|||
buf.writeByte(syncId);
|
||||
|
||||
writer.accept(buf);
|
||||
player.networkHandler.sendPacket(new CustomPayloadS2CPacket(OPEN_CONTAINER, buf));
|
||||
player.networkHandler.sendPacket(ServerPlayNetworking.createS2CPacket(OPEN_CONTAINER, buf));
|
||||
|
||||
PacketByteBuf clonedBuf = new PacketByteBuf(buf.duplicate());
|
||||
clonedBuf.readIdentifier();
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
version = getSubprojectVersion(project)
|
||||
|
||||
moduleDependencies(project, [
|
||||
'fabric-api-base',
|
||||
'fabric-networking-api-v1'
|
||||
])
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.minecraft.network.packet.Packet;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
import net.fabricmc.fabric.impl.client.networking.v0.ClientSidePacketRegistryImpl;
|
||||
|
||||
/**
|
||||
* The client-side packet registry.
|
||||
*
|
||||
* <p>It is used for:
|
||||
*
|
||||
* <ul><li>registering client-side packet receivers (server -> client packets)
|
||||
* <li>sending packets to the server (client -> server packets).</ul>
|
||||
*
|
||||
* @deprecated Please migrate to {@link net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking}.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ClientSidePacketRegistry extends PacketRegistry {
|
||||
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<? extends Future<? super Void>> 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<? extends Future<? super Void>> 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);
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.client.networking.v0;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.thread.ThreadExecutor;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.fabricmc.fabric.api.network.ClientSidePacketRegistry;
|
||||
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.impl.networking.GenericFutureListenerHolder;
|
||||
|
||||
public class ClientSidePacketRegistryImpl implements ClientSidePacketRegistry, PacketRegistry {
|
||||
@Override
|
||||
public boolean canServerReceive(Identifier id) {
|
||||
return ClientPlayNetworking.getSendable().contains(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToServer(Packet<?> packet, GenericFutureListener<? extends Future<? super Void>> completionListener) {
|
||||
if (MinecraftClient.getInstance().getNetworkHandler() != null) {
|
||||
MinecraftClient.getInstance().getNetworkHandler().getConnection().send(packet, GenericFutureListenerHolder.create(completionListener));
|
||||
return;
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Cannot send packet to server while not in game!"); // TODO: Error message
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet<?> toPacket(Identifier id, PacketByteBuf buf) {
|
||||
return ClientPlayNetworking.createC2SPacket(id, buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Identifier id, PacketConsumer consumer) {
|
||||
// id is checked in client networking
|
||||
Objects.requireNonNull(consumer, "PacketConsumer cannot be null");
|
||||
|
||||
ClientPlayNetworking.registerGlobalReceiver(id, (client, handler, buf, sender) -> {
|
||||
consumer.accept(new PacketContext() {
|
||||
@Override
|
||||
public EnvType getPacketEnvironment() {
|
||||
return EnvType.CLIENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerEntity getPlayer() {
|
||||
return client.player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreadExecutor<?> getTaskQueue() {
|
||||
return client;
|
||||
}
|
||||
}, buf);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(Identifier id) {
|
||||
ClientPlayNetworking.unregisterGlobalReceiver(id);
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.client.networking.v0;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.event.network.S2CPacketTypeCallback;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.C2SPlayChannelEvents;
|
||||
|
||||
public final class OldClientNetworkingHooks implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
// Must be lambdas below
|
||||
C2SPlayChannelEvents.REGISTER.register((handler, client, sender, channels) -> S2CPacketTypeCallback.REGISTERED.invoker().accept(channels));
|
||||
C2SPlayChannelEvents.UNREGISTER.register((handler, client, sender, channels) -> S2CPacketTypeCallback.UNREGISTERED.invoker().accept(channels));
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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 java.util.Collection;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
import net.fabricmc.fabric.api.networking.v1.S2CPlayChannelEvents;
|
||||
|
||||
/**
|
||||
* Event for listening to packet type registration and unregistration notifications
|
||||
* (also known as "minecraft:register" and "minecraft:unregister") sent by a client.
|
||||
*
|
||||
* <p>Registrations received will be for <em>server -> client</em> packets
|
||||
* that the sending client can understand.
|
||||
*
|
||||
* @deprecated Please migrate to {@link S2CPlayChannelEvents} since this was incorrectly named.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface C2SPacketTypeCallback {
|
||||
/**
|
||||
* @deprecated Please migrate to {@link net.fabricmc.fabric.api.client.networking.v1.C2SPlayChannelEvents#REGISTER}.
|
||||
*/
|
||||
@Deprecated
|
||||
Event<C2SPacketTypeCallback> REGISTERED = EventFactory.createArrayBacked(
|
||||
C2SPacketTypeCallback.class,
|
||||
(callbacks) -> (client, types) -> {
|
||||
for (C2SPacketTypeCallback callback : callbacks) {
|
||||
callback.accept(client, types);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* @deprecated Please migrate to {@link net.fabricmc.fabric.api.client.networking.v1.C2SPlayChannelEvents#UNREGISTER}.
|
||||
*/
|
||||
@Deprecated
|
||||
Event<C2SPacketTypeCallback> UNREGISTERED = EventFactory.createArrayBacked(
|
||||
C2SPacketTypeCallback.class,
|
||||
(callbacks) -> (client, types) -> {
|
||||
for (C2SPacketTypeCallback callback : callbacks) {
|
||||
callback.accept(client, types);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Accept a collection of types.
|
||||
*
|
||||
* @param client The player who is the source of the packet.
|
||||
* @param types The provided collection of types.
|
||||
*/
|
||||
void accept(PlayerEntity client, Collection<Identifier> types);
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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 java.util.Collection;
|
||||
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
import net.fabricmc.fabric.api.networking.v1.S2CPlayChannelEvents;
|
||||
|
||||
/**
|
||||
* Event for listening to packet type registration and unregistration notifications
|
||||
* (also known as "minecraft:register" and "minecraft:unregister") sent by a server.
|
||||
*
|
||||
* <p>Registrations received will be for <em>client -> server</em> packets
|
||||
* that the sending server can understand.
|
||||
*
|
||||
* @deprecated Please migrate to {@link net.fabricmc.fabric.api.client.networking.v1.C2SPlayChannelEvents} since this was incorrectly named.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface S2CPacketTypeCallback {
|
||||
/**
|
||||
* @deprecated Please migrate to {@link S2CPlayChannelEvents#REGISTER}.
|
||||
*/
|
||||
@Deprecated
|
||||
Event<S2CPacketTypeCallback> REGISTERED = EventFactory.createArrayBacked(
|
||||
S2CPacketTypeCallback.class,
|
||||
(callbacks) -> (types) -> {
|
||||
for (S2CPacketTypeCallback callback : callbacks) {
|
||||
callback.accept(types);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* @deprecated Please migrate to {@link S2CPlayChannelEvents#UNREGISTER}.
|
||||
*/
|
||||
@Deprecated
|
||||
Event<S2CPacketTypeCallback> UNREGISTERED = EventFactory.createArrayBacked(
|
||||
S2CPacketTypeCallback.class,
|
||||
(callbacks) -> (types) -> {
|
||||
for (S2CPacketTypeCallback callback : callbacks) {
|
||||
callback.accept(types);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Accept a collection of types.
|
||||
*
|
||||
* @param types The provided collection of types.
|
||||
*/
|
||||
void accept(Collection<Identifier> types);
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.PacketByteBuf;
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
|
||||
/**
|
||||
* Interface for receiving CustomPayload-based packets.
|
||||
*
|
||||
* @deprecated See the corresponding play packet handler in {@link net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking} or {@link ServerPlayNetworking}
|
||||
*/
|
||||
@Deprecated
|
||||
@FunctionalInterface
|
||||
public interface PacketConsumer {
|
||||
/**
|
||||
* Receive a CustomPayload-based packet.
|
||||
*
|
||||
* <p>The PacketByteBuf received will be released as soon as the method exits,
|
||||
* meaning that you have to call .retain()/.release() on it if you want to
|
||||
* keep it around after that.
|
||||
*
|
||||
* <p>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 happen within this method's execution)
|
||||
* and "applying" (which, unless you know what you're doing, should happen
|
||||
* on the main thread, after this method exits).
|
||||
*
|
||||
* @param context The context (receiving player, side, etc.)
|
||||
* @param buffer The byte buffer containing the received packet data.
|
||||
*/
|
||||
void accept(PacketContext context, PacketByteBuf buffer);
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.thread.ThreadExecutor;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
|
||||
/**
|
||||
* Interface defining a context used during packet processing. Allows access
|
||||
* to additional information, such as the source/target of the player, or
|
||||
* the correct task queue to enqueue synchronization-requiring code on.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface PacketContext {
|
||||
/**
|
||||
* Get the environment associated with the packet.
|
||||
*
|
||||
* @return EnvType.CLIENT if processing packet on the client side,
|
||||
* EnvType.SERVER otherwise.
|
||||
*/
|
||||
EnvType getPacketEnvironment();
|
||||
|
||||
/**
|
||||
* Get the player associated with the packet.
|
||||
*
|
||||
* <p>On the client side, this always returns the client-side player instance.
|
||||
* On the server side, it returns the player belonging to the client this
|
||||
* packet was sent by.
|
||||
*
|
||||
* @return The player associated with the packet.
|
||||
*/
|
||||
PlayerEntity getPlayer();
|
||||
|
||||
/**
|
||||
* Get the task queue for a given side.
|
||||
*
|
||||
* <p>As Minecraft networking I/O is asynchronous, but a lot of its logic is
|
||||
* not thread-safe, it is recommended to do the following:
|
||||
*
|
||||
* <ul><li>read and parse the PacketByteBuf,
|
||||
* <li>run the packet response logic through the main thread task queue via
|
||||
* ThreadTaskQueue.execute(). The method will check if it's not already
|
||||
* on the main thread in order to avoid unnecessary delays, so don't
|
||||
* worry about that!</ul>
|
||||
*
|
||||
* @return The thread task queue.
|
||||
*/
|
||||
ThreadExecutor getTaskQueue();
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.fabricmc.fabric.api.server.PlayerStream;
|
||||
import net.fabricmc.fabric.impl.networking.v0.ServerSidePacketRegistryImpl;
|
||||
|
||||
/**
|
||||
* The server-side packet registry.
|
||||
*
|
||||
* <p>It is used for:
|
||||
*
|
||||
* <ul><li>registering server-side packet receivers (client -> server packets)
|
||||
* <li>sending packets to clients (server -> client packets).</ul>
|
||||
*
|
||||
* <p>For iterating over clients in a server, see {@link PlayerStream}.
|
||||
*
|
||||
* @deprecated Please migrate to {@link ServerPlayNetworking}.
|
||||
*/
|
||||
@Deprecated
|
||||
public interface ServerSidePacketRegistry extends PacketRegistry {
|
||||
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<? extends Future<? super Void>> 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<? extends Future<? super Void>> 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);
|
||||
}
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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 java.util.stream.Stream;
|
||||
|
||||
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.ServerPlayerEntity;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.PlayerLookup;
|
||||
|
||||
/**
|
||||
* Helper streams for looking up players on a server.
|
||||
*
|
||||
* <p>In general, most of these methods will only function with a {@link ServerWorld} instance.
|
||||
*
|
||||
* @deprecated Please use {@link PlayerLookup} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class PlayerStream {
|
||||
private PlayerStream() { }
|
||||
|
||||
public static Stream<ServerPlayerEntity> all(MinecraftServer server) {
|
||||
if (server.getPlayerManager() != null) {
|
||||
return server.getPlayerManager().getPlayerList().stream();
|
||||
} else {
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public static Stream<PlayerEntity> world(World world) {
|
||||
if (world instanceof ServerWorld) {
|
||||
// noinspection unchecked,rawtypes
|
||||
return ((Stream) ((ServerWorld) world).getPlayers().stream());
|
||||
} else {
|
||||
throw new RuntimeException("Only supported on ServerWorld!");
|
||||
}
|
||||
}
|
||||
|
||||
public static Stream<PlayerEntity> watching(World world, ChunkPos pos) {
|
||||
if (world instanceof ServerWorld) {
|
||||
//noinspection unchecked,rawtypes
|
||||
return (Stream) PlayerLookup.tracking((ServerWorld) world, pos).stream();
|
||||
}
|
||||
|
||||
throw new RuntimeException("Only supported on ServerWorld!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<PlayerEntity> watching(Entity entity) {
|
||||
//noinspection unchecked,rawtypes
|
||||
return (Stream) PlayerLookup.tracking(entity).stream();
|
||||
}
|
||||
|
||||
public static Stream<PlayerEntity> watching(BlockEntity entity) {
|
||||
return watching(entity.getWorld(), entity.getPos());
|
||||
}
|
||||
|
||||
public static Stream<PlayerEntity> watching(World world, BlockPos pos) {
|
||||
return watching(world, new ChunkPos(pos));
|
||||
}
|
||||
|
||||
public static Stream<PlayerEntity> around(World world, Vec3d vector, double radius) {
|
||||
double radiusSq = radius * radius;
|
||||
return world(world).filter((p) -> p.squaredDistanceTo(vector) <= radiusSq);
|
||||
}
|
||||
|
||||
public static Stream<PlayerEntity> around(World world, BlockPos pos, double radius) {
|
||||
double radiusSq = radius * radius;
|
||||
return world(world).filter((p) -> p.squaredDistanceTo(pos.getX(), pos.getY(), pos.getZ()) <= radiusSq);
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking.v0;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.event.network.C2SPacketTypeCallback;
|
||||
import net.fabricmc.fabric.api.networking.v1.S2CPlayChannelEvents;
|
||||
|
||||
public final class OldNetworkingHooks implements ModInitializer {
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
// Must be lambdas below
|
||||
S2CPlayChannelEvents.REGISTER.register((handler, server, sender, channels) -> {
|
||||
C2SPacketTypeCallback.REGISTERED.invoker().accept(handler.player, channels);
|
||||
});
|
||||
S2CPlayChannelEvents.UNREGISTER.register((handler, server, sender, channels) -> {
|
||||
C2SPacketTypeCallback.UNREGISTERED.invoker().accept(handler.player, channels);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking.v0;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import io.netty.util.concurrent.Future;
|
||||
import io.netty.util.concurrent.GenericFutureListener;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.thread.ThreadExecutor;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
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.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.fabricmc.fabric.impl.networking.GenericFutureListenerHolder;
|
||||
|
||||
public class ServerSidePacketRegistryImpl implements ServerSidePacketRegistry, PacketRegistry {
|
||||
@Override
|
||||
public boolean canPlayerReceive(PlayerEntity player, Identifier id) {
|
||||
if (player instanceof ServerPlayerEntity) {
|
||||
return ServerPlayNetworking.canSend((ServerPlayerEntity) player, id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToPlayer(PlayerEntity player, Packet<?> packet, GenericFutureListener<? extends Future<? super Void>> completionListener) {
|
||||
if (player instanceof ServerPlayerEntity) {
|
||||
((ServerPlayerEntity) player).networkHandler.sendPacket(packet, GenericFutureListenerHolder.create(completionListener));
|
||||
return;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Can only send to ServerPlayerEntities!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet<?> toPacket(Identifier id, PacketByteBuf buf) {
|
||||
return new CustomPayloadS2CPacket(id, buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Identifier id, PacketConsumer consumer) {
|
||||
Objects.requireNonNull(consumer, "PacketConsumer cannot be null");
|
||||
|
||||
ServerPlayNetworking.registerGlobalReceiver(id, (server, player, handler, buf, sender) -> {
|
||||
consumer.accept(new PacketContext() {
|
||||
@Override
|
||||
public EnvType getPacketEnvironment() {
|
||||
return EnvType.SERVER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerEntity getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThreadExecutor<?> getTaskQueue() {
|
||||
return server;
|
||||
}
|
||||
}, buf);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregister(Identifier id) {
|
||||
ServerPlayNetworking.unregisterGlobalReceiver(id);
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
|
@ -1,35 +0,0 @@
|
|||
{
|
||||
"schemaVersion": 1,
|
||||
"id": "fabric-networking-v0",
|
||||
"name": "Fabric Networking (v0)",
|
||||
"version": "${version}",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"icon": "assets/fabric-networking-v0/icon.png",
|
||||
"contact": {
|
||||
"homepage": "https://fabricmc.net",
|
||||
"irc": "irc://irc.esper.net:6667/fabric",
|
||||
"issues": "https://github.com/FabricMC/fabric/issues",
|
||||
"sources": "https://github.com/FabricMC/fabric"
|
||||
},
|
||||
"authors": [
|
||||
"FabricMC"
|
||||
],
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"net.fabricmc.fabric.impl.networking.v0.OldNetworkingHooks"
|
||||
],
|
||||
"client": [
|
||||
"net.fabricmc.fabric.impl.client.networking.v0.OldClientNetworkingHooks"
|
||||
]
|
||||
},
|
||||
"depends": {
|
||||
"fabricloader": ">=0.4.0",
|
||||
"fabric-api-base": "*",
|
||||
"fabric-networking-api-v1": "*"
|
||||
},
|
||||
"description": "Legacy Networking packet hooks and registries, superseded by fabric-networking-api-v1.",
|
||||
"custom": {
|
||||
"fabric-api:module-lifecycle": "deprecated"
|
||||
}
|
||||
}
|
|
@ -54,6 +54,7 @@
|
|||
"minecraft:ore_redstone",
|
||||
"minecraft:ore_redstone_lower",
|
||||
"minecraft:ore_diamond",
|
||||
"minecraft:ore_diamond_medium",
|
||||
"minecraft:ore_diamond_large",
|
||||
"minecraft:ore_diamond_buried",
|
||||
"minecraft:ore_lapis",
|
||||
|
|
|
@ -76,6 +76,8 @@ public class ClientTagTest implements ClientModInitializer {
|
|||
LOGGER.info("The tests for client tags passed!");
|
||||
});
|
||||
|
||||
if (true) return;
|
||||
|
||||
// This should be tested on a server with the datapack from the builtin resourcepack.
|
||||
// That is, fabric:sword_efficient should NOT exist on the server (can be confirmed with F3 on a dirt block),
|
||||
// but the this test should pass as minecraft:sword_efficient will contain dirt on the server
|
||||
|
|
|
@ -26,14 +26,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.client.network.ClientCommandSource;
|
||||
import net.minecraft.client.network.ClientDynamicRegistryType;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.command.CommandRegistryAccess;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.network.packet.s2c.play.CommandTreeS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
|
||||
import net.minecraft.registry.DynamicRegistryManager;
|
||||
import net.minecraft.resource.featuretoggle.FeatureSet;
|
||||
import net.minecraft.registry.CombinedDynamicRegistries;
|
||||
|
||||
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
|
||||
|
@ -48,17 +47,19 @@ abstract class ClientPlayNetworkHandlerMixin {
|
|||
@Final
|
||||
private ClientCommandSource commandSource;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private FeatureSet enabledFeatures;
|
||||
|
||||
@Final
|
||||
@Shadow
|
||||
private CombinedDynamicRegistries<ClientDynamicRegistryType> combinedDynamicRegistries;
|
||||
private DynamicRegistryManager.Immutable combinedDynamicRegistries;
|
||||
|
||||
@Inject(method = "onGameJoin", at = @At("RETURN"))
|
||||
private void onGameJoin(GameJoinS2CPacket packet, CallbackInfo info) {
|
||||
final CommandDispatcher<FabricClientCommandSource> dispatcher = new CommandDispatcher<>();
|
||||
ClientCommandInternals.setActiveDispatcher(dispatcher);
|
||||
ClientCommandRegistrationCallback.EVENT.invoker().register(dispatcher, CommandRegistryAccess.of(this.combinedDynamicRegistries.getCombinedRegistryManager(), this.enabledFeatures));
|
||||
ClientCommandRegistrationCallback.EVENT.invoker().register(dispatcher, CommandRegistryAccess.of(this.combinedDynamicRegistries, this.enabledFeatures));
|
||||
ClientCommandInternals.finalizeInit();
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.registry.tag.GameEventTags;
|
||||
import net.minecraft.world.event.GameEvent;
|
||||
import net.minecraft.world.event.Vibrations;
|
||||
|
@ -49,14 +50,14 @@ public final class SculkSensorFrequencyRegistry {
|
|||
*/
|
||||
public static void register(GameEvent event, int frequency) {
|
||||
if (frequency <= 0 || frequency >= 16) {
|
||||
throw new IllegalArgumentException("Attempted to register Sculk Sensor frequency for event "+event.getId()+" with frequency "+frequency+". Sculk Sensor frequencies must be between 1 and 15 inclusive.");
|
||||
throw new IllegalArgumentException("Attempted to register Sculk Sensor frequency for event "+ Registries.GAME_EVENT.getId(event) +" with frequency "+frequency+". Sculk Sensor frequencies must be between 1 and 15 inclusive.");
|
||||
}
|
||||
|
||||
final Object2IntOpenHashMap<GameEvent> map = (Object2IntOpenHashMap<GameEvent>) Vibrations.FREQUENCIES;
|
||||
int replaced = map.put(event, frequency);
|
||||
|
||||
if (replaced != 0) {
|
||||
LOGGER.debug("Replaced old frequency mapping for {} - was {}, now {}", event.getId(), replaced, frequency);
|
||||
LOGGER.debug("Replaced old frequency mapping for {} - was {}, now {}", Registries.GAME_EVENT.getId(event), replaced, frequency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ public final class ContentRegistryTest implements ModInitializer {
|
|||
public static final Logger LOGGER = LoggerFactory.getLogger(ContentRegistryTest.class);
|
||||
|
||||
public static final Identifier TEST_EVENT_ID = new Identifier("fabric-content-registries-v0-testmod", "test_event");
|
||||
public static final GameEvent TEST_EVENT = new GameEvent(TEST_EVENT_ID.toString(), GameEvent.DEFAULT_RANGE);
|
||||
public static final GameEvent TEST_EVENT = new GameEvent(GameEvent.DEFAULT_RANGE);
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
|
|
|
@ -232,7 +232,7 @@ transitive-accessible method net/minecraft/data/client/BlockStateModelGenerator
|
|||
transitive-accessible method net/minecraft/data/client/BlockStateModelGenerator buildBlockStateVariants (Ljava/util/List;Ljava/util/function/UnaryOperator;)Ljava/util/List;
|
||||
transitive-accessible method net/minecraft/data/client/BlockStateModelGenerator registerLantern (Lnet/minecraft/block/Block;)V
|
||||
transitive-accessible method net/minecraft/data/client/BlockStateModelGenerator registerTopSoil (Lnet/minecraft/block/Block;Lnet/minecraft/util/Identifier;Lnet/minecraft/data/client/BlockStateVariant;)V
|
||||
transitive-accessible method net/minecraft/data/client/BlockStateModelGenerator registerPressurePlate (Lnet/minecraft/block/Block;Lnet/minecraft/block/Block;)V
|
||||
transitive-accessible method net/minecraft/data/client/BlockStateModelGenerator registerWeightedPressurePlate (Lnet/minecraft/block/Block;Lnet/minecraft/block/Block;)V
|
||||
transitive-accessible method net/minecraft/data/client/BlockStateModelGenerator registerParented (Lnet/minecraft/block/Block;Lnet/minecraft/block/Block;)V
|
||||
transitive-accessible method net/minecraft/data/client/BlockStateModelGenerator registerNorthDefaultHorizontalRotation (Lnet/minecraft/block/Block;)V
|
||||
transitive-accessible method net/minecraft/data/client/BlockStateModelGenerator registerPiston (Lnet/minecraft/block/Block;Lnet/minecraft/util/Identifier;Lnet/minecraft/data/client/TextureMap;)V
|
||||
|
|
|
@ -21,17 +21,28 @@ import org.jetbrains.annotations.Nullable;
|
|||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.NetworkSide;
|
||||
import net.minecraft.network.PacketCallbacks;
|
||||
import net.minecraft.network.listener.PacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
||||
public class FakePlayerNetworkHandler extends ServerPlayNetworkHandler {
|
||||
private static final ClientConnection FAKE_CONNECTION = new ClientConnection(NetworkSide.CLIENTBOUND);
|
||||
private static final ClientConnection FAKE_CONNECTION = new FakeClientConnection();
|
||||
|
||||
public FakePlayerNetworkHandler(ServerPlayerEntity player) {
|
||||
super(player.getServer(), FAKE_CONNECTION, player);
|
||||
super(player.getServer(), FAKE_CONNECTION, player, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPacket(Packet<?> packet, @Nullable PacketCallbacks callbacks) { }
|
||||
public void send(Packet<?> packet, @Nullable PacketCallbacks callbacks, boolean flush) { }
|
||||
|
||||
private static final class FakeClientConnection extends ClientConnection {
|
||||
private FakeClientConnection() {
|
||||
super(NetworkSide.CLIENTBOUND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPacketListener(PacketListener packetListener) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,8 +47,8 @@ public class MainMixin {
|
|||
}
|
||||
|
||||
// Inject after resourcePackManager is stored
|
||||
@Inject(method = "main", cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", shift = At.Shift.BY, by = 2, target = "Lnet/minecraft/resource/VanillaDataPackProvider;createManager(Ljava/nio/file/Path;)Lnet/minecraft/resource/ResourcePackManager;"))
|
||||
private static void main(String[] args, CallbackInfo info, OptionParser optionParser, OptionSpec optionSpec, OptionSpec optionSpec2, OptionSpec optionSpec3, OptionSpec optionSpec4, OptionSpec optionSpec5, OptionSpec optionSpec6, OptionSpec optionSpec7, OptionSpec optionSpec8, OptionSpec optionSpec9, OptionSpec optionSpec10, OptionSpec optionSpec11, OptionSpec optionSpec12, OptionSpec optionSpec13, OptionSpec optionSpec14, OptionSpec optionSpec15, OptionSpec optionSpec16, OptionSet optionSet, Path path2, ServerPropertiesLoader serverPropertiesLoader, Path path3, EulaReader eulaReader, File file, ApiServices apiServices, String string, LevelStorage levelStorage, LevelStorage.Session session, LevelSummary levelSummary, boolean bl, ResourcePackManager resourcePackManager) {
|
||||
@Inject(method = "main", cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", shift = At.Shift.BY, by = 2, target = "Lnet/minecraft/resource/VanillaDataPackProvider;createManager(Lnet/minecraft/world/level/storage/LevelStorage$Session;)Lnet/minecraft/resource/ResourcePackManager;"))
|
||||
private static void main(String[] args, CallbackInfo info, OptionParser optionParser, OptionSpec optionSpec, OptionSpec optionSpec2, OptionSpec optionSpec3, OptionSpec optionSpec4, OptionSpec optionSpec5, OptionSpec optionSpec6, OptionSpec optionSpec7, OptionSpec optionSpec8, OptionSpec optionSpec9, OptionSpec optionSpec10, OptionSpec optionSpec11, OptionSpec optionSpec12, OptionSpec optionSpec13, OptionSpec optionSpec14, OptionSpec optionSpec15, OptionSet optionSet, Path path2, ServerPropertiesLoader serverPropertiesLoader, Path path3, EulaReader eulaReader, File file, ApiServices apiServices, String string, LevelStorage levelStorage, LevelStorage.Session session, LevelSummary levelSummary, boolean bl, ResourcePackManager resourcePackManager) {
|
||||
if (FabricGameTestHelper.ENABLED) {
|
||||
FabricGameTestHelper.runHeadlessServer(session, resourcePackManager);
|
||||
info.cancel(); // Do not progress in starting the normal dedicated server
|
||||
|
|
|
@ -55,8 +55,8 @@ public abstract class ClientChunkManagerMixin {
|
|||
}
|
||||
}
|
||||
|
||||
@Inject(method = "unload", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientChunkManager$ClientChunkMap;compareAndSet(ILnet/minecraft/world/chunk/WorldChunk;Lnet/minecraft/world/chunk/WorldChunk;)Lnet/minecraft/world/chunk/WorldChunk;"), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
|
||||
private void onChunkUnload(int chunkX, int chunkZ, CallbackInfo ci, int i, WorldChunk chunk) {
|
||||
@Inject(method = "unload", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientChunkManager$ClientChunkMap;compareAndSet(ILnet/minecraft/world/chunk/WorldChunk;Lnet/minecraft/world/chunk/WorldChunk;)Lnet/minecraft/world/chunk/WorldChunk;"), locals = LocalCapture.CAPTURE_FAILHARD)
|
||||
private void onChunkUnload(ChunkPos pos, CallbackInfo ci, int i, WorldChunk chunk) {
|
||||
ClientChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload(this.world, chunk);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,9 +26,9 @@ import net.minecraft.block.entity.BlockEntity;
|
|||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.network.packet.s2c.common.SynchronizeTagsS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.PlayerRespawnS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.play.SynchronizeTagsS2CPacket;
|
||||
import net.minecraft.world.chunk.WorldChunk;
|
||||
|
||||
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientBlockEntityEvents;
|
||||
|
@ -101,7 +101,7 @@ abstract class ClientPlayNetworkHandlerMixin {
|
|||
method = "onSynchronizeTags",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "java/util/Map.forEach(Ljava/util/function/BiConsumer;)V",
|
||||
target = "Lnet/minecraft/client/network/ClientCommonNetworkHandler;onSynchronizeTags(Lnet/minecraft/network/packet/s2c/common/SynchronizeTagsS2CPacket;)V",
|
||||
shift = At.Shift.AFTER, by = 1
|
||||
)
|
||||
)
|
||||
|
|
|
@ -33,13 +33,13 @@ public class PlayerManagerMixin {
|
|||
method = "onPlayerConnect",
|
||||
at = @At(value = "INVOKE", target = "net/minecraft/network/packet/s2c/play/SynchronizeRecipesS2CPacket.<init>(Ljava/util/Collection;)V")
|
||||
)
|
||||
private void hookOnPlayerConnect(ClientConnection connection, ServerPlayerEntity player, CallbackInfo ci) {
|
||||
private void hookOnPlayerConnect(ClientConnection connection, ServerPlayerEntity player, int latency, CallbackInfo ci) {
|
||||
ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS.invoker().onSyncDataPackContents(player, true);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "onDataPacksReloaded",
|
||||
at = @At(value = "INVOKE", target = "net/minecraft/network/packet/s2c/play/SynchronizeTagsS2CPacket.<init>(Ljava/util/Map;)V")
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/common/SynchronizeTagsS2CPacket;<init>(Ljava/util/Map;)V")
|
||||
)
|
||||
private void hookOnDataPacksReloaded(CallbackInfo ci) {
|
||||
for (ServerPlayerEntity player : ((PlayerManager) (Object) this).getPlayerList()) {
|
||||
|
|
|
@ -7,3 +7,7 @@ testDependencies(project, [
|
|||
':fabric-lifecycle-events-v1',
|
||||
':fabric-key-binding-api-v1'
|
||||
])
|
||||
|
||||
loom {
|
||||
accessWidenerPath = file('src/main/resources/fabric-networking-api-v1.accesswidener')
|
||||
}
|
||||
|
|
|
@ -18,7 +18,10 @@ package net.fabricmc.fabric.api.client.networking.v1;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientConfigurationNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
|
@ -50,6 +53,28 @@ public final class C2SPlayChannelEvents {
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* An event for the client configuration network handler receiving an update indicating the connected server's ability to receive packets in certain channels.
|
||||
* This event may be invoked at any time after login and up to disconnection.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public static final Event<RegisterConfiguration> REGISTER_CONFIGURATION = EventFactory.createArrayBacked(RegisterConfiguration.class, callbacks -> (handler, sender, client, channels) -> {
|
||||
for (RegisterConfiguration callback : callbacks) {
|
||||
callback.onChannelRegister(handler, sender, client, channels);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* An event for the client configuration network handler receiving an update indicating the connected server's lack of ability to receive packets in certain channels.
|
||||
* This event may be invoked at any time after login and up to disconnection.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public static final Event<UnregisterConfiguration> UNREGISTER_CONFIGURATION = EventFactory.createArrayBacked(UnregisterConfiguration.class, callbacks -> (handler, sender, client, channels) -> {
|
||||
for (UnregisterConfiguration callback : callbacks) {
|
||||
callback.onChannelUnregister(handler, sender, client, channels);
|
||||
}
|
||||
});
|
||||
|
||||
private C2SPlayChannelEvents() {
|
||||
}
|
||||
|
||||
|
@ -68,4 +93,22 @@ public final class C2SPlayChannelEvents {
|
|||
public interface Unregister {
|
||||
void onChannelUnregister(ClientPlayNetworkHandler handler, PacketSender sender, MinecraftClient client, List<Identifier> channels);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see C2SPlayChannelEvents#REGISTER_CONFIGURATION
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@ApiStatus.Experimental
|
||||
public interface RegisterConfiguration {
|
||||
void onChannelRegister(ClientConfigurationNetworkHandler handler, PacketSender sender, MinecraftClient client, List<Identifier> channels);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see C2SPlayChannelEvents#UNREGISTER_CONFIGURATION
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@ApiStatus.Experimental
|
||||
public interface UnregisterConfiguration {
|
||||
void onChannelUnregister(ClientConfigurationNetworkHandler handler, PacketSender sender, MinecraftClient client, List<Identifier> channels);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.client.networking.v1;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientConfigurationNetworkHandler;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
/**
|
||||
* Offers access to events related to the configuration connection to a server on a logical client.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public class ClientConfigurationConnectionEvents {
|
||||
/**
|
||||
* Event indicating a connection entered the CONFIGURATION state, ready for registering channel handlers.
|
||||
*
|
||||
* @see ClientConfigurationNetworking#registerReceiver(Identifier, ClientConfigurationNetworking.ConfigurationChannelHandler)
|
||||
*/
|
||||
public static final Event<ClientConfigurationConnectionEvents.Init> INIT = EventFactory.createArrayBacked(ClientConfigurationConnectionEvents.Init.class, callbacks -> (handler, client) -> {
|
||||
for (ClientConfigurationConnectionEvents.Init callback : callbacks) {
|
||||
callback.onConfigurationInit(handler, client);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* An event called after the ReadyS2CPacket has been received, just before switching to the PLAY state.
|
||||
*
|
||||
* <p>No packets should be sent when this event is invoked.
|
||||
*/
|
||||
public static final Event<ClientConfigurationConnectionEvents.Ready> READY = EventFactory.createArrayBacked(ClientConfigurationConnectionEvents.Ready.class, callbacks -> (handler, client) -> {
|
||||
for (ClientConfigurationConnectionEvents.Ready callback : callbacks) {
|
||||
callback.onConfigurationReady(handler, client);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* An event for the disconnection of the client configuration network handler.
|
||||
*
|
||||
* <p>No packets should be sent when this event is invoked.
|
||||
*/
|
||||
public static final Event<ClientConfigurationConnectionEvents.Disconnect> DISCONNECT = EventFactory.createArrayBacked(ClientConfigurationConnectionEvents.Disconnect.class, callbacks -> (handler, client) -> {
|
||||
for (ClientConfigurationConnectionEvents.Disconnect callback : callbacks) {
|
||||
callback.onConfigurationDisconnect(handler, client);
|
||||
}
|
||||
});
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Init {
|
||||
void onConfigurationInit(ClientConfigurationNetworkHandler handler, MinecraftClient client);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Ready {
|
||||
void onConfigurationReady(ClientConfigurationNetworkHandler handler, MinecraftClient client);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Disconnect {
|
||||
void onConfigurationDisconnect(ClientConfigurationNetworkHandler handler, MinecraftClient client);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,455 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.client.networking.v1;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientConfigurationNetworkHandler;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.listener.ServerCommonPacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.thread.ThreadExecutor;
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.FabricPacket;
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketSender;
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketType;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking;
|
||||
import net.fabricmc.fabric.impl.networking.client.ClientConfigurationNetworkAddon;
|
||||
import net.fabricmc.fabric.impl.networking.client.ClientNetworkingImpl;
|
||||
import net.fabricmc.fabric.mixin.networking.client.accessor.ClientCommonNetworkHandlerAccessor;
|
||||
|
||||
/**
|
||||
* Offers access to configurtion stage client-side networking functionalities.
|
||||
*
|
||||
* <p>Client-side networking functionalities include receiving clientbound packets,
|
||||
* sending serverbound packets, and events related to client-side network handlers.
|
||||
*
|
||||
* <p>This class should be only used on the physical client and for the logical client.
|
||||
*
|
||||
* <p>See {@link net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking} for information on how to use the packet
|
||||
* object-based API.
|
||||
*
|
||||
* @see ServerConfigurationNetworking
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public final class ClientConfigurationNetworking {
|
||||
/**
|
||||
* Registers a handler to a channel.
|
||||
* A global receiver is registered to all connections, in the present and future.
|
||||
*
|
||||
* <p>The handler runs on the network thread. After reading the buffer there, access to game state
|
||||
* must be performed in the render thread by calling {@link ThreadExecutor#execute(Runnable)}.
|
||||
*
|
||||
* <p>If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made.
|
||||
* Use {@link #unregisterGlobalReceiver(Identifier)} to unregister the existing handler.
|
||||
*
|
||||
* <p>For new code, {@link #registerGlobalReceiver(PacketType, ConfigurationPacketHandler)}
|
||||
* is preferred, as it is designed in a way that prevents thread safety issues.
|
||||
*
|
||||
* @param channelName the id of the channel
|
||||
* @param channelHandler the handler
|
||||
* @return false if a handler is already registered to the channel
|
||||
* @see ClientConfigurationNetworking#unregisterGlobalReceiver(Identifier)
|
||||
* @see ClientConfigurationNetworking#registerReceiver(Identifier, ConfigurationChannelHandler)
|
||||
*/
|
||||
public static boolean registerGlobalReceiver(Identifier channelName, ConfigurationChannelHandler channelHandler) {
|
||||
return ClientNetworkingImpl.CONFIGURATION.registerGlobalReceiver(channelName, channelHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a handler for a packet type.
|
||||
* A global receiver is registered to all connections, in the present and future.
|
||||
*
|
||||
* <p>If a handler is already registered for the {@code type}, this method will return {@code false}, and no change will be made.
|
||||
* Use {@link #unregisterGlobalReceiver(PacketType)} to unregister the existing handler.
|
||||
*
|
||||
* @param type the packet type
|
||||
* @param handler the handler
|
||||
* @return false if a handler is already registered to the channel
|
||||
* @see ClientConfigurationNetworking#unregisterGlobalReceiver(PacketType)
|
||||
* @see ClientConfigurationNetworking#registerReceiver(PacketType, ConfigurationPacketHandler)
|
||||
*/
|
||||
public static <T extends FabricPacket> boolean registerGlobalReceiver(PacketType<T> type, ConfigurationPacketHandler<T> handler) {
|
||||
return registerGlobalReceiver(type.getId(), new ConfigurationChannelHandlerProxy<T>() {
|
||||
@Override
|
||||
public ConfigurationPacketHandler<T> getOriginalHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(MinecraftClient client, ClientConfigurationNetworkHandler networkHandler, PacketByteBuf buf, PacketSender sender) {
|
||||
T packet = type.read(buf);
|
||||
|
||||
if (client.isOnThread()) {
|
||||
// Do not submit to the render thread if we're already running there.
|
||||
// Normally, packets are handled on the network IO thread - though it is
|
||||
// not guaranteed (for example, with 1.19.4 S2C packet bundling)
|
||||
// Since we're handling it right now, connection check is redundant.
|
||||
handler.receive(packet, sender);
|
||||
} else {
|
||||
client.execute(() -> {
|
||||
if (((ClientCommonNetworkHandlerAccessor) networkHandler).getConnection().isOpen()) handler.receive(packet, sender);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the handler of a channel.
|
||||
* A global receiver is registered to all connections, in the present and future.
|
||||
*
|
||||
* <p>The {@code channel} is guaranteed not to have a handler after this call.
|
||||
*
|
||||
* @param channelName the id of the channel
|
||||
* @return the previous handler, or {@code null} if no handler was bound to the channel
|
||||
* @see ClientConfigurationNetworking#registerGlobalReceiver(Identifier, ConfigurationChannelHandler)
|
||||
* @see ClientConfigurationNetworking#unregisterReceiver(Identifier)
|
||||
*/
|
||||
@Nullable
|
||||
public static ClientConfigurationNetworking.ConfigurationChannelHandler unregisterGlobalReceiver(Identifier channelName) {
|
||||
return ClientNetworkingImpl.CONFIGURATION.unregisterGlobalReceiver(channelName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the handler for a packet type.
|
||||
* A global receiver is registered to all connections, in the present and future.
|
||||
*
|
||||
* <p>The {@code type} is guaranteed not to have an associated handler after this call.
|
||||
*
|
||||
* @param type the packet type
|
||||
* @return the previous handler, or {@code null} if no handler was bound to the channel,
|
||||
* or it was not registered using {@link #registerGlobalReceiver(PacketType, ConfigurationPacketHandler)}
|
||||
* @see ClientConfigurationNetworking#registerGlobalReceiver(PacketType, ConfigurationPacketHandler)
|
||||
* @see ClientConfigurationNetworking#unregisterReceiver(PacketType)
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends FabricPacket> ClientConfigurationNetworking.ConfigurationPacketHandler<T> unregisterGlobalReceiver(PacketType<T> type) {
|
||||
ConfigurationChannelHandler handler = ClientNetworkingImpl.CONFIGURATION.unregisterGlobalReceiver(type.getId());
|
||||
return handler instanceof ConfigurationChannelHandlerProxy<?> proxy ? (ConfigurationPacketHandler<T>) proxy.getOriginalHandler() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all channel names which global receivers are registered for.
|
||||
* A global receiver is registered to all connections, in the present and future.
|
||||
*
|
||||
* @return all channel names which global receivers are registered for.
|
||||
*/
|
||||
public static Set<Identifier> getGlobalReceivers() {
|
||||
return ClientNetworkingImpl.CONFIGURATION.getChannels();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a handler to a channel.
|
||||
*
|
||||
* <p>If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made.
|
||||
* Use {@link #unregisterReceiver(Identifier)} to unregister the existing handler.
|
||||
*
|
||||
* <p>For example, if you only register a receiver using this method when a {@linkplain ClientLoginNetworking#registerGlobalReceiver(Identifier, ClientLoginNetworking.LoginQueryRequestHandler)}
|
||||
* login query has been received, you should use {@link ClientPlayConnectionEvents#INIT} to register the channel handler.
|
||||
*
|
||||
* <p>For new code, {@link #registerReceiver(PacketType, ConfigurationPacketHandler)}
|
||||
* is preferred, as it is designed in a way that prevents thread safety issues.
|
||||
*
|
||||
* @param channelName the id of the channel
|
||||
* @return false if a handler is already registered to the channel
|
||||
* @throws IllegalStateException if the client is not connected to a server
|
||||
* @see ClientPlayConnectionEvents#INIT
|
||||
*/
|
||||
public static boolean registerReceiver(Identifier channelName, ConfigurationChannelHandler channelHandler) {
|
||||
final ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getClientConfigurationAddon();
|
||||
|
||||
if (addon != null) {
|
||||
return addon.registerChannel(channelName, channelHandler);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Cannot register receiver while not configuring!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a handler for a packet type.
|
||||
*
|
||||
* <p>If a handler is already registered for the {@code type}, this method will return {@code false}, and no change will be made.
|
||||
* Use {@link #unregisterReceiver(PacketType)} to unregister the existing handler.
|
||||
*
|
||||
* <p>For example, if you only register a receiver using this method when a {@linkplain ClientLoginNetworking#registerGlobalReceiver(Identifier, ClientLoginNetworking.LoginQueryRequestHandler)}
|
||||
* login query has been received, you should use {@link ClientPlayConnectionEvents#INIT} to register the channel handler.
|
||||
*
|
||||
* @param type the packet type
|
||||
* @param handler the handler
|
||||
* @return {@code false} if a handler is already registered for the type
|
||||
* @throws IllegalStateException if the client is not connected to a server
|
||||
* @see ClientPlayConnectionEvents#INIT
|
||||
*/
|
||||
public static <T extends FabricPacket> boolean registerReceiver(PacketType<T> type, ConfigurationPacketHandler<T> handler) {
|
||||
return registerReceiver(type.getId(), new ConfigurationChannelHandlerProxy<T>() {
|
||||
@Override
|
||||
public ConfigurationPacketHandler<T> getOriginalHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(MinecraftClient client, ClientConfigurationNetworkHandler networkHandler, PacketByteBuf buf, PacketSender sender) {
|
||||
T packet = type.read(buf);
|
||||
|
||||
if (client.isOnThread()) {
|
||||
// Do not submit to the render thread if we're already running there.
|
||||
// Normally, packets are handled on the network IO thread - though it is
|
||||
// not guaranteed (for example, with 1.19.4 S2C packet bundling)
|
||||
// Since we're handling it right now, connection check is redundant.
|
||||
handler.receive(packet, sender);
|
||||
} else {
|
||||
client.execute(() -> {
|
||||
if (((ClientCommonNetworkHandlerAccessor) networkHandler).getConnection().isOpen()) handler.receive(packet, sender);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the handler of a channel.
|
||||
*
|
||||
* <p>The {@code channelName} is guaranteed not to have a handler after this call.
|
||||
*
|
||||
* @param channelName the id of the channel
|
||||
* @return the previous handler, or {@code null} if no handler was bound to the channel
|
||||
* @throws IllegalStateException if the client is not connected to a server
|
||||
*/
|
||||
@Nullable
|
||||
public static ClientConfigurationNetworking.ConfigurationChannelHandler unregisterReceiver(Identifier channelName) throws IllegalStateException {
|
||||
final ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getClientConfigurationAddon();
|
||||
|
||||
if (addon != null) {
|
||||
return addon.unregisterChannel(channelName);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Cannot unregister receiver while not configuring!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the handler for a packet type.
|
||||
*
|
||||
* <p>The {@code type} is guaranteed not to have an associated handler after this call.
|
||||
*
|
||||
* @param type the packet type
|
||||
* @return the previous handler, or {@code null} if no handler was bound to the channel,
|
||||
* or it was not registered using {@link #registerReceiver(PacketType, ConfigurationPacketHandler)}
|
||||
* @throws IllegalStateException if the client is not connected to a server
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends FabricPacket> ClientConfigurationNetworking.ConfigurationPacketHandler<T> unregisterReceiver(PacketType<T> type) {
|
||||
ConfigurationChannelHandler handler = unregisterReceiver(type.getId());
|
||||
return handler instanceof ConfigurationChannelHandlerProxy<?> proxy ? (ConfigurationPacketHandler<T>) proxy.getOriginalHandler() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the channel names that the client can receive packets on.
|
||||
*
|
||||
* @return All the channel names that the client can receive packets on
|
||||
* @throws IllegalStateException if the client is not connected to a server
|
||||
*/
|
||||
public static Set<Identifier> getReceived() throws IllegalStateException {
|
||||
final ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getClientConfigurationAddon();
|
||||
|
||||
if (addon != null) {
|
||||
return addon.getReceivableChannels();
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Cannot get a list of channels the client can receive packets on while not configuring!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all channel names that the connected server declared the ability to receive a packets on.
|
||||
*
|
||||
* @return All the channel names the connected server declared the ability to receive a packets on
|
||||
* @throws IllegalStateException if the client is not connected to a server
|
||||
*/
|
||||
public static Set<Identifier> getSendable() throws IllegalStateException {
|
||||
final ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getClientConfigurationAddon();
|
||||
|
||||
if (addon != null) {
|
||||
return addon.getSendableChannels();
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Cannot get a list of channels the server can receive packets on while not configuring!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the connected server declared the ability to receive a packet on a specified channel name.
|
||||
*
|
||||
* @param channelName the channel name
|
||||
* @return {@code true} if the connected server has declared the ability to receive a packet on the specified channel.
|
||||
* False if the client is not in game.
|
||||
*/
|
||||
public static boolean canSend(Identifier channelName) throws IllegalArgumentException {
|
||||
final ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getClientConfigurationAddon();
|
||||
|
||||
if (addon != null) {
|
||||
return addon.getSendableChannels().contains(channelName);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Cannot get a list of channels the server can receive packets on while not configuring!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the connected server declared the ability to receive a packet on a specified channel name.
|
||||
* This returns {@code false} if the client is not in game.
|
||||
*
|
||||
* @param type the packet type
|
||||
* @return {@code true} if the connected server has declared the ability to receive a packet on the specified channel
|
||||
*/
|
||||
public static boolean canSend(PacketType<?> type) {
|
||||
return canSend(type.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet which may be sent to the connected server.
|
||||
*
|
||||
* @param channelName the channel name
|
||||
* @param buf the packet byte buf which represents the payload of the packet
|
||||
* @return a new packet
|
||||
*/
|
||||
public static Packet<ServerCommonPacketListener> createC2SPacket(Identifier channelName, PacketByteBuf buf) {
|
||||
Objects.requireNonNull(channelName, "Channel name cannot be null");
|
||||
Objects.requireNonNull(buf, "Buf cannot be null");
|
||||
|
||||
return ClientNetworkingImpl.createC2SPacket(channelName, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the packet sender which sends packets to the connected server.
|
||||
*
|
||||
* @return the client's packet sender
|
||||
* @throws IllegalStateException if the client is not connected to a server
|
||||
*/
|
||||
public static PacketSender getSender() throws IllegalStateException {
|
||||
final ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getClientConfigurationAddon();
|
||||
|
||||
if (addon != null) {
|
||||
return addon;
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Cannot get PacketSender while not configuring!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet to the connected server.
|
||||
*
|
||||
* @param channelName the channel of the packet
|
||||
* @param buf the payload of the packet
|
||||
* @throws IllegalStateException if the client is not connected to a server
|
||||
*/
|
||||
public static void send(Identifier channelName, PacketByteBuf buf) throws IllegalStateException {
|
||||
final ClientConfigurationNetworkAddon addon = ClientNetworkingImpl.getClientConfigurationAddon();
|
||||
|
||||
if (addon != null) {
|
||||
addon.sendPacket(createC2SPacket(channelName, buf));
|
||||
return;
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Cannot send packet while not configuring!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet to the connected server.
|
||||
*
|
||||
* @param packet the packet
|
||||
* @throws IllegalStateException if the client is not connected to a server
|
||||
*/
|
||||
public static <T extends FabricPacket> void send(T packet) {
|
||||
Objects.requireNonNull(packet, "Packet cannot be null");
|
||||
Objects.requireNonNull(packet.getType(), "Packet#getType cannot return null");
|
||||
|
||||
PacketByteBuf buf = PacketByteBufs.create();
|
||||
packet.write(buf);
|
||||
send(packet.getType().getId(), buf);
|
||||
}
|
||||
|
||||
private ClientConfigurationNetworking() {
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ConfigurationChannelHandler {
|
||||
/**
|
||||
* Handles an incoming packet.
|
||||
*
|
||||
* <p>This method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}.
|
||||
* Modification to the game should be {@linkplain net.minecraft.util.thread.ThreadExecutor#submit(Runnable) scheduled} using the provided Minecraft client instance.
|
||||
*
|
||||
* <p>An example usage of this is to display an overlay message:
|
||||
* <pre>{@code
|
||||
* ClientConfigurationNetworking.registerReceiver(new Identifier("mymod", "overlay"), (client, handler, buf, responseSender) -> {
|
||||
* String message = buf.readString(32767);
|
||||
*
|
||||
* // All operations on the server or world must be executed on the server thread
|
||||
* client.execute(() -> {
|
||||
* client.inGameHud.setOverlayMessage(message, true);
|
||||
* });
|
||||
* });
|
||||
* }</pre>
|
||||
* @param client the client
|
||||
* @param handler the network handler that received this packet
|
||||
* @param buf the payload of the packet
|
||||
* @param responseSender the packet sender
|
||||
*/
|
||||
void receive(MinecraftClient client, ClientConfigurationNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender);
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal packet handler that works as a proxy between old and new API.
|
||||
* @param <T> the type of the packet
|
||||
*/
|
||||
private interface ConfigurationChannelHandlerProxy<T extends FabricPacket> extends ConfigurationChannelHandler {
|
||||
ConfigurationPacketHandler<T> getOriginalHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* A thread-safe packet handler utilizing {@link FabricPacket}.
|
||||
* @param <T> the type of the packet
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ConfigurationPacketHandler<T extends FabricPacket> {
|
||||
/**
|
||||
* Handles the incoming packet. This is called on the render thread, and can safely
|
||||
* call client methods.
|
||||
*
|
||||
* <p>An example usage of this is to display an overlay message:
|
||||
* <pre>{@code
|
||||
* // See FabricPacket for creating the packet
|
||||
* ClientConfigurationNetworking.registerReceiver(OVERLAY_PACKET_TYPE, (player, packet, responseSender) -> {
|
||||
* MinecraftClient.getInstance().inGameHud.setOverlayMessage(packet.message(), true);
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* @param packet the packet
|
||||
* @param responseSender the packet sender
|
||||
* @see FabricPacket
|
||||
*/
|
||||
void receive(T packet, PacketSender responseSender);
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ import net.minecraft.client.MinecraftClient;
|
|||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.listener.ServerPlayPacketListener;
|
||||
import net.minecraft.network.listener.ServerCommonPacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.thread.ThreadExecutor;
|
||||
|
@ -50,6 +50,7 @@ import net.fabricmc.fabric.impl.networking.client.ClientPlayNetworkAddon;
|
|||
* object-based API.
|
||||
*
|
||||
* @see ClientLoginNetworking
|
||||
* @see ClientConfigurationNetworking
|
||||
* @see ServerPlayNetworking
|
||||
*/
|
||||
public final class ClientPlayNetworking {
|
||||
|
@ -331,11 +332,11 @@ public final class ClientPlayNetworking {
|
|||
* @param buf the packet byte buf which represents the payload of the packet
|
||||
* @return a new packet
|
||||
*/
|
||||
public static Packet<ServerPlayPacketListener> createC2SPacket(Identifier channelName, PacketByteBuf buf) {
|
||||
public static Packet<ServerCommonPacketListener> createC2SPacket(Identifier channelName, PacketByteBuf buf) {
|
||||
Objects.requireNonNull(channelName, "Channel name cannot be null");
|
||||
Objects.requireNonNull(buf, "Buf cannot be null");
|
||||
|
||||
return ClientNetworkingImpl.createPlayC2SPacket(channelName, buf);
|
||||
return ClientNetworkingImpl.createC2SPacket(channelName, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking.client;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientConfigurationNetworkHandler;
|
||||
import net.minecraft.network.NetworkState;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.client.networking.v1.C2SPlayChannelEvents;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationConnectionEvents;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.fabricmc.fabric.impl.networking.AbstractChanneledNetworkAddon;
|
||||
import net.fabricmc.fabric.impl.networking.ChannelInfoHolder;
|
||||
import net.fabricmc.fabric.impl.networking.NetworkingImpl;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload;
|
||||
import net.fabricmc.fabric.mixin.networking.client.accessor.ClientCommonNetworkHandlerAccessor;
|
||||
import net.fabricmc.fabric.mixin.networking.client.accessor.ClientConfigurationNetworkHandlerAccessor;
|
||||
|
||||
public final class ClientConfigurationNetworkAddon extends AbstractChanneledNetworkAddon<ClientConfigurationNetworking.ConfigurationChannelHandler> {
|
||||
private final ClientConfigurationNetworkHandler handler;
|
||||
private final MinecraftClient client;
|
||||
private boolean sentInitialRegisterPacket;
|
||||
|
||||
public ClientConfigurationNetworkAddon(ClientConfigurationNetworkHandler handler, MinecraftClient client) {
|
||||
super(ClientNetworkingImpl.CONFIGURATION, ((ClientCommonNetworkHandlerAccessor) handler).getConnection(), "ClientPlayNetworkAddon for " + ((ClientConfigurationNetworkHandlerAccessor) handler).getProfile().getName());
|
||||
this.handler = handler;
|
||||
this.client = client;
|
||||
|
||||
// Must register pending channels via lateinit
|
||||
this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkState.CONFIGURATION);
|
||||
|
||||
// Register global receivers and attach to session
|
||||
this.receiver.startSession(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lateInit() {
|
||||
for (Map.Entry<Identifier, ClientConfigurationNetworking.ConfigurationChannelHandler> entry : this.receiver.getHandlers().entrySet()) {
|
||||
this.registerChannel(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
ClientConfigurationConnectionEvents.INIT.invoker().onConfigurationInit(this.handler, this.client);
|
||||
}
|
||||
|
||||
public void onServerReady() {
|
||||
this.sendInitialChannelRegistrationPacket();
|
||||
this.sentInitialRegisterPacket = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an incoming packet.
|
||||
*
|
||||
* @param payload the payload to handle
|
||||
* @return true if the packet has been handled
|
||||
*/
|
||||
public boolean handle(PacketByteBufPayload payload) {
|
||||
try {
|
||||
return this.handle(payload.id(), payload.data());
|
||||
} finally {
|
||||
payload.data().release();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void receive(ClientConfigurationNetworking.ConfigurationChannelHandler handler, PacketByteBuf buf) {
|
||||
handler.receive(this.client, this.handler, buf, this);
|
||||
}
|
||||
|
||||
// impl details
|
||||
|
||||
@Override
|
||||
protected void schedule(Runnable task) {
|
||||
MinecraftClient.getInstance().execute(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet<?> createPacket(Identifier channelName, PacketByteBuf buf) {
|
||||
return ClientPlayNetworking.createC2SPacket(channelName, buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invokeRegisterEvent(List<Identifier> ids) {
|
||||
C2SPlayChannelEvents.REGISTER_CONFIGURATION.invoker().onChannelRegister(this.handler, this, this.client, ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invokeUnregisterEvent(List<Identifier> ids) {
|
||||
C2SPlayChannelEvents.UNREGISTER_CONFIGURATION.invoker().onChannelUnregister(this.handler, this, this.client, ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleRegistration(Identifier channelName) {
|
||||
// If we can already send packets, immediately send the register packet for this channel
|
||||
if (this.sentInitialRegisterPacket) {
|
||||
final PacketByteBuf buf = this.createRegistrationPacket(Collections.singleton(channelName));
|
||||
|
||||
if (buf != null) {
|
||||
this.sendPacket(NetworkingImpl.REGISTER_CHANNEL, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleUnregistration(Identifier channelName) {
|
||||
// If we can already send packets, immediately send the unregister packet for this channel
|
||||
if (this.sentInitialRegisterPacket) {
|
||||
final PacketByteBuf buf = this.createRegistrationPacket(Collections.singleton(channelName));
|
||||
|
||||
if (buf != null) {
|
||||
this.sendPacket(NetworkingImpl.UNREGISTER_CHANNEL, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleReady() {
|
||||
ClientConfigurationConnectionEvents.READY.invoker().onConfigurationReady(this.handler, this.client);
|
||||
ClientNetworkingImpl.setClientConfigurationAddon(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invokeDisconnectEvent() {
|
||||
ClientConfigurationConnectionEvents.DISCONNECT.invoker().onConfigurationDisconnect(this.handler, this.client);
|
||||
this.receiver.endSession(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isReservedChannel(Identifier channelName) {
|
||||
return NetworkingImpl.isReservedPlayChannel(channelName);
|
||||
}
|
||||
}
|
|
@ -38,6 +38,8 @@ import net.fabricmc.fabric.api.networking.v1.FutureListeners;
|
|||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||
import net.fabricmc.fabric.impl.networking.AbstractNetworkAddon;
|
||||
import net.fabricmc.fabric.impl.networking.GenericFutureListenerHolder;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufLoginQueryRequestPayload;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufLoginQueryResponse;
|
||||
import net.fabricmc.fabric.mixin.networking.client.accessor.ClientLoginNetworkHandlerAccessor;
|
||||
|
||||
public final class ClientLoginNetworkAddon extends AbstractNetworkAddon<ClientLoginNetworking.LoginQueryRequestHandler> {
|
||||
|
@ -55,7 +57,8 @@ public final class ClientLoginNetworkAddon extends AbstractNetworkAddon<ClientLo
|
|||
}
|
||||
|
||||
public boolean handlePacket(LoginQueryRequestS2CPacket packet) {
|
||||
return handlePacket(packet.getQueryId(), packet.getChannel(), packet.getPayload());
|
||||
PacketByteBufLoginQueryRequestPayload payload = (PacketByteBufLoginQueryRequestPayload) packet.payload();
|
||||
return handlePacket(packet.queryId(), packet.payload().id(), payload.data());
|
||||
}
|
||||
|
||||
private boolean handlePacket(int queryId, Identifier channelName, PacketByteBuf originalBuf) {
|
||||
|
@ -83,7 +86,7 @@ public final class ClientLoginNetworkAddon extends AbstractNetworkAddon<ClientLo
|
|||
try {
|
||||
CompletableFuture<@Nullable PacketByteBuf> future = handler.receive(this.client, this.handler, buf, futureListeners::add);
|
||||
future.thenAccept(result -> {
|
||||
LoginQueryResponseC2SPacket packet = new LoginQueryResponseC2SPacket(queryId, result);
|
||||
LoginQueryResponseC2SPacket packet = new LoginQueryResponseC2SPacket(queryId, new PacketByteBufLoginQueryResponse(result));
|
||||
GenericFutureListener<? extends Future<? super Void>> listener = null;
|
||||
|
||||
for (GenericFutureListener<? extends Future<? super Void>> each : futureListeners) {
|
||||
|
@ -114,7 +117,7 @@ public final class ClientLoginNetworkAddon extends AbstractNetworkAddon<ClientLo
|
|||
this.receiver.endSession(this);
|
||||
}
|
||||
|
||||
public void handlePlayTransition() {
|
||||
public void handleConfigurationTransition() {
|
||||
this.receiver.endSession(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -28,12 +28,15 @@ import net.minecraft.client.gui.screen.ConnectScreen;
|
|||
import net.minecraft.client.network.ClientLoginNetworkHandler;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.NetworkState;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.listener.ServerPlayPacketListener;
|
||||
import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket;
|
||||
import net.minecraft.network.listener.ServerCommonPacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.c2s.common.CustomPayloadC2SPacket;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationConnectionEvents;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientLoginNetworking;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
|
@ -42,14 +45,17 @@ import net.fabricmc.fabric.impl.networking.ChannelInfoHolder;
|
|||
import net.fabricmc.fabric.impl.networking.GlobalReceiverRegistry;
|
||||
import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
|
||||
import net.fabricmc.fabric.impl.networking.NetworkingImpl;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload;
|
||||
import net.fabricmc.fabric.mixin.networking.client.accessor.ClientLoginNetworkHandlerAccessor;
|
||||
import net.fabricmc.fabric.mixin.networking.client.accessor.ConnectScreenAccessor;
|
||||
import net.fabricmc.fabric.mixin.networking.client.accessor.MinecraftClientAccessor;
|
||||
|
||||
public final class ClientNetworkingImpl {
|
||||
public static final GlobalReceiverRegistry<ClientLoginNetworking.LoginQueryRequestHandler> LOGIN = new GlobalReceiverRegistry<>();
|
||||
public static final GlobalReceiverRegistry<ClientConfigurationNetworking.ConfigurationChannelHandler> CONFIGURATION = new GlobalReceiverRegistry<>();
|
||||
public static final GlobalReceiverRegistry<ClientPlayNetworking.PlayChannelHandler> PLAY = new GlobalReceiverRegistry<>();
|
||||
private static ClientPlayNetworkAddon currentPlayAddon;
|
||||
private static ClientConfigurationNetworkAddon currentConfigurationAddon;
|
||||
|
||||
public static ClientPlayNetworkAddon getAddon(ClientPlayNetworkHandler handler) {
|
||||
return (ClientPlayNetworkAddon) ((NetworkHandlerExtensions) handler).getAddon();
|
||||
|
@ -59,8 +65,8 @@ public final class ClientNetworkingImpl {
|
|||
return (ClientLoginNetworkAddon) ((NetworkHandlerExtensions) handler).getAddon();
|
||||
}
|
||||
|
||||
public static Packet<ServerPlayPacketListener> createPlayC2SPacket(Identifier channelName, PacketByteBuf buf) {
|
||||
return new CustomPayloadC2SPacket(channelName, buf);
|
||||
public static Packet<ServerCommonPacketListener> createC2SPacket(Identifier channelName, PacketByteBuf buf) {
|
||||
return new CustomPayloadC2SPacket(new PacketByteBufPayload(channelName, buf));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,6 +91,11 @@ public final class ClientNetworkingImpl {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ClientConfigurationNetworkAddon getClientConfigurationAddon() {
|
||||
return currentConfigurationAddon;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ClientPlayNetworkAddon getClientPlayAddon() {
|
||||
// Since Minecraft can be a bit weird, we need to check for the play addon in a few ways:
|
||||
|
@ -104,15 +115,25 @@ public final class ClientNetworkingImpl {
|
|||
}
|
||||
|
||||
public static void setClientPlayAddon(ClientPlayNetworkAddon addon) {
|
||||
assert addon == null || currentConfigurationAddon == null;
|
||||
currentPlayAddon = addon;
|
||||
}
|
||||
|
||||
public static void setClientConfigurationAddon(ClientConfigurationNetworkAddon addon) {
|
||||
assert addon == null || currentPlayAddon == null;
|
||||
currentConfigurationAddon = addon;
|
||||
}
|
||||
|
||||
public static void clientInit() {
|
||||
// Reference cleanup for the locally stored addon if we are disconnected
|
||||
ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> {
|
||||
currentPlayAddon = null;
|
||||
});
|
||||
|
||||
ClientConfigurationConnectionEvents.DISCONNECT.register((handler, client) -> {
|
||||
currentConfigurationAddon = null;
|
||||
});
|
||||
|
||||
// Register a login query handler for early channel registration.
|
||||
ClientLoginNetworking.registerGlobalReceiver(NetworkingImpl.EARLY_REGISTRATION_CHANNEL, (client, handler, buf, listenerAdder) -> {
|
||||
int n = buf.readVarInt();
|
||||
|
@ -123,7 +144,7 @@ public final class ClientNetworkingImpl {
|
|||
}
|
||||
|
||||
ClientConnection connection = ((ClientLoginNetworkHandlerAccessor) handler).getConnection();
|
||||
((ChannelInfoHolder) connection).getPendingChannelsNames().addAll(ids);
|
||||
((ChannelInfoHolder) connection).getPendingChannelsNames(NetworkState.PLAY).addAll(ids);
|
||||
NetworkingImpl.LOGGER.debug("Received accepted channels from the server");
|
||||
|
||||
PacketByteBuf response = PacketByteBufs.create();
|
||||
|
|
|
@ -25,9 +25,9 @@ import org.slf4j.Logger;
|
|||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.NetworkState;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.client.networking.v1.C2SPlayChannelEvents;
|
||||
|
@ -36,6 +36,7 @@ import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
|||
import net.fabricmc.fabric.impl.networking.AbstractChanneledNetworkAddon;
|
||||
import net.fabricmc.fabric.impl.networking.ChannelInfoHolder;
|
||||
import net.fabricmc.fabric.impl.networking.NetworkingImpl;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload;
|
||||
|
||||
public final class ClientPlayNetworkAddon extends AbstractChanneledNetworkAddon<ClientPlayNetworking.PlayChannelHandler> {
|
||||
private final ClientPlayNetworkHandler handler;
|
||||
|
@ -50,7 +51,7 @@ public final class ClientPlayNetworkAddon extends AbstractChanneledNetworkAddon<
|
|||
this.client = client;
|
||||
|
||||
// Must register pending channels via lateinit
|
||||
this.registerPendingChannels((ChannelInfoHolder) this.connection);
|
||||
this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkState.PLAY);
|
||||
|
||||
// Register global receivers and attach to session
|
||||
this.receiver.startSession(this);
|
||||
|
@ -80,16 +81,14 @@ public final class ClientPlayNetworkAddon extends AbstractChanneledNetworkAddon<
|
|||
/**
|
||||
* Handles an incoming packet.
|
||||
*
|
||||
* @param packet the packet to handle
|
||||
* @param payload the payload to handle
|
||||
* @return true if the packet has been handled
|
||||
*/
|
||||
public boolean handle(CustomPayloadS2CPacket packet) {
|
||||
PacketByteBuf buf = packet.getData();
|
||||
|
||||
public boolean handle(PacketByteBufPayload payload) {
|
||||
try {
|
||||
return this.handle(packet.getChannel(), buf);
|
||||
return this.handle(payload.id(), payload.data());
|
||||
} finally {
|
||||
buf.release();
|
||||
payload.data().release();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking.client;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.client.network.ClientCommonNetworkHandler;
|
||||
import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
|
||||
import net.fabricmc.fabric.impl.networking.client.ClientConfigurationNetworkAddon;
|
||||
import net.fabricmc.fabric.impl.networking.client.ClientPlayNetworkAddon;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload;
|
||||
|
||||
@Mixin(ClientCommonNetworkHandler.class)
|
||||
public abstract class ClientCommonNetworkHandlerMixin implements NetworkHandlerExtensions {
|
||||
@Inject(method = "onDisconnected", at = @At("HEAD"))
|
||||
private void handleDisconnection(Text reason, CallbackInfo ci) {
|
||||
this.getAddon().handleDisconnect();
|
||||
}
|
||||
|
||||
@Inject(method = "onCustomPayload(Lnet/minecraft/network/packet/s2c/common/CustomPayloadS2CPacket;)V", at = @At("HEAD"), cancellable = true)
|
||||
public void onCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) {
|
||||
if (packet.payload() instanceof PacketByteBufPayload payload) {
|
||||
boolean handled;
|
||||
|
||||
if (this.getAddon() instanceof ClientPlayNetworkAddon addon) {
|
||||
handled = addon.handle(payload);
|
||||
} else if (this.getAddon() instanceof ClientConfigurationNetworkAddon addon) {
|
||||
handled = addon.handle(payload);
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown network addon");
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
ci.cancel();
|
||||
} else {
|
||||
payload.data().skipBytes(payload.data().readableBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking.client;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientCommonNetworkHandler;
|
||||
import net.minecraft.client.network.ClientConfigurationNetworkHandler;
|
||||
import net.minecraft.client.network.ClientConnectionState;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.packet.s2c.config.ReadyS2CPacket;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
|
||||
import net.fabricmc.fabric.impl.networking.client.ClientConfigurationNetworkAddon;
|
||||
import net.fabricmc.fabric.impl.networking.client.ClientNetworkingImpl;
|
||||
|
||||
// We want to apply a bit earlier than other mods which may not use us in order to prevent refCount issues
|
||||
@Mixin(value = ClientConfigurationNetworkHandler.class, priority = 999)
|
||||
public abstract class ClientConfigurationNetworkHandlerMixin extends ClientCommonNetworkHandler implements NetworkHandlerExtensions {
|
||||
@Unique
|
||||
private ClientConfigurationNetworkAddon addon;
|
||||
|
||||
protected ClientConfigurationNetworkHandlerMixin(MinecraftClient client, ClientConnection connection, ClientConnectionState connectionState) {
|
||||
super(client, connection, connectionState);
|
||||
}
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void initAddon(CallbackInfo ci) {
|
||||
this.addon = new ClientConfigurationNetworkAddon((ClientConfigurationNetworkHandler) (Object) this, this.client);
|
||||
// A bit of a hack but it allows the field above to be set in case someone registers handlers during INIT event which refers to said field
|
||||
ClientNetworkingImpl.setClientConfigurationAddon(this.addon);
|
||||
this.addon.lateInit();
|
||||
}
|
||||
|
||||
@Inject(method = "onReady", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/ClientConnection;setPacketListener(Lnet/minecraft/network/listener/PacketListener;)V"))
|
||||
public void onReady(ReadyS2CPacket packet, CallbackInfo ci) {
|
||||
this.addon.handleReady();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientConfigurationNetworkAddon getAddon() {
|
||||
return addon;
|
||||
}
|
||||
}
|
|
@ -26,11 +26,14 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientLoginNetworkHandler;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.packet.s2c.login.LoginQueryRequestS2CPacket;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
|
||||
import net.fabricmc.fabric.impl.networking.client.ClientConfigurationNetworkAddon;
|
||||
import net.fabricmc.fabric.impl.networking.client.ClientLoginNetworkAddon;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufLoginQueryRequestPayload;
|
||||
|
||||
@Mixin(ClientLoginNetworkHandler.class)
|
||||
abstract class ClientLoginNetworkHandlerMixin implements NetworkHandlerExtensions {
|
||||
|
@ -38,6 +41,10 @@ abstract class ClientLoginNetworkHandlerMixin implements NetworkHandlerExtension
|
|||
@Final
|
||||
private MinecraftClient client;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private ClientConnection connection;
|
||||
|
||||
@Unique
|
||||
private ClientLoginNetworkAddon addon;
|
||||
|
||||
|
@ -48,8 +55,12 @@ abstract class ClientLoginNetworkHandlerMixin implements NetworkHandlerExtension
|
|||
|
||||
@Inject(method = "onQueryRequest", at = @At(value = "INVOKE", target = "Ljava/util/function/Consumer;accept(Ljava/lang/Object;)V", remap = false, shift = At.Shift.AFTER), cancellable = true)
|
||||
private void handleQueryRequest(LoginQueryRequestS2CPacket packet, CallbackInfo ci) {
|
||||
if (packet.payload() instanceof PacketByteBufLoginQueryRequestPayload payload) {
|
||||
if (this.addon.handlePacket(packet)) {
|
||||
ci.cancel();
|
||||
} else {
|
||||
payload.data().skipBytes(payload.data().readableBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,8 +70,14 @@ abstract class ClientLoginNetworkHandlerMixin implements NetworkHandlerExtension
|
|||
}
|
||||
|
||||
@Inject(method = "onSuccess", at = @At("HEAD"))
|
||||
private void handlePlayTransition(CallbackInfo ci) {
|
||||
addon.handlePlayTransition();
|
||||
private void handleConfigurationTransition(CallbackInfo ci) {
|
||||
addon.handleConfigurationTransition();
|
||||
}
|
||||
|
||||
@Inject(method = "onSuccess", at = @At("TAIL"))
|
||||
private void handleConfigurationReady(CallbackInfo ci) {
|
||||
NetworkHandlerExtensions networkHandlerExtensions = (NetworkHandlerExtensions) connection.getPacketListener();
|
||||
((ClientConfigurationNetworkAddon) networkHandlerExtensions.getAddon()).onServerReady();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,19 +16,18 @@
|
|||
|
||||
package net.fabricmc.fabric.mixin.networking.client;
|
||||
|
||||
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.MinecraftClient;
|
||||
import net.minecraft.client.network.ClientCommonNetworkHandler;
|
||||
import net.minecraft.client.network.ClientConnectionState;
|
||||
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||
import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.packet.s2c.play.GameJoinS2CPacket;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
|
||||
import net.fabricmc.fabric.impl.networking.client.ClientNetworkingImpl;
|
||||
|
@ -36,14 +35,14 @@ import net.fabricmc.fabric.impl.networking.client.ClientPlayNetworkAddon;
|
|||
|
||||
// We want to apply a bit earlier than other mods which may not use us in order to prevent refCount issues
|
||||
@Mixin(value = ClientPlayNetworkHandler.class, priority = 999)
|
||||
abstract class ClientPlayNetworkHandlerMixin implements NetworkHandlerExtensions {
|
||||
@Final
|
||||
@Shadow
|
||||
private MinecraftClient client;
|
||||
|
||||
abstract class ClientPlayNetworkHandlerMixin extends ClientCommonNetworkHandler implements NetworkHandlerExtensions {
|
||||
@Unique
|
||||
private ClientPlayNetworkAddon addon;
|
||||
|
||||
protected ClientPlayNetworkHandlerMixin(MinecraftClient client, ClientConnection connection, ClientConnectionState connectionState) {
|
||||
super(client, connection, connectionState);
|
||||
}
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void initAddon(CallbackInfo ci) {
|
||||
this.addon = new ClientPlayNetworkAddon((ClientPlayNetworkHandler) (Object) this, this.client);
|
||||
|
@ -57,18 +56,6 @@ abstract class ClientPlayNetworkHandlerMixin implements NetworkHandlerExtensions
|
|||
this.addon.onServerReady();
|
||||
}
|
||||
|
||||
@Inject(method = "onCustomPayload", at = @At("HEAD"), cancellable = true)
|
||||
private void handleCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) {
|
||||
if (this.addon.handle(packet)) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "onDisconnected", at = @At("HEAD"))
|
||||
private void handleDisconnection(Text reason, CallbackInfo ci) {
|
||||
this.addon.handleDisconnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientPlayNetworkAddon getAddon() {
|
||||
return this.addon;
|
||||
|
|
|
@ -14,16 +14,16 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.networking.accessor;
|
||||
package net.fabricmc.fabric.mixin.networking.client.accessor;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.client.network.ClientCommonNetworkHandler;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||
|
||||
@Mixin(ServerPlayNetworkHandler.class)
|
||||
public interface ServerPlayNetworkHandlerAccessor {
|
||||
@Mixin(ClientCommonNetworkHandler.class)
|
||||
public interface ClientCommonNetworkHandlerAccessor {
|
||||
@Accessor
|
||||
ClientConnection getConnection();
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking.client.accessor;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.client.network.ClientConfigurationNetworkHandler;
|
||||
|
||||
@Mixin(ClientConfigurationNetworkHandler.class)
|
||||
public interface ClientConfigurationNetworkHandlerAccessor {
|
||||
@Accessor
|
||||
GameProfile getProfile();
|
||||
}
|
|
@ -3,9 +3,13 @@
|
|||
"package": "net.fabricmc.fabric.mixin.networking.client",
|
||||
"compatibilityLevel": "JAVA_16",
|
||||
"client": [
|
||||
"accessor.ClientCommonNetworkHandlerAccessor",
|
||||
"accessor.ClientConfigurationNetworkHandlerAccessor",
|
||||
"accessor.ClientLoginNetworkHandlerAccessor",
|
||||
"accessor.ConnectScreenAccessor",
|
||||
"accessor.MinecraftClientAccessor",
|
||||
"ClientCommonNetworkHandlerMixin",
|
||||
"ClientConfigurationNetworkHandlerMixin",
|
||||
"ClientLoginNetworkHandlerMixin",
|
||||
"ClientPlayNetworkHandlerMixin"
|
||||
],
|
||||
|
|
|
@ -48,7 +48,9 @@ public interface PacketSender {
|
|||
*
|
||||
* @param packet the packet
|
||||
*/
|
||||
void sendPacket(Packet<?> packet);
|
||||
default void sendPacket(Packet<?> packet) {
|
||||
sendPacket(packet, (PacketCallbacks) null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet.
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking.v1;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerConfigurationNetworkHandler;
|
||||
|
||||
import net.fabricmc.fabric.api.event.Event;
|
||||
import net.fabricmc.fabric.api.event.EventFactory;
|
||||
|
||||
/**
|
||||
* Offers access to events related to the connection to a client on a logical server while a client is configuring.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public class ServerConfigurationConnectionEvents {
|
||||
/**
|
||||
* Event indicating a connection began sending configuration packets.
|
||||
*/
|
||||
public static final Event<Send> SEND = EventFactory.createArrayBacked(Send.class, callbacks -> (handler, server) -> {
|
||||
for (Send callback : callbacks) {
|
||||
callback.onSendConfiguration(handler, server);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* An event for the disconnection of the server configuration network handler.
|
||||
*
|
||||
* <p>No packets should be sent when this event is invoked.
|
||||
*/
|
||||
public static final Event<ServerConfigurationConnectionEvents.Disconnect> DISCONNECT = EventFactory.createArrayBacked(ServerConfigurationConnectionEvents.Disconnect.class, callbacks -> (handler, server) -> {
|
||||
for (ServerConfigurationConnectionEvents.Disconnect callback : callbacks) {
|
||||
callback.onConfigureDisconnect(handler, server);
|
||||
}
|
||||
});
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Send {
|
||||
void onSendConfiguration(ServerConfigurationNetworkHandler handler, MinecraftServer server);
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Disconnect {
|
||||
void onConfigureDisconnect(ServerConfigurationNetworkHandler handler, MinecraftServer server);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,447 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking.v1;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.listener.ClientCommonPacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerConfigurationNetworkHandler;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.thread.ThreadExecutor;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.server.ServerNetworkingImpl;
|
||||
import net.fabricmc.fabric.mixin.networking.accessor.ServerCommonNetworkHandlerAccessor;
|
||||
|
||||
/**
|
||||
* Offers access to configuration stage server-side networking functionalities.
|
||||
*
|
||||
* <p>Server-side networking functionalities include receiving serverbound packets, sending clientbound packets, and events related to server-side network handlers.
|
||||
*
|
||||
* <p>This class should be only used for the logical server.
|
||||
*
|
||||
* <p>See {@link ServerPlayNetworking} for information on how to use the packet
|
||||
* object-based API.
|
||||
*
|
||||
* <p>See the documentation on each class for more information.
|
||||
*
|
||||
* @see ServerLoginNetworking
|
||||
* @see ServerConfigurationNetworking
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public final class ServerConfigurationNetworking {
|
||||
/**
|
||||
* Registers a handler to a channel.
|
||||
* A global receiver is registered to all connections, in the present and future.
|
||||
*
|
||||
* <p>The handler runs on the network thread. After reading the buffer there, the server
|
||||
* must be modified in the server thread by calling {@link ThreadExecutor#execute(Runnable)}.
|
||||
*
|
||||
* <p>If a handler is already registered to the {@code channel}, this method will return {@code false}, and no change will be made.
|
||||
* Use {@link #unregisterReceiver(ServerConfigurationNetworkHandler, Identifier)} to unregister the existing handler.
|
||||
*
|
||||
* <p>For new code, {@link #registerGlobalReceiver(PacketType, ConfigurationPacketHandler)}
|
||||
* is preferred, as it is designed in a way that prevents thread safety issues.
|
||||
*
|
||||
* @param channelName the id of the channel
|
||||
* @param channelHandler the handler
|
||||
* @return false if a handler is already registered to the channel
|
||||
* @see ServerConfigurationNetworking#unregisterGlobalReceiver(Identifier)
|
||||
* @see ServerConfigurationNetworking#registerReceiver(ServerConfigurationNetworkHandler, Identifier, ConfigurationChannelHandler)
|
||||
*/
|
||||
public static boolean registerGlobalReceiver(Identifier channelName, ConfigurationChannelHandler channelHandler) {
|
||||
return ServerNetworkingImpl.CONFIGURATION.registerGlobalReceiver(channelName, channelHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a handler for a packet type.
|
||||
* A global receiver is registered to all connections, in the present and future.
|
||||
*
|
||||
* <p>If a handler is already registered for the {@code type}, this method will return {@code false}, and no change will be made.
|
||||
* Use {@link #unregisterReceiver(ServerConfigurationNetworkHandler, PacketType)} to unregister the existing handler.
|
||||
*
|
||||
* @param type the packet type
|
||||
* @param handler the handler
|
||||
* @return {@code false} if a handler is already registered to the channel
|
||||
* @see ServerConfigurationNetworking#unregisterGlobalReceiver(PacketType)
|
||||
* @see ServerConfigurationNetworking#registerReceiver(ServerConfigurationNetworkHandler, PacketType, ConfigurationPacketHandler)
|
||||
*/
|
||||
public static <T extends FabricPacket> boolean registerGlobalReceiver(PacketType<T> type, ConfigurationPacketHandler<T> handler) {
|
||||
return registerGlobalReceiver(type.getId(), new ConfigurationChannelHandlerProxy<T>() {
|
||||
@Override
|
||||
public ConfigurationPacketHandler<T> getOriginalHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(MinecraftServer server, ServerConfigurationNetworkHandler networkHandler, PacketByteBuf buf, PacketSender sender) {
|
||||
T packet = type.read(buf);
|
||||
|
||||
if (server.isOnThread()) {
|
||||
// Do not submit to the server thread if we're already running there.
|
||||
// Normally, packets are handled on the network IO thread - though it is
|
||||
// not guaranteed (for example, with 1.19.4 S2C packet bundling)
|
||||
// Since we're handling it right now, connection check is redundant.
|
||||
handler.receive(packet, sender);
|
||||
} else {
|
||||
server.execute(() -> {
|
||||
if (networkHandler.isConnectionOpen()) handler.receive(packet, sender);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the handler of a channel.
|
||||
* A global receiver is registered to all connections, in the present and future.
|
||||
*
|
||||
* <p>The {@code channel} is guaranteed not to have a handler after this call.
|
||||
*
|
||||
* @param channelName the id of the channel
|
||||
* @return the previous handler, or {@code null} if no handler was bound to the channel
|
||||
* @see ServerConfigurationNetworking#registerGlobalReceiver(Identifier, ConfigurationChannelHandler)
|
||||
* @see ServerConfigurationNetworking#unregisterReceiver(ServerConfigurationNetworkHandler, Identifier)
|
||||
*/
|
||||
@Nullable
|
||||
public static ServerConfigurationNetworking.ConfigurationChannelHandler unregisterGlobalReceiver(Identifier channelName) {
|
||||
return ServerNetworkingImpl.CONFIGURATION.unregisterGlobalReceiver(channelName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the handler for a packet type.
|
||||
* A global receiver is registered to all connections, in the present and future.
|
||||
*
|
||||
* <p>The {@code type} is guaranteed not to have an associated handler after this call.
|
||||
*
|
||||
* @param type the packet type
|
||||
* @return the previous handler, or {@code null} if no handler was bound to the channel,
|
||||
* or it was not registered using {@link #registerGlobalReceiver(PacketType, ConfigurationPacketHandler)}
|
||||
* @see ServerConfigurationNetworking#registerGlobalReceiver(PacketType, ConfigurationPacketHandler)
|
||||
* @see ServerConfigurationNetworking#unregisterReceiver(ServerConfigurationNetworkHandler, PacketType)
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends FabricPacket> ServerConfigurationNetworking.ConfigurationPacketHandler<T> unregisterGlobalReceiver(PacketType<T> type) {
|
||||
ConfigurationChannelHandler handler = ServerNetworkingImpl.CONFIGURATION.unregisterGlobalReceiver(type.getId());
|
||||
return handler instanceof ConfigurationChannelHandlerProxy<?> proxy ? (ConfigurationPacketHandler<T>) proxy.getOriginalHandler() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all channel names which global receivers are registered for.
|
||||
* A global receiver is registered to all connections, in the present and future.
|
||||
*
|
||||
* @return all channel names which global receivers are registered for.
|
||||
*/
|
||||
public static Set<Identifier> getGlobalReceivers() {
|
||||
return ServerNetworkingImpl.CONFIGURATION.getChannels();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a handler to a channel.
|
||||
* This method differs from {@link ServerConfigurationNetworking#registerGlobalReceiver(Identifier, ConfigurationChannelHandler)} since
|
||||
* the channel handler will only be applied to the player represented by the {@link ServerConfigurationNetworkHandler}.
|
||||
*
|
||||
* <p>The handler runs on the network thread. After reading the buffer there, the world
|
||||
* must be modified in the server thread by calling {@link ThreadExecutor#execute(Runnable)}.
|
||||
*
|
||||
* <p>For example, if you only register a receiver using this method when a {@linkplain ServerLoginNetworking#registerGlobalReceiver(Identifier, ServerLoginNetworking.LoginQueryResponseHandler)}
|
||||
* login response has been received, you should use {@link ServerPlayConnectionEvents#INIT} to register the channel handler.
|
||||
*
|
||||
* <p>If a handler is already registered to the {@code channelName}, this method will return {@code false}, and no change will be made.
|
||||
* Use {@link #unregisterReceiver(ServerConfigurationNetworkHandler, Identifier)} to unregister the existing handler.
|
||||
*
|
||||
* <p>For new code, {@link #registerReceiver(ServerConfigurationNetworkHandler, PacketType, ConfigurationPacketHandler)}
|
||||
* is preferred, as it is designed in a way that prevents thread safety issues.
|
||||
*
|
||||
* @param networkHandler the handler
|
||||
* @param channelName the id of the channel
|
||||
* @param channelHandler the handler
|
||||
* @return false if a handler is already registered to the channel name
|
||||
* @see ServerPlayConnectionEvents#INIT
|
||||
*/
|
||||
public static boolean registerReceiver(ServerConfigurationNetworkHandler networkHandler, Identifier channelName, ConfigurationChannelHandler channelHandler) {
|
||||
Objects.requireNonNull(networkHandler, "Network handler cannot be null");
|
||||
|
||||
return ServerNetworkingImpl.getAddon(networkHandler).registerChannel(channelName, channelHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a handler for a packet type.
|
||||
* This method differs from {@link ServerConfigurationNetworking#registerGlobalReceiver(PacketType, ConfigurationPacketHandler)} since
|
||||
* the channel handler will only be applied to the player represented by the {@link ServerConfigurationNetworkHandler}.
|
||||
*
|
||||
* <p>For example, if you only register a receiver using this method when a {@linkplain ServerLoginNetworking#registerGlobalReceiver(Identifier, ServerLoginNetworking.LoginQueryResponseHandler)}
|
||||
* login response has been received, you should use {@link ServerPlayConnectionEvents#INIT} to register the channel handler.
|
||||
*
|
||||
* <p>If a handler is already registered for the {@code type}, this method will return {@code false}, and no change will be made.
|
||||
* Use {@link #unregisterReceiver(ServerConfigurationNetworkHandler, PacketType)} to unregister the existing handler.
|
||||
*
|
||||
* @param networkHandler the network handler
|
||||
* @param type the packet type
|
||||
* @param handler the handler
|
||||
* @return {@code false} if a handler is already registered to the channel name
|
||||
* @see ServerPlayConnectionEvents#INIT
|
||||
*/
|
||||
public static <T extends FabricPacket> boolean registerReceiver(ServerConfigurationNetworkHandler networkHandler, PacketType<T> type, ConfigurationPacketHandler<T> handler) {
|
||||
return registerReceiver(networkHandler, type.getId(), new ConfigurationChannelHandlerProxy<T>() {
|
||||
@Override
|
||||
public ConfigurationPacketHandler<T> getOriginalHandler() {
|
||||
return handler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receive(MinecraftServer server, ServerConfigurationNetworkHandler networkHandler2, PacketByteBuf buf, PacketSender sender) {
|
||||
T packet = type.read(buf);
|
||||
|
||||
if (server.isOnThread()) {
|
||||
// Do not submit to the server thread if we're already running there.
|
||||
// Normally, packets are handled on the network IO thread - though it is
|
||||
// not guaranteed (for example, with 1.19.4 S2C packet bundling)
|
||||
// Since we're handling it right now, connection check is redundant.
|
||||
handler.receive(packet, sender);
|
||||
} else {
|
||||
server.execute(() -> {
|
||||
if (networkHandler2.isConnectionOpen()) handler.receive(packet, sender);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the handler of a channel.
|
||||
*
|
||||
* <p>The {@code channelName} is guaranteed not to have a handler after this call.
|
||||
*
|
||||
* @param channelName the id of the channel
|
||||
* @return the previous handler, or {@code null} if no handler was bound to the channel name
|
||||
*/
|
||||
@Nullable
|
||||
public static ServerConfigurationNetworking.ConfigurationChannelHandler unregisterReceiver(ServerConfigurationNetworkHandler networkHandler, Identifier channelName) {
|
||||
Objects.requireNonNull(networkHandler, "Network handler cannot be null");
|
||||
|
||||
return ServerNetworkingImpl.getAddon(networkHandler).unregisterChannel(channelName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the handler for a packet type.
|
||||
*
|
||||
* <p>The {@code type} is guaranteed not to have an associated handler after this call.
|
||||
*
|
||||
* @param type the type of the packet
|
||||
* @return the previous handler, or {@code null} if no handler was bound to the channel,
|
||||
* or it was not registered using {@link #registerReceiver(ServerConfigurationNetworkHandler, PacketType, ConfigurationPacketHandler)}
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends FabricPacket> ServerConfigurationNetworking.ConfigurationPacketHandler<T> unregisterReceiver(ServerConfigurationNetworkHandler networkHandler, PacketType<T> type) {
|
||||
ConfigurationChannelHandler handler = unregisterReceiver(networkHandler, type.getId());
|
||||
return handler instanceof ConfigurationChannelHandlerProxy<?> proxy ? (ConfigurationPacketHandler<T>) proxy.getOriginalHandler() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the channel names that the server can receive packets on.
|
||||
*
|
||||
* @param handler the network handler
|
||||
* @return All the channel names that the server can receive packets on
|
||||
*/
|
||||
public static Set<Identifier> getReceived(ServerConfigurationNetworkHandler handler) {
|
||||
Objects.requireNonNull(handler, "Server configuration network handler cannot be null");
|
||||
|
||||
return ServerNetworkingImpl.getAddon(handler).getReceivableChannels();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all channel names that a connected client declared the ability to receive a packets on.
|
||||
*
|
||||
* @param handler the network handler
|
||||
* @return {@code true} if the connected client has declared the ability to receive a packet on the specified channel
|
||||
*/
|
||||
public static Set<Identifier> getSendable(ServerConfigurationNetworkHandler handler) {
|
||||
Objects.requireNonNull(handler, "Server configuration network handler cannot be null");
|
||||
|
||||
return ServerNetworkingImpl.getAddon(handler).getSendableChannels();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the connected client declared the ability to receive a packet on a specified channel name.
|
||||
*
|
||||
* @param handler the network handler
|
||||
* @param channelName the channel name
|
||||
* @return {@code true} if the connected client has declared the ability to receive a packet on the specified channel
|
||||
*/
|
||||
public static boolean canSend(ServerConfigurationNetworkHandler handler, Identifier channelName) {
|
||||
Objects.requireNonNull(handler, "Server configuration network handler cannot be null");
|
||||
Objects.requireNonNull(channelName, "Channel name cannot be null");
|
||||
|
||||
return ServerNetworkingImpl.getAddon(handler).getSendableChannels().contains(channelName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the connected client declared the ability to receive a specific type of packet.
|
||||
*
|
||||
* @param handler the network handler
|
||||
* @param type the packet type
|
||||
* @return {@code true} if the connected client has declared the ability to receive a specific type of packet
|
||||
*/
|
||||
public static boolean canSend(ServerConfigurationNetworkHandler handler, PacketType<?> type) {
|
||||
Objects.requireNonNull(handler, "Server configuration network handler cannot be null");
|
||||
Objects.requireNonNull(type, "Packet type cannot be null");
|
||||
|
||||
return ServerNetworkingImpl.getAddon(handler).getSendableChannels().contains(type.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet which may be sent to a connected client.
|
||||
*
|
||||
* @param channelName the channel name
|
||||
* @param buf the packet byte buf which represents the payload of the packet
|
||||
* @return a new packet
|
||||
*/
|
||||
public static Packet<ClientCommonPacketListener> createS2CPacket(Identifier channelName, PacketByteBuf buf) {
|
||||
Objects.requireNonNull(channelName, "Channel cannot be null");
|
||||
Objects.requireNonNull(buf, "Buf cannot be null");
|
||||
|
||||
return ServerNetworkingImpl.createC2SPacket(channelName, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the packet sender which sends packets to the connected client.
|
||||
*
|
||||
* @param handler the network handler, representing the connection to the player/client
|
||||
* @return the packet sender
|
||||
*/
|
||||
public static PacketSender getSender(ServerConfigurationNetworkHandler handler) {
|
||||
Objects.requireNonNull(handler, "Server configuration network handler cannot be null");
|
||||
|
||||
return ServerNetworkingImpl.getAddon(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet to a configuring player.
|
||||
*
|
||||
* @param handler the handler to send the packet to
|
||||
* @param channelName the channel of the packet
|
||||
* @param buf the payload of the packet.
|
||||
*/
|
||||
public static void send(ServerConfigurationNetworkHandler handler, Identifier channelName, PacketByteBuf buf) {
|
||||
Objects.requireNonNull(handler, "Server configuration entity cannot be null");
|
||||
Objects.requireNonNull(channelName, "Channel name cannot be null");
|
||||
Objects.requireNonNull(buf, "Packet byte buf cannot be null");
|
||||
|
||||
handler.sendPacket(createS2CPacket(channelName, buf));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet to a configuring player.
|
||||
*
|
||||
* @param handler the network handler to send the packet to
|
||||
* @param packet the packet
|
||||
*/
|
||||
public static <T extends FabricPacket> void send(ServerConfigurationNetworkHandler handler, T packet) {
|
||||
Objects.requireNonNull(handler, "Server configuration handler cannot be null");
|
||||
Objects.requireNonNull(packet, "Packet cannot be null");
|
||||
Objects.requireNonNull(packet.getType(), "Packet#getType cannot return null");
|
||||
|
||||
PacketByteBuf buf = PacketByteBufs.create();
|
||||
packet.write(buf);
|
||||
handler.sendPacket(createS2CPacket(packet.getType().getId(), buf));
|
||||
}
|
||||
|
||||
// Helper methods
|
||||
|
||||
/**
|
||||
* Returns the <i>Minecraft</i> Server of a server configuration network handler.
|
||||
*
|
||||
* @param handler the server configuration network handler
|
||||
*/
|
||||
public static MinecraftServer getServer(ServerConfigurationNetworkHandler handler) {
|
||||
Objects.requireNonNull(handler, "Network handler cannot be null");
|
||||
|
||||
return ((ServerCommonNetworkHandlerAccessor) handler).getServer();
|
||||
}
|
||||
|
||||
private ServerConfigurationNetworking() {
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ConfigurationChannelHandler {
|
||||
/**
|
||||
* Handles an incoming packet.
|
||||
*
|
||||
* <p>This method is executed on {@linkplain io.netty.channel.EventLoop netty's event loops}.
|
||||
* Modification to the game should be {@linkplain ThreadExecutor#submit(Runnable) scheduled} using the provided Minecraft server instance.
|
||||
*
|
||||
* <p>An example usage of this is:
|
||||
* <pre>{@code
|
||||
* ServerConfigurationNetworking.registerReceiver(new Identifier("mymod", "boom"), (server, handler, buf, responseSender) -> {
|
||||
* boolean fire = buf.readBoolean();
|
||||
*
|
||||
* // All operations on the server must be executed on the server thread
|
||||
* server.execute(() -> {
|
||||
*
|
||||
* });
|
||||
* });
|
||||
* }</pre>
|
||||
* @param server the server
|
||||
* @param handler the network handler that received this packet, representing the player/client who sent the packet
|
||||
* @param buf the payload of the packet
|
||||
* @param responseSender the packet sender
|
||||
*/
|
||||
void receive(MinecraftServer server, ServerConfigurationNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender);
|
||||
}
|
||||
|
||||
/**
|
||||
* An internal packet handler that works as a proxy between old and new API.
|
||||
* @param <T> the type of the packet
|
||||
*/
|
||||
private interface ConfigurationChannelHandlerProxy<T extends FabricPacket> extends ConfigurationChannelHandler {
|
||||
ConfigurationPacketHandler<T> getOriginalHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* A thread-safe packet handler utilizing {@link FabricPacket}.
|
||||
* @param <T> the type of the packet
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ConfigurationPacketHandler<T extends FabricPacket> {
|
||||
/**
|
||||
* Handles the incoming packet. This is called on the server thread.
|
||||
*
|
||||
* <p>An example usage of this:
|
||||
* <pre>{@code
|
||||
* // See FabricPacket for creating the packet
|
||||
* ServerConfigurationNetworking.registerReceiver(BOOM_PACKET_TYPE, (packet, responseSender) -> {
|
||||
*
|
||||
* });
|
||||
* }</pre>
|
||||
*
|
||||
*
|
||||
* @param packet the packet
|
||||
* @param responseSender the packet sender
|
||||
* @see FabricPacket
|
||||
*/
|
||||
void receive(T packet, PacketSender responseSender);
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ import net.fabricmc.fabric.mixin.networking.accessor.ServerLoginNetworkHandlerAc
|
|||
* <p>Server-side networking functionalities include receiving serverbound query responses and sending clientbound query requests.
|
||||
*
|
||||
* @see ServerPlayNetworking
|
||||
* @see ServerConfigurationNetworking
|
||||
*/
|
||||
public final class ServerLoginNetworking {
|
||||
/**
|
||||
|
|
|
@ -21,9 +21,9 @@ import java.util.Set;
|
|||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.listener.ClientPlayPacketListener;
|
||||
import net.minecraft.network.listener.ClientCommonPacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
@ -60,6 +60,7 @@ import net.fabricmc.fabric.impl.networking.server.ServerNetworkingImpl;
|
|||
* <p>See the documentation on each class for more information.
|
||||
*
|
||||
* @see ServerLoginNetworking
|
||||
* @see ServerConfigurationNetworking
|
||||
*/
|
||||
public final class ServerPlayNetworking {
|
||||
/**
|
||||
|
@ -381,11 +382,11 @@ public final class ServerPlayNetworking {
|
|||
* @param buf the packet byte buf which represents the payload of the packet
|
||||
* @return a new packet
|
||||
*/
|
||||
public static Packet<ClientPlayPacketListener> createS2CPacket(Identifier channelName, PacketByteBuf buf) {
|
||||
public static Packet<ClientCommonPacketListener> createS2CPacket(Identifier channelName, PacketByteBuf buf) {
|
||||
Objects.requireNonNull(channelName, "Channel cannot be null");
|
||||
Objects.requireNonNull(buf, "Buf cannot be null");
|
||||
|
||||
return ServerNetworkingImpl.createPlayC2SPacket(channelName, buf);
|
||||
return ServerNetworkingImpl.createC2SPacket(channelName, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,9 +31,10 @@ import io.netty.util.concurrent.GenericFutureListener;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.NetworkState;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.PacketCallbacks;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.InvalidIdentifierException;
|
||||
|
||||
|
@ -65,8 +66,8 @@ public abstract class AbstractChanneledNetworkAddon<H> extends AbstractNetworkAd
|
|||
|
||||
public abstract void lateInit();
|
||||
|
||||
protected void registerPendingChannels(ChannelInfoHolder holder) {
|
||||
final Collection<Identifier> pending = holder.getPendingChannelsNames();
|
||||
protected void registerPendingChannels(ChannelInfoHolder holder, NetworkState state) {
|
||||
final Collection<Identifier> pending = holder.getPendingChannelsNames(state);
|
||||
|
||||
if (!pending.isEmpty()) {
|
||||
register(new ArrayList<>(pending));
|
||||
|
@ -169,13 +170,6 @@ public abstract class AbstractChanneledNetworkAddon<H> extends AbstractNetworkAd
|
|||
this.invokeUnregisterEvent(ids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPacket(Packet<?> packet) {
|
||||
Objects.requireNonNull(packet, "Packet cannot be null");
|
||||
|
||||
this.connection.send(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends Future<? super Void>> callback) {
|
||||
sendPacket(packet, GenericFutureListenerHolder.create(callback));
|
||||
|
|
|
@ -18,11 +18,12 @@ package net.fabricmc.fabric.impl.networking;
|
|||
|
||||
import java.util.Collection;
|
||||
|
||||
import net.minecraft.network.NetworkState;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public interface ChannelInfoHolder {
|
||||
/**
|
||||
* @return Channels which are declared as receivable by the other side but have not been declared yet.
|
||||
*/
|
||||
Collection<Identifier> getPendingChannelsNames();
|
||||
Collection<Identifier> getPendingChannelsNames(NetworkState state);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.s2c.login.LoginQueryRequestPayload;
|
||||
import net.minecraft.network.packet.s2c.login.LoginQueryRequestS2CPacket;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufLoginQueryRequestPayload;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PayloadHelper;
|
||||
|
||||
public class LoginQueryRequestS2CPacketFactory {
|
||||
public static LoginQueryRequestS2CPacket create(PacketByteBuf buf) {
|
||||
int queryId = buf.readVarInt();
|
||||
Identifier identifier = buf.readIdentifier();
|
||||
return new LoginQueryRequestS2CPacket(queryId, readPayload(identifier, buf));
|
||||
}
|
||||
|
||||
private static LoginQueryRequestPayload readPayload(Identifier id, PacketByteBuf buf) {
|
||||
return new PacketByteBufLoginQueryRequestPayload(id, PayloadHelper.read(buf));
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.NetworkState;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
|
@ -80,7 +81,7 @@ public final class NetworkingImpl {
|
|||
}
|
||||
|
||||
ClientConnection connection = ((ServerLoginNetworkHandlerAccessor) handler).getConnection();
|
||||
((ChannelInfoHolder) connection).getPendingChannelsNames().addAll(ids);
|
||||
((ChannelInfoHolder) connection).getPendingChannelsNames(NetworkState.PLAY).addAll(ids);
|
||||
NetworkingImpl.LOGGER.debug("Received accepted channels from the client for \"{}\"", handler.getConnectionInfo());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking.payload;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.s2c.login.LoginQueryRequestPayload;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public record PacketByteBufLoginQueryRequestPayload(Identifier id, PacketByteBuf data) implements LoginQueryRequestPayload {
|
||||
@Override
|
||||
public void write(PacketByteBuf buf) {
|
||||
PayloadHelper.write(buf, data());
|
||||
}
|
||||
}
|
|
@ -14,21 +14,14 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.mixin.networking.accessor;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
package net.fabricmc.fabric.impl.networking.payload;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.c2s.login.LoginQueryResponseC2SPacket;
|
||||
import net.minecraft.network.packet.c2s.login.LoginQueryResponse;
|
||||
|
||||
@Mixin(LoginQueryResponseC2SPacket.class)
|
||||
public interface LoginQueryResponseC2SPacketAccessor {
|
||||
@Accessor
|
||||
int getQueryId();
|
||||
|
||||
@Nullable
|
||||
@Accessor
|
||||
PacketByteBuf getResponse();
|
||||
public record PacketByteBufLoginQueryResponse(PacketByteBuf data) implements LoginQueryResponse {
|
||||
@Override
|
||||
public void write(PacketByteBuf buf) {
|
||||
PayloadHelper.write(buf, data());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking.payload;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.CustomPayload;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public record PacketByteBufPayload(Identifier id, PacketByteBuf data) implements CustomPayload {
|
||||
@Override
|
||||
public void write(PacketByteBuf buf) {
|
||||
PayloadHelper.write(buf, data());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking.payload;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||
|
||||
public class PayloadHelper {
|
||||
public static void write(PacketByteBuf byteBuf, PacketByteBuf data) {
|
||||
byteBuf.writeBytes(data.copy());
|
||||
}
|
||||
|
||||
public static PacketByteBuf read(PacketByteBuf byteBuf) {
|
||||
PacketByteBuf newBuf = PacketByteBufs.create();
|
||||
newBuf.writeBytes(byteBuf.copy());
|
||||
byteBuf.skipBytes(byteBuf.readableBytes());
|
||||
return newBuf;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking.server;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.network.NetworkState;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.PacketCallbacks;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerConfigurationNetworkHandler;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerConfigurationConnectionEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.fabricmc.fabric.impl.networking.AbstractChanneledNetworkAddon;
|
||||
import net.fabricmc.fabric.impl.networking.ChannelInfoHolder;
|
||||
import net.fabricmc.fabric.impl.networking.NetworkingImpl;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload;
|
||||
import net.fabricmc.fabric.mixin.networking.accessor.ServerCommonNetworkHandlerAccessor;
|
||||
|
||||
public final class ServerConfigurationNetworkAddon extends AbstractChanneledNetworkAddon<ServerConfigurationNetworking.ConfigurationChannelHandler> {
|
||||
private final ServerConfigurationNetworkHandler handler;
|
||||
private final MinecraftServer server;
|
||||
private boolean sentInitialRegisterPacket;
|
||||
|
||||
public ServerConfigurationNetworkAddon(ServerConfigurationNetworkHandler handler, MinecraftServer server) {
|
||||
super(ServerNetworkingImpl.CONFIGURATION, ((ServerCommonNetworkHandlerAccessor) handler).getConnection(), "ServerConfigurationNetworkAddon for " + handler.getDebugProfile().getName());
|
||||
this.handler = handler;
|
||||
this.server = server;
|
||||
|
||||
// Must register pending channels via lateinit
|
||||
this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkState.CONFIGURATION);
|
||||
|
||||
// Register global receivers and attach to session
|
||||
this.receiver.startSession(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lateInit() {
|
||||
for (Map.Entry<Identifier, ServerConfigurationNetworking.ConfigurationChannelHandler> entry : this.receiver.getHandlers().entrySet()) {
|
||||
this.registerChannel(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public void sendConfiguration() {
|
||||
ServerConfigurationConnectionEvents.SEND.invoker().onSendConfiguration(handler, server);
|
||||
}
|
||||
|
||||
public void onClientReady() {
|
||||
this.sendInitialChannelRegistrationPacket();
|
||||
this.sentInitialRegisterPacket = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an incoming packet.
|
||||
*
|
||||
* @param payload the payload to handle
|
||||
* @return true if the packet has been handled
|
||||
*/
|
||||
public boolean handle(PacketByteBufPayload payload) {
|
||||
return this.handle(payload.id(), payload.data());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void receive(ServerConfigurationNetworking.ConfigurationChannelHandler handler, PacketByteBuf buf) {
|
||||
handler.receive(this.server, this.handler, buf, this);
|
||||
}
|
||||
|
||||
// impl details
|
||||
|
||||
@Override
|
||||
protected void schedule(Runnable task) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet<?> createPacket(Identifier channelName, PacketByteBuf buf) {
|
||||
return ServerPlayNetworking.createS2CPacket(channelName, buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invokeRegisterEvent(List<Identifier> ids) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invokeUnregisterEvent(List<Identifier> ids) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleRegistration(Identifier channelName) {
|
||||
// If we can already send packets, immediately send the register packet for this channel
|
||||
if (this.sentInitialRegisterPacket) {
|
||||
final PacketByteBuf buf = this.createRegistrationPacket(Collections.singleton(channelName));
|
||||
|
||||
if (buf != null) {
|
||||
this.sendPacket(NetworkingImpl.REGISTER_CHANNEL, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleUnregistration(Identifier channelName) {
|
||||
// If we can already send packets, immediately send the unregister packet for this channel
|
||||
if (this.sentInitialRegisterPacket) {
|
||||
final PacketByteBuf buf = this.createRegistrationPacket(Collections.singleton(channelName));
|
||||
|
||||
if (buf != null) {
|
||||
this.sendPacket(NetworkingImpl.UNREGISTER_CHANNEL, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invokeDisconnectEvent() {
|
||||
ServerConfigurationConnectionEvents.DISCONNECT.invoker().onConfigureDisconnect(handler, server);
|
||||
this.receiver.endSession(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isReservedChannel(Identifier channelName) {
|
||||
return NetworkingImpl.isReservedPlayChannel(channelName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPacket(Packet<?> packet, PacketCallbacks callback) {
|
||||
// Ensure we flush the packet.
|
||||
handler.send(packet, callback, true);
|
||||
}
|
||||
}
|
|
@ -30,9 +30,9 @@ import io.netty.util.concurrent.GenericFutureListener;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.PacketCallbacks;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.c2s.login.LoginQueryResponseC2SPacket;
|
||||
import net.minecraft.network.packet.s2c.login.LoginCompressionS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.login.LoginQueryRequestS2CPacket;
|
||||
|
@ -46,7 +46,8 @@ import net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents;
|
|||
import net.fabricmc.fabric.api.networking.v1.ServerLoginNetworking;
|
||||
import net.fabricmc.fabric.impl.networking.AbstractNetworkAddon;
|
||||
import net.fabricmc.fabric.impl.networking.GenericFutureListenerHolder;
|
||||
import net.fabricmc.fabric.mixin.networking.accessor.LoginQueryResponseC2SPacketAccessor;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufLoginQueryRequestPayload;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufLoginQueryResponse;
|
||||
import net.fabricmc.fabric.mixin.networking.accessor.ServerLoginNetworkHandlerAccessor;
|
||||
|
||||
public final class ServerLoginNetworkAddon extends AbstractNetworkAddon<ServerLoginNetworking.LoginQueryResponseHandler> implements PacketSender {
|
||||
|
@ -128,8 +129,8 @@ public final class ServerLoginNetworkAddon extends AbstractNetworkAddon<ServerLo
|
|||
* @return true if the packet was handled
|
||||
*/
|
||||
public boolean handle(LoginQueryResponseC2SPacket packet) {
|
||||
LoginQueryResponseC2SPacketAccessor access = (LoginQueryResponseC2SPacketAccessor) packet;
|
||||
return handle(access.getQueryId(), access.getResponse());
|
||||
PacketByteBufLoginQueryResponse response = (PacketByteBufLoginQueryResponse) packet.response();
|
||||
return handle(packet.queryId(), response == null ? null : response.data());
|
||||
}
|
||||
|
||||
private boolean handle(int queryId, @Nullable PacketByteBuf originalBuf) {
|
||||
|
@ -164,17 +165,10 @@ public final class ServerLoginNetworkAddon extends AbstractNetworkAddon<ServerLo
|
|||
public Packet<?> createPacket(Identifier channelName, PacketByteBuf buf) {
|
||||
int queryId = this.queryIdFactory.nextId();
|
||||
|
||||
LoginQueryRequestS2CPacket ret = new LoginQueryRequestS2CPacket(queryId, channelName, buf);
|
||||
LoginQueryRequestS2CPacket ret = new LoginQueryRequestS2CPacket(queryId, new PacketByteBufLoginQueryRequestPayload(channelName, buf));
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPacket(Packet<?> packet) {
|
||||
Objects.requireNonNull(packet, "Packet cannot be null");
|
||||
|
||||
this.connection.send(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPacket(Packet<?> packet, @Nullable GenericFutureListener<? extends io.netty.util.concurrent.Future<? super Void>> callback) {
|
||||
sendPacket(packet, GenericFutureListenerHolder.create(callback));
|
||||
|
@ -188,7 +182,7 @@ public final class ServerLoginNetworkAddon extends AbstractNetworkAddon<ServerLo
|
|||
}
|
||||
|
||||
public void registerOutgoingPacket(LoginQueryRequestS2CPacket packet) {
|
||||
this.channels.put(packet.getQueryId(), packet.getChannel());
|
||||
this.channels.put(packet.queryId(), packet.payload().id());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -205,7 +199,7 @@ public final class ServerLoginNetworkAddon extends AbstractNetworkAddon<ServerLo
|
|||
this.receiver.endSession(this);
|
||||
}
|
||||
|
||||
public void handlePlayTransition() {
|
||||
public void handleConfigurationTransition() {
|
||||
this.receiver.endSession(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,21 +16,25 @@
|
|||
|
||||
package net.fabricmc.fabric.impl.networking.server;
|
||||
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.listener.ClientPlayPacketListener;
|
||||
import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket;
|
||||
import net.minecraft.network.listener.ClientCommonPacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket;
|
||||
import net.minecraft.server.network.ServerConfigurationNetworkHandler;
|
||||
import net.minecraft.server.network.ServerLoginNetworkHandler;
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerLoginNetworking;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.fabricmc.fabric.impl.networking.GlobalReceiverRegistry;
|
||||
import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload;
|
||||
|
||||
public final class ServerNetworkingImpl {
|
||||
public static final GlobalReceiverRegistry<ServerLoginNetworking.LoginQueryResponseHandler> LOGIN = new GlobalReceiverRegistry<>();
|
||||
public static final GlobalReceiverRegistry<ServerConfigurationNetworking.ConfigurationChannelHandler> CONFIGURATION = new GlobalReceiverRegistry<>();
|
||||
public static final GlobalReceiverRegistry<ServerPlayNetworking.PlayChannelHandler> PLAY = new GlobalReceiverRegistry<>();
|
||||
|
||||
public static ServerPlayNetworkAddon getAddon(ServerPlayNetworkHandler handler) {
|
||||
|
@ -41,7 +45,11 @@ public final class ServerNetworkingImpl {
|
|||
return (ServerLoginNetworkAddon) ((NetworkHandlerExtensions) handler).getAddon();
|
||||
}
|
||||
|
||||
public static Packet<ClientPlayPacketListener> createPlayC2SPacket(Identifier channel, PacketByteBuf buf) {
|
||||
return new CustomPayloadS2CPacket(channel, buf);
|
||||
public static ServerConfigurationNetworkAddon getAddon(ServerConfigurationNetworkHandler handler) {
|
||||
return (ServerConfigurationNetworkAddon) ((NetworkHandlerExtensions) handler).getAddon();
|
||||
}
|
||||
|
||||
public static Packet<ClientCommonPacketListener> createC2SPacket(Identifier channel, PacketByteBuf buf) {
|
||||
return new CustomPayloadS2CPacket(new PacketByteBufPayload(channel, buf));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,9 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.NetworkState;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
@ -33,8 +33,8 @@ import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
|||
import net.fabricmc.fabric.impl.networking.AbstractChanneledNetworkAddon;
|
||||
import net.fabricmc.fabric.impl.networking.ChannelInfoHolder;
|
||||
import net.fabricmc.fabric.impl.networking.NetworkingImpl;
|
||||
import net.fabricmc.fabric.mixin.networking.accessor.CustomPayloadC2SPacketAccessor;
|
||||
import net.fabricmc.fabric.mixin.networking.accessor.ServerPlayNetworkHandlerAccessor;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload;
|
||||
import net.fabricmc.fabric.mixin.networking.accessor.ServerCommonNetworkHandlerAccessor;
|
||||
|
||||
public final class ServerPlayNetworkAddon extends AbstractChanneledNetworkAddon<ServerPlayNetworking.PlayChannelHandler> {
|
||||
private final ServerPlayNetworkHandler handler;
|
||||
|
@ -42,12 +42,12 @@ public final class ServerPlayNetworkAddon extends AbstractChanneledNetworkAddon<
|
|||
private boolean sentInitialRegisterPacket;
|
||||
|
||||
public ServerPlayNetworkAddon(ServerPlayNetworkHandler handler, MinecraftServer server) {
|
||||
super(ServerNetworkingImpl.PLAY, ((ServerPlayNetworkHandlerAccessor) handler).getConnection(), "ServerPlayNetworkAddon for " + handler.player.getEntityName());
|
||||
super(ServerNetworkingImpl.PLAY, ((ServerCommonNetworkHandlerAccessor) handler).getConnection(), "ServerPlayNetworkAddon for " + handler.player.getEntityName());
|
||||
this.handler = handler;
|
||||
this.server = server;
|
||||
|
||||
// Must register pending channels via lateinit
|
||||
this.registerPendingChannels((ChannelInfoHolder) this.connection);
|
||||
this.registerPendingChannels((ChannelInfoHolder) this.connection, NetworkState.PLAY);
|
||||
|
||||
// Register global receivers and attach to session
|
||||
this.receiver.startSession(this);
|
||||
|
@ -72,12 +72,11 @@ public final class ServerPlayNetworkAddon extends AbstractChanneledNetworkAddon<
|
|||
/**
|
||||
* Handles an incoming packet.
|
||||
*
|
||||
* @param packet the packet to handle
|
||||
* @param payload the payload to handle
|
||||
* @return true if the packet has been handled
|
||||
*/
|
||||
public boolean handle(CustomPayloadC2SPacket packet) {
|
||||
CustomPayloadC2SPacketAccessor access = (CustomPayloadC2SPacketAccessor) packet;
|
||||
return this.handle(access.getChannel(), access.getData());
|
||||
public boolean handle(PacketByteBufPayload payload) {
|
||||
return this.handle(payload.id(), payload.data());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,6 +18,7 @@ package net.fabricmc.fabric.mixin.networking;
|
|||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import io.netty.channel.ChannelFuture;
|
||||
|
@ -36,9 +37,9 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
|||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.NetworkSide;
|
||||
import net.minecraft.network.NetworkState;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.PacketCallbacks;
|
||||
import net.minecraft.network.listener.PacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
|
@ -60,11 +61,11 @@ abstract class ClientConnectionMixin implements ChannelInfoHolder {
|
|||
public abstract void send(Packet<?> packet, @Nullable PacketCallbacks arg);
|
||||
|
||||
@Unique
|
||||
private Collection<Identifier> playChannels;
|
||||
private Map<NetworkState, Collection<Identifier>> playChannels;
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void initAddedFields(NetworkSide side, CallbackInfo ci) {
|
||||
this.playChannels = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
this.playChannels = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
// Must be fully qualified due to mixin not working in production without it
|
||||
|
@ -81,7 +82,7 @@ abstract class ClientConnectionMixin implements ChannelInfoHolder {
|
|||
}
|
||||
|
||||
@Inject(method = "sendImmediately", at = @At(value = "FIELD", target = "Lnet/minecraft/network/ClientConnection;packetsSentCounter:I"))
|
||||
private void checkPacket(Packet<?> packet, PacketCallbacks callback, CallbackInfo ci) {
|
||||
private void checkPacket(Packet<?> packet, PacketCallbacks callback, boolean flush, CallbackInfo ci) {
|
||||
if (this.packetListener instanceof PacketCallbackListener) {
|
||||
((PacketCallbackListener) this.packetListener).sent(packet);
|
||||
}
|
||||
|
@ -94,9 +95,9 @@ abstract class ClientConnectionMixin implements ChannelInfoHolder {
|
|||
}
|
||||
}
|
||||
|
||||
@Inject(method = "sendInternal", at = @At(value = "INVOKE_ASSIGN", target = "Lio/netty/channel/Channel;writeAndFlush(Ljava/lang/Object;)Lio/netty/channel/ChannelFuture;", remap = false), locals = LocalCapture.CAPTURE_FAILHARD)
|
||||
private void sendInternal(Packet<?> packet, @Nullable PacketCallbacks listener, NetworkState packetState, NetworkState currentState, CallbackInfo ci, ChannelFuture channelFuture) {
|
||||
if (listener instanceof GenericFutureListenerHolder holder) {
|
||||
@Inject(method = "sendInternal", at = @At(value = "INVOKE", target = "Lio/netty/channel/ChannelFuture;addListener(Lio/netty/util/concurrent/GenericFutureListener;)Lio/netty/channel/ChannelFuture;", remap = false), locals = LocalCapture.CAPTURE_FAILHARD)
|
||||
private void sendInternal(Packet<?> packet, @Nullable PacketCallbacks callbacks, boolean flush, CallbackInfo ci, ChannelFuture channelFuture) {
|
||||
if (callbacks instanceof GenericFutureListenerHolder holder) {
|
||||
channelFuture.addListener(holder.getDelegate());
|
||||
channelFuture.addListener(ChannelFutureListener.FIRE_EXCEPTION_ON_FAILURE);
|
||||
ci.cancel();
|
||||
|
@ -104,7 +105,7 @@ abstract class ClientConnectionMixin implements ChannelInfoHolder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Collection<Identifier> getPendingChannelsNames() {
|
||||
return this.playChannels;
|
||||
public Collection<Identifier> getPendingChannelsNames(NetworkState state) {
|
||||
return this.playChannels.computeIfAbsent(state, (key) -> Collections.newSetFromMap(new ConcurrentHashMap<>()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.command.CommandRegistryAccess;
|
||||
import net.minecraft.server.command.CommandManager;
|
||||
import net.minecraft.server.command.DebugConfigCommand;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
|
||||
@Mixin(CommandManager.class)
|
||||
public class CommandManagerMixin {
|
||||
@Shadow
|
||||
@Final
|
||||
private CommandDispatcher<ServerCommandSource> dispatcher;
|
||||
|
||||
@Inject(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/dedicated/command/BanIpCommand;register(Lcom/mojang/brigadier/CommandDispatcher;)V"))
|
||||
private void init(CommandManager.RegistrationEnvironment environment, CommandRegistryAccess commandRegistryAccess, CallbackInfo ci) {
|
||||
if (SharedConstants.isDevelopment) {
|
||||
// Command is registered when isDevelopment is set.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!FabricLoader.getInstance().isDevelopmentEnvironment()) {
|
||||
// Only register this command in a dev env
|
||||
return;
|
||||
}
|
||||
|
||||
DebugConfigCommand.register(this.dispatcher);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.CustomPayload;
|
||||
import net.minecraft.network.packet.c2s.common.CustomPayloadC2SPacket;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PayloadHelper;
|
||||
|
||||
@Mixin(CustomPayloadC2SPacket.class)
|
||||
public class CustomPayloadC2SPacketMixin {
|
||||
@Inject(
|
||||
method = "readPayload",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/c2s/common/CustomPayloadC2SPacket;readUnknownPayload(Lnet/minecraft/util/Identifier;Lnet/minecraft/network/PacketByteBuf;)Lnet/minecraft/network/packet/UnknownCustomPayload;"),
|
||||
cancellable = true
|
||||
)
|
||||
private static void readPayload(Identifier id, PacketByteBuf buf, CallbackInfoReturnable<CustomPayload> cir) {
|
||||
cir.setReturnValue(new PacketByteBufPayload(id, PayloadHelper.read(buf)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.CustomPayload;
|
||||
import net.minecraft.network.packet.s2c.common.CustomPayloadS2CPacket;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PayloadHelper;
|
||||
|
||||
@Mixin(CustomPayloadS2CPacket.class)
|
||||
public class CustomPayloadS2CPacketMixin {
|
||||
@Inject(
|
||||
method = "readPayload",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/common/CustomPayloadS2CPacket;readUnknownPayload(Lnet/minecraft/util/Identifier;Lnet/minecraft/network/PacketByteBuf;)Lnet/minecraft/network/packet/UnknownCustomPayload;"),
|
||||
cancellable = true
|
||||
)
|
||||
private static void readPayload(Identifier id, PacketByteBuf buf, CallbackInfoReturnable<CustomPayload> cir) {
|
||||
cir.setReturnValue(new PacketByteBufPayload(id, PayloadHelper.read(buf)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.s2c.login.LoginQueryRequestS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.login.UnknownLoginQueryRequestPayload;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
@Mixin(LoginQueryRequestS2CPacket.class)
|
||||
public class LoginQueryRequestS2CPacketMixin {
|
||||
@Inject(method = "readPayload", at = @At("HEAD"))
|
||||
private static void readPayload(Identifier id, PacketByteBuf buf, CallbackInfoReturnable<UnknownLoginQueryRequestPayload> cir) {
|
||||
throw new IllegalStateException("Must use LoginQueryRequestS2CPacketFactory");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.c2s.login.LoginQueryResponse;
|
||||
import net.minecraft.network.packet.c2s.login.LoginQueryResponseC2SPacket;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufLoginQueryResponse;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PayloadHelper;
|
||||
|
||||
@Mixin(LoginQueryResponseC2SPacket.class)
|
||||
public class LoginQueryResponseC2SPacketMixin {
|
||||
@Inject(method = "readResponse", at = @At("HEAD"), cancellable = true)
|
||||
private static void readResponse(int queryId, PacketByteBuf buf, CallbackInfoReturnable<LoginQueryResponse> cir) {
|
||||
boolean hasPayload = buf.readBoolean();
|
||||
|
||||
if (!hasPayload) {
|
||||
cir.setReturnValue(null);
|
||||
return;
|
||||
}
|
||||
|
||||
cir.setReturnValue(new PacketByteBufLoginQueryResponse(PayloadHelper.read(buf)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
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.CallbackInfoReturnable;
|
||||
|
||||
import net.minecraft.network.NetworkState;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.listener.ClientLoginPacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.s2c.login.LoginQueryRequestS2CPacket;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.LoginQueryRequestS2CPacketFactory;
|
||||
|
||||
@Mixin(NetworkState.InternalPacketHandler.class)
|
||||
public abstract class NetworkStateInternalPacketHandlerMixin<T extends ClientLoginPacketListener> {
|
||||
@Unique
|
||||
private static final Function<PacketByteBuf, LoginQueryRequestS2CPacket> LOGIN_QUERY_REQUEST_FACTORY = LoginQueryRequestS2CPacketFactory::create;
|
||||
|
||||
@Shadow public abstract <P extends Packet<? super T>> NetworkState.InternalPacketHandler<T> register(Class<P> type, Function<PacketByteBuf, P> packetFactory);
|
||||
|
||||
@Inject(method = "register", at = @At("HEAD"), cancellable = true)
|
||||
private <P extends Packet<? super T>> void register(Class<P> type, Function<PacketByteBuf, P> packetFactory, CallbackInfoReturnable<NetworkState.InternalPacketHandler<T>> cir) {
|
||||
if (type == LoginQueryRequestS2CPacket.class && packetFactory != LOGIN_QUERY_REQUEST_FACTORY) {
|
||||
cir.setReturnValue(register(LoginQueryRequestS2CPacket.class, LOGIN_QUERY_REQUEST_FACTORY));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,8 +29,8 @@ import net.fabricmc.fabric.impl.networking.server.ServerNetworkingImpl;
|
|||
|
||||
@Mixin(PlayerManager.class)
|
||||
abstract class PlayerManagerMixin {
|
||||
@Inject(method = "onPlayerConnect", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/CustomPayloadS2CPacket;<init>(Lnet/minecraft/util/Identifier;Lnet/minecraft/network/PacketByteBuf;)V"))
|
||||
private void handlePlayerConnection(ClientConnection connection, ServerPlayerEntity player, CallbackInfo ci) {
|
||||
@Inject(method = "onPlayerConnect", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/PlayerAbilitiesS2CPacket;<init>(Lnet/minecraft/entity/player/PlayerAbilities;)V"))
|
||||
private void handlePlayerConnection(ClientConnection connection, ServerPlayerEntity player, int latency, CallbackInfo ci) {
|
||||
ServerNetworkingImpl.getAddon(player.networkHandler).onClientReady();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.network.packet.c2s.common.CustomPayloadC2SPacket;
|
||||
import net.minecraft.server.network.ServerCommonNetworkHandler;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufPayload;
|
||||
import net.fabricmc.fabric.impl.networking.server.ServerConfigurationNetworkAddon;
|
||||
import net.fabricmc.fabric.impl.networking.server.ServerPlayNetworkAddon;
|
||||
|
||||
@Mixin(ServerCommonNetworkHandler.class)
|
||||
public abstract class ServerCommonNetworkHandlerMixin implements NetworkHandlerExtensions {
|
||||
@Inject(method = "onCustomPayload", at = @At("HEAD"), cancellable = true)
|
||||
private void handleCustomPayloadReceivedAsync(CustomPayloadC2SPacket packet, CallbackInfo ci) {
|
||||
if (packet.payload() instanceof PacketByteBufPayload payload) {
|
||||
boolean handled;
|
||||
|
||||
if (getAddon() instanceof ServerPlayNetworkAddon addon) {
|
||||
handled = addon.handle(payload);
|
||||
} else if (getAddon() instanceof ServerConfigurationNetworkAddon addon) {
|
||||
handled = addon.handle(payload);
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown addon");
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
ci.cancel();
|
||||
} else {
|
||||
payload.data().skipBytes(payload.data().readableBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2017, 2018, 2019 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.networking;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
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.network.ClientConnection;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.s2c.common.DisconnectS2CPacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerCommonNetworkHandler;
|
||||
import net.minecraft.server.network.ServerConfigurationNetworkHandler;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.DisconnectPacketSource;
|
||||
import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
|
||||
import net.fabricmc.fabric.impl.networking.server.ServerConfigurationNetworkAddon;
|
||||
|
||||
// We want to apply a bit earlier than other mods which may not use us in order to prevent refCount issues
|
||||
@Mixin(value = ServerConfigurationNetworkHandler.class, priority = 999)
|
||||
public abstract class ServerConfigurationNetworkHandlerMixin extends ServerCommonNetworkHandler implements NetworkHandlerExtensions, DisconnectPacketSource {
|
||||
@Unique
|
||||
ServerConfigurationNetworkAddon addon;
|
||||
|
||||
public ServerConfigurationNetworkHandlerMixin(MinecraftServer server, ClientConnection connection, int keepAliveId) {
|
||||
super(server, connection, keepAliveId);
|
||||
}
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void initAddon(CallbackInfo ci) {
|
||||
this.addon = new ServerConfigurationNetworkAddon((ServerConfigurationNetworkHandler) (Object) this, this.server);
|
||||
// A bit of a hack but it allows the field above to be set in case someone registers handlers during INIT event which refers to said field
|
||||
this.addon.lateInit();
|
||||
}
|
||||
|
||||
@Inject(method = "sendConfigurations", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getCombinedDynamicRegistries()Lnet/minecraft/registry/CombinedDynamicRegistries;"))
|
||||
private void onClientReady(CallbackInfo ci) {
|
||||
this.addon.onClientReady();
|
||||
}
|
||||
|
||||
@Inject(method = "sendConfigurations", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerConfigurationNetworkHandler;queueSendResourcePackTask()V"))
|
||||
private void sendConfigurations(CallbackInfo ci) {
|
||||
this.addon.sendConfiguration();
|
||||
}
|
||||
|
||||
@Inject(method = "onDisconnected", at = @At("HEAD"))
|
||||
private void handleDisconnection(Text reason, CallbackInfo ci) {
|
||||
this.addon.handleDisconnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerConfigurationNetworkAddon getAddon() {
|
||||
return addon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Packet<?> createDisconnectPacket(Text message) {
|
||||
return new DisconnectS2CPacket(message);
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package net.fabricmc.fabric.mixin.networking;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
@ -31,12 +32,12 @@ import net.minecraft.network.packet.s2c.login.LoginDisconnectS2CPacket;
|
|||
import net.minecraft.network.packet.s2c.login.LoginQueryRequestS2CPacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerLoginNetworkHandler;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
import net.fabricmc.fabric.impl.networking.DisconnectPacketSource;
|
||||
import net.fabricmc.fabric.impl.networking.NetworkHandlerExtensions;
|
||||
import net.fabricmc.fabric.impl.networking.PacketCallbackListener;
|
||||
import net.fabricmc.fabric.impl.networking.payload.PacketByteBufLoginQueryResponse;
|
||||
import net.fabricmc.fabric.impl.networking.server.ServerLoginNetworkAddon;
|
||||
|
||||
@Mixin(ServerLoginNetworkHandler.class)
|
||||
|
@ -46,7 +47,7 @@ abstract class ServerLoginNetworkHandlerMixin implements NetworkHandlerExtension
|
|||
private MinecraftServer server;
|
||||
|
||||
@Shadow
|
||||
public abstract void acceptPlayer();
|
||||
protected abstract void tickVerify(GameProfile profile);
|
||||
|
||||
@Unique
|
||||
private ServerLoginNetworkAddon addon;
|
||||
|
@ -56,11 +57,11 @@ abstract class ServerLoginNetworkHandlerMixin implements NetworkHandlerExtension
|
|||
this.addon = new ServerLoginNetworkAddon((ServerLoginNetworkHandler) (Object) this);
|
||||
}
|
||||
|
||||
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerLoginNetworkHandler;acceptPlayer()V"))
|
||||
private void handlePlayerJoin(ServerLoginNetworkHandler handler) {
|
||||
@Redirect(method = "tick", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerLoginNetworkHandler;tickVerify(Lcom/mojang/authlib/GameProfile;)V"))
|
||||
private void handlePlayerJoin(ServerLoginNetworkHandler instance, GameProfile profile) {
|
||||
// Do not accept the player, thereby moving into play stage until all login futures being waited on are completed
|
||||
if (this.addon.queryTick()) {
|
||||
this.acceptPlayer();
|
||||
this.tickVerify(profile);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,10 +70,14 @@ abstract class ServerLoginNetworkHandlerMixin implements NetworkHandlerExtension
|
|||
// Handle queries
|
||||
if (this.addon.handle(packet)) {
|
||||
ci.cancel();
|
||||
} else {
|
||||
if (packet.response() instanceof PacketByteBufLoginQueryResponse response) {
|
||||
response.data().skipBytes(response.data().readableBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(method = "acceptPlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getNetworkCompressionThreshold()I", ordinal = 0))
|
||||
@Redirect(method = "tickVerify", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/MinecraftServer;getNetworkCompressionThreshold()I", ordinal = 0))
|
||||
private int removeLateCompressionPacketSending(MinecraftServer server) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -82,9 +87,9 @@ abstract class ServerLoginNetworkHandlerMixin implements NetworkHandlerExtension
|
|||
this.addon.handleDisconnect();
|
||||
}
|
||||
|
||||
@Inject(method = "addToServer", at = @At("HEAD"))
|
||||
private void handlePlayTransitionNormal(ServerPlayerEntity player, CallbackInfo ci) {
|
||||
this.addon.handlePlayTransition();
|
||||
@Inject(method = "sendSuccessPacket", at = @At("HEAD"))
|
||||
private void handlePlayTransitionNormal(GameProfile profile, CallbackInfo ci) {
|
||||
this.addon.handleConfigurationTransition();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,9 +16,7 @@
|
|||
|
||||
package net.fabricmc.fabric.mixin.networking;
|
||||
|
||||
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;
|
||||
|
@ -26,9 +24,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket;
|
||||
import net.minecraft.network.packet.s2c.play.DisconnectS2CPacket;
|
||||
import net.minecraft.network.packet.s2c.common.DisconnectS2CPacket;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerCommonNetworkHandler;
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||
import net.minecraft.text.Text;
|
||||
|
||||
|
@ -38,17 +36,14 @@ import net.fabricmc.fabric.impl.networking.server.ServerPlayNetworkAddon;
|
|||
|
||||
// We want to apply a bit earlier than other mods which may not use us in order to prevent refCount issues
|
||||
@Mixin(value = ServerPlayNetworkHandler.class, priority = 999)
|
||||
abstract class ServerPlayNetworkHandlerMixin implements NetworkHandlerExtensions, DisconnectPacketSource {
|
||||
@Shadow
|
||||
@Final
|
||||
private MinecraftServer server;
|
||||
@Shadow
|
||||
@Final
|
||||
public ClientConnection connection;
|
||||
|
||||
abstract class ServerPlayNetworkHandlerMixin extends ServerCommonNetworkHandler implements NetworkHandlerExtensions, DisconnectPacketSource {
|
||||
@Unique
|
||||
private ServerPlayNetworkAddon addon;
|
||||
|
||||
private ServerPlayNetworkHandlerMixin(MinecraftServer server, ClientConnection connection, int keepAliveId) {
|
||||
super(server, connection, keepAliveId);
|
||||
}
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void initAddon(CallbackInfo ci) {
|
||||
this.addon = new ServerPlayNetworkAddon((ServerPlayNetworkHandler) (Object) this, this.server);
|
||||
|
@ -56,13 +51,6 @@ abstract class ServerPlayNetworkHandlerMixin implements NetworkHandlerExtensions
|
|||
this.addon.lateInit();
|
||||
}
|
||||
|
||||
@Inject(method = "onCustomPayload", at = @At("HEAD"), cancellable = true)
|
||||
private void handleCustomPayloadReceivedAsync(CustomPayloadC2SPacket packet, CallbackInfo ci) {
|
||||
if (this.addon.handle(packet)) {
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "onDisconnected", at = @At("HEAD"))
|
||||
private void handleDisconnection(Text reason, CallbackInfo ci) {
|
||||
this.addon.handleDisconnect();
|
||||
|
|
|
@ -19,15 +19,15 @@ package net.fabricmc.fabric.mixin.networking.accessor;
|
|||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.network.ClientConnection;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerCommonNetworkHandler;
|
||||
|
||||
@Mixin(CustomPayloadC2SPacket.class)
|
||||
public interface CustomPayloadC2SPacketAccessor {
|
||||
@Mixin(ServerCommonNetworkHandler.class)
|
||||
public interface ServerCommonNetworkHandlerAccessor {
|
||||
@Accessor
|
||||
Identifier getChannel();
|
||||
ClientConnection getConnection();
|
||||
|
||||
@Accessor
|
||||
PacketByteBuf getData();
|
||||
MinecraftServer getServer();
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
accessWidener v2 named
|
||||
|
||||
accessible class net/minecraft/network/NetworkState$InternalPacketHandler
|
|
@ -4,14 +4,20 @@
|
|||
"compatibilityLevel": "JAVA_16",
|
||||
"mixins": [
|
||||
"ClientConnectionMixin",
|
||||
"CommandManagerMixin",
|
||||
"CustomPayloadC2SPacketMixin",
|
||||
"CustomPayloadS2CPacketMixin",
|
||||
"EntityTrackerEntryMixin",
|
||||
"LoginQueryRequestS2CPacketMixin",
|
||||
"LoginQueryResponseC2SPacketMixin",
|
||||
"NetworkStateInternalPacketHandlerMixin",
|
||||
"PlayerManagerMixin",
|
||||
"ServerCommonNetworkHandlerMixin",
|
||||
"ServerConfigurationNetworkHandlerMixin",
|
||||
"ServerLoginNetworkHandlerMixin",
|
||||
"ServerPlayNetworkHandlerMixin",
|
||||
"accessor.CustomPayloadC2SPacketAccessor",
|
||||
"accessor.EntityTrackerAccessor",
|
||||
"accessor.LoginQueryResponseC2SPacketAccessor",
|
||||
"accessor.ServerPlayNetworkHandlerAccessor",
|
||||
"accessor.ServerCommonNetworkHandlerAccessor",
|
||||
"accessor.ServerLoginNetworkHandlerAccessor",
|
||||
"accessor.ThreadedAnvilChunkStorageAccessor"
|
||||
],
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
"net.fabricmc.fabric.impl.networking.client.ClientNetworkingImpl::clientInit"
|
||||
]
|
||||
},
|
||||
"accessWidener": "fabric-networking-api-v1.accesswidener",
|
||||
"depends": {
|
||||
"fabricloader": ">=0.4.0",
|
||||
"fabric-api-base": "*"
|
||||
|
|
|
@ -27,6 +27,8 @@ import com.mojang.brigadier.CommandDispatcher;
|
|||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.listener.ClientPlayPacketListener;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.packet.s2c.play.BundleS2CPacket;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
|
@ -64,7 +66,7 @@ public final class NetworkingPlayPacketTest implements ModInitializer {
|
|||
PacketByteBuf buf2 = PacketByteBufs.create();
|
||||
buf2.writeText(Text.literal("bundled #2"));
|
||||
|
||||
BundleS2CPacket packet = new BundleS2CPacket(List.of(
|
||||
BundleS2CPacket packet = new BundleS2CPacket((List<Packet<ClientPlayPacketListener>>) (Object) List.of(
|
||||
ServerPlayNetworking.createS2CPacket(TEST_CHANNEL, buf1),
|
||||
ServerPlayNetworking.createS2CPacket(TEST_CHANNEL, buf2)));
|
||||
ctx.getSource().getPlayer().networkHandler.sendPacket(packet);
|
||||
|
|
|
@ -27,10 +27,11 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
|||
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.registry.DefaultedRegistry;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
import net.minecraft.village.TradeOffer;
|
||||
import net.minecraft.village.TradeOffers;
|
||||
import net.minecraft.village.VillagerDataContainer;
|
||||
import net.minecraft.village.VillagerType;
|
||||
|
||||
@Mixin(TradeOffers.TypeAwareBuyForOneEmeraldFactory.class)
|
||||
|
@ -50,7 +51,7 @@ public abstract class TradeOffersTypeAwareBuyForOneEmeraldFactoryMixin {
|
|||
* To prevent "item" -> "air" trades, if the result of a type aware trade is air, make sure no offer is created.
|
||||
*/
|
||||
@Inject(method = "create", at = @At(value = "NEW", target = "net/minecraft/village/TradeOffer"), locals = LocalCapture.CAPTURE_FAILEXCEPTION, cancellable = true)
|
||||
private void failOnNullItem(Entity entity, Random random, CallbackInfoReturnable<TradeOffer> cir, ItemStack buyingItem) {
|
||||
private void failOnNullItem(Entity entity, Random random, CallbackInfoReturnable<TradeOffer> cir, VillagerDataContainer villagerDataContainer, ItemStack buyingItem) {
|
||||
if (buyingItem.isEmpty()) { // Will return true for an "empty" item stack that had null passed in the ctor
|
||||
cir.setReturnValue(null); // Return null to prevent creation of empty trades
|
||||
}
|
||||
|
|
|
@ -16,10 +16,8 @@
|
|||
|
||||
package net.fabricmc.fabric.impl.recipe.ingredient.client;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientLoginNetworking;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking;
|
||||
import net.fabricmc.fabric.impl.recipe.ingredient.CustomIngredientSync;
|
||||
|
||||
/**
|
||||
|
@ -28,10 +26,9 @@ import net.fabricmc.fabric.impl.recipe.ingredient.CustomIngredientSync;
|
|||
public class CustomIngredientSyncClient implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
ClientLoginNetworking.registerGlobalReceiver(CustomIngredientSync.PACKET_ID, (client, handler, buf, listenerAdder) -> {
|
||||
ClientConfigurationNetworking.registerGlobalReceiver(CustomIngredientSync.PACKET_ID, (client, handler, buf, responseSender) -> {
|
||||
int protocolVersion = buf.readVarInt();
|
||||
|
||||
return CompletableFuture.completedFuture(CustomIngredientSync.createResponsePacket(protocolVersion));
|
||||
handler.sendPacket(ClientConfigurationNetworking.createC2SPacket(CustomIngredientSync.PACKET_ID, CustomIngredientSync.createResponsePacket(protocolVersion)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,13 +23,14 @@ import io.netty.channel.ChannelHandler;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.PacketEncoder;
|
||||
import net.minecraft.network.handler.PacketEncoder;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerLoginConnectionEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerLoginNetworking;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerConfigurationConnectionEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking;
|
||||
import net.fabricmc.fabric.mixin.networking.accessor.ServerCommonNetworkHandlerAccessor;
|
||||
import net.fabricmc.fabric.mixin.recipe.ingredient.PacketEncoderMixin;
|
||||
|
||||
/**
|
||||
|
@ -81,21 +82,21 @@ public class CustomIngredientSync implements ModInitializer {
|
|||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
ServerLoginConnectionEvents.QUERY_START.register((handler, server, sender, synchronizer) -> {
|
||||
ServerConfigurationConnectionEvents.SEND.register((handler, server) -> {
|
||||
// TODO 1.20.2 canSend isnt working reliably during configuration
|
||||
//if (!ServerConfigurationNetworking.canSend(handler, PACKET_ID)) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
// Send packet with 1 so the client can send us back the list of supported tags.
|
||||
// 1 is sent in case we need a different protocol later for some reason.
|
||||
PacketByteBuf buf = PacketByteBufs.create();
|
||||
buf.writeVarInt(PROTOCOL_VERSION_1); // max supported server protocol version
|
||||
sender.sendPacket(PACKET_ID, buf);
|
||||
handler.sendPacket(ServerConfigurationNetworking.createS2CPacket(PACKET_ID, buf));
|
||||
});
|
||||
ServerLoginNetworking.registerGlobalReceiver(PACKET_ID, (server, handler, understood, buf, synchronizer, responseSender) -> {
|
||||
if (!understood) {
|
||||
// Skip if the client didn't understand the query.
|
||||
return;
|
||||
}
|
||||
|
||||
ServerConfigurationNetworking.registerGlobalReceiver(PACKET_ID, (server, handler, buf, responseSender) -> {
|
||||
Set<Identifier> supportedCustomIngredients = decodeResponsePacket(buf);
|
||||
ChannelHandler packetEncoder = handler.connection.channel.pipeline().get("encoder");
|
||||
ChannelHandler packetEncoder = ((ServerCommonNetworkHandlerAccessor) handler).getConnection().channel.pipeline().get("encoder");
|
||||
|
||||
if (packetEncoder != null) { // Null in singleplayer
|
||||
((SupportedIngredientsPacketEncoder) packetEncoder).fabric_setSupportedCustomIngredients(supportedCustomIngredients);
|
||||
|
|
|
@ -18,7 +18,7 @@ package net.fabricmc.fabric.impl.recipe.ingredient;
|
|||
|
||||
import java.util.Set;
|
||||
|
||||
import net.minecraft.network.PacketEncoder;
|
||||
import net.minecraft.network.handler.PacketEncoder;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
/**
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
|||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.network.PacketEncoder;
|
||||
import net.minecraft.network.handler.PacketEncoder;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.impl.recipe.ingredient.CustomIngredientSync;
|
||||
|
|
|
@ -22,10 +22,11 @@ import org.slf4j.LoggerFactory;
|
|||
import net.minecraft.text.Text;
|
||||
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking;
|
||||
import net.fabricmc.fabric.impl.registry.sync.RegistrySyncManager;
|
||||
import net.fabricmc.fabric.impl.registry.sync.RemapException;
|
||||
import net.fabricmc.fabric.impl.registry.sync.packet.RegistryPacketHandler;
|
||||
import net.fabricmc.fabric.mixin.networking.client.accessor.ClientCommonNetworkHandlerAccessor;
|
||||
|
||||
public class FabricRegistryClientInit implements ClientModInitializer {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(FabricRegistryClientInit.class);
|
||||
|
@ -36,10 +37,10 @@ public class FabricRegistryClientInit implements ClientModInitializer {
|
|||
}
|
||||
|
||||
private void registerSyncPacketReceiver(RegistryPacketHandler packetHandler) {
|
||||
ClientPlayNetworking.registerGlobalReceiver(packetHandler.getPacketId(), (client, handler, buf, responseSender) ->
|
||||
ClientConfigurationNetworking.registerGlobalReceiver(packetHandler.getPacketId(), (client, handler, buf, responseSender) ->
|
||||
RegistrySyncManager.receivePacket(client, packetHandler, buf, RegistrySyncManager.DEBUG || !client.isInSingleplayer(), (e) -> {
|
||||
LOGGER.error("Registry remapping failed!", e);
|
||||
client.execute(() -> handler.getConnection().disconnect(getText(e)));
|
||||
client.execute(() -> ((ClientCommonNetworkHandlerAccessor) handler).getConnection().disconnect(getText(e)));
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -14,36 +14,20 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package net.fabricmc.fabric.api.network;
|
||||
package net.fabricmc.fabric.impl.registry.sync;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.network.packet.Packet;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
|
||||
@Deprecated
|
||||
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);
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerConfigurationNetworking;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
public record ConfiguringServerPlayer(GameProfile gameProfile, Consumer<Packet<?>> sender) {
|
||||
public void sendPacket(Identifier identifier, PacketByteBuf buf) {
|
||||
sender.accept(ServerConfigurationNetworking.createS2CPacket(identifier, buf));
|
||||
}
|
||||
}
|
|
@ -21,13 +21,12 @@ import net.minecraft.registry.Registries;
|
|||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.event.registry.RegistryAttribute;
|
||||
import net.fabricmc.fabric.api.event.registry.RegistryAttributeHolder;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerConfigurationConnectionEvents;
|
||||
|
||||
public class FabricRegistryInit implements ModInitializer {
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) ->
|
||||
RegistrySyncManager.sendPacket(server, handler.player));
|
||||
ServerConfigurationConnectionEvents.SEND.register(RegistrySyncManager::configureClient);
|
||||
|
||||
// Synced in PlaySoundS2CPacket.
|
||||
RegistryAttributeHolder.get(Registries.SOUND_EVENT)
|
||||
|
|
|
@ -49,7 +49,7 @@ import net.minecraft.registry.Registries;
|
|||
import net.minecraft.registry.Registry;
|
||||
import net.minecraft.registry.RegistryKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.network.ServerConfigurationNetworkHandler;
|
||||
import net.minecraft.text.MutableText;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
|
@ -74,15 +74,19 @@ public final class RegistrySyncManager {
|
|||
|
||||
private RegistrySyncManager() { }
|
||||
|
||||
public static void sendPacket(MinecraftServer server, ServerPlayerEntity player) {
|
||||
if (!DEBUG && server.isHost(player.getGameProfile())) {
|
||||
public static void configureClient(ServerConfigurationNetworkHandler handler, MinecraftServer server) {
|
||||
sendPacket(server, new ConfiguringServerPlayer(handler.getDebugProfile(), handler::sendPacket));
|
||||
}
|
||||
|
||||
static void sendPacket(MinecraftServer server, ConfiguringServerPlayer player) {
|
||||
if (!DEBUG && server.isHost(player.gameProfile())) {
|
||||
return;
|
||||
}
|
||||
|
||||
sendPacket(player, DIRECT_PACKET_HANDLER);
|
||||
}
|
||||
|
||||
private static void sendPacket(ServerPlayerEntity player, RegistryPacketHandler handler) {
|
||||
private static void sendPacket(ConfiguringServerPlayer player, RegistryPacketHandler handler) {
|
||||
Map<Identifier, Object2IntMap<Identifier>> map = RegistrySyncManager.createAndPopulateRegistryMap(true, null);
|
||||
|
||||
if (map != null) {
|
||||
|
|
|
@ -30,10 +30,10 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||
import net.fabricmc.fabric.impl.registry.sync.ConfiguringServerPlayer;
|
||||
|
||||
/**
|
||||
* A more optimized method to sync registry ids to client.
|
||||
|
@ -73,7 +73,7 @@ public class DirectRegistryPacketHandler extends RegistryPacketHandler {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void sendPacket(ServerPlayerEntity player, Map<Identifier, Object2IntMap<Identifier>> registryMap) {
|
||||
public void sendPacket(ConfiguringServerPlayer player, Map<Identifier, Object2IntMap<Identifier>> registryMap) {
|
||||
PacketByteBuf buf = PacketByteBufs.create();
|
||||
|
||||
// Group registry ids with same namespace.
|
||||
|
|
|
@ -24,11 +24,10 @@ import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
|
||||
import net.fabricmc.fabric.impl.registry.sync.ConfiguringServerPlayer;
|
||||
import net.fabricmc.fabric.impl.registry.sync.RegistrySyncManager;
|
||||
|
||||
public abstract class RegistryPacketHandler {
|
||||
|
@ -37,7 +36,7 @@ public abstract class RegistryPacketHandler {
|
|||
|
||||
public abstract Identifier getPacketId();
|
||||
|
||||
public abstract void sendPacket(ServerPlayerEntity player, Map<Identifier, Object2IntMap<Identifier>> registryMap);
|
||||
public abstract void sendPacket(ConfiguringServerPlayer player, Map<Identifier, Object2IntMap<Identifier>> registryMap);
|
||||
|
||||
public abstract void receivePacket(PacketByteBuf buf);
|
||||
|
||||
|
@ -48,8 +47,8 @@ public abstract class RegistryPacketHandler {
|
|||
@Nullable
|
||||
public abstract Map<Identifier, Object2IntMap<Identifier>> getSyncedRegistryMap();
|
||||
|
||||
protected final void sendPacket(ServerPlayerEntity player, PacketByteBuf buf) {
|
||||
ServerPlayNetworking.send(player, getPacketId(), buf);
|
||||
protected final void sendPacket(ConfiguringServerPlayer player, PacketByteBuf buf) {
|
||||
player.sendPacket(getPacketId(), buf);
|
||||
}
|
||||
|
||||
protected final void computeBufSize(PacketByteBuf buf) {
|
||||
|
|
|
@ -74,13 +74,14 @@ public final class DynamicRegistryClientTest implements ClientModInitializer {
|
|||
throw new AssertionError("Entries in " + TEST_SYNCED_2_DYNAMIC_REGISTRY_KEY + " should use network codec");
|
||||
}
|
||||
|
||||
if (simpleNested == null) {
|
||||
didNotReceive(TEST_NESTED_DYNAMIC_REGISTRY_KEY, SYNCED_ID);
|
||||
}
|
||||
// TODO 1.20.2
|
||||
//if (simpleNested == null) {
|
||||
// didNotReceive(TEST_NESTED_DYNAMIC_REGISTRY_KEY, SYNCED_ID);
|
||||
//}
|
||||
|
||||
if (simpleNested.nested().value() != synced1) {
|
||||
throw new AssertionError("Did not match up synced nested entry to the other synced value");
|
||||
}
|
||||
//if (simpleNested.nested().value() != synced1) {
|
||||
// throw new AssertionError("Did not match up synced nested entry to the other synced value");
|
||||
//}
|
||||
|
||||
// If the registries weren't passed through in SP, check that the empty registry was skipped.
|
||||
if (client.getServer() == null && handler.getRegistryManager().getOptional(TEST_EMPTY_SYNCED_DYNAMIC_REGISTRY_KEY).isPresent()) {
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"depends": {
|
||||
"fabric-renderer-api-v1":"*",
|
||||
"fabric-resource-loader-v0": "*"
|
||||
},
|
||||
"entrypoints": {
|
||||
|
|
|
@ -27,10 +27,9 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
|||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import net.minecraft.client.render.entity.EntityRenderer;
|
||||
import net.minecraft.client.render.entity.EntityRendererFactory;
|
||||
import net.minecraft.client.render.entity.EntityRenderers;
|
||||
import net.minecraft.client.network.AbstractClientPlayerEntity;
|
||||
import net.minecraft.client.render.entity.EntityRenderer;
|
||||
import net.minecraft.client.render.entity.LivingEntityRenderer;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
|
@ -69,7 +68,7 @@ public abstract class EntityRenderersMixin {
|
|||
// private static synthetic method_32175(Lcom/google/common/collect/ImmutableMap$Builder;Lnet/minecraft/class_5617$class_5618;Ljava/lang/String;Lnet/minecraft/class_5617;)V
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Redirect(method = "method_32175", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/EntityRendererFactory;create(Lnet/minecraft/client/render/entity/EntityRendererFactory$Context;)Lnet/minecraft/client/render/entity/EntityRenderer;"))
|
||||
private static EntityRenderer<? extends PlayerEntity> createPlayerEntityRenderer(EntityRendererFactory<AbstractClientPlayerEntity> playerEntityRendererFactory, EntityRendererFactory.Context context, ImmutableMap.Builder builder, EntityRendererFactory.Context context2, String str, EntityRendererFactory<AbstractClientPlayerEntity> playerEntityRendererFactory2) {
|
||||
private static EntityRenderer<? extends PlayerEntity> createPlayerEntityRenderer(EntityRendererFactory playerEntityRendererFactory, EntityRendererFactory.Context context) {
|
||||
EntityRenderer<? extends PlayerEntity> entityRenderer = playerEntityRendererFactory.create(context);
|
||||
|
||||
LivingEntityRendererAccessor accessor = (LivingEntityRendererAccessor) entityRenderer;
|
||||
|
|
|
@ -5,9 +5,6 @@
|
|||
"version": "1.0.0",
|
||||
"environment": "*",
|
||||
"license": "Apache-2.0",
|
||||
"depends": {
|
||||
"fabric-rendering-v1": "*"
|
||||
},
|
||||
"entrypoints": {
|
||||
"main": [
|
||||
"net.fabricmc.fabric.test.rendering.TooltipComponentTestInit"
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.spongepowered.asm.mixin.injection.ModifyArg;
|
|||
|
||||
import net.minecraft.client.resource.DefaultClientResourcePackProvider;
|
||||
import net.minecraft.resource.AbstractFileResourcePack;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.resource.ResourcePackProfile;
|
||||
import net.minecraft.resource.ResourcePackSource;
|
||||
import net.minecraft.resource.ResourceType;
|
||||
|
@ -51,7 +52,18 @@ public class DefaultClientResourcePackProviderMixin {
|
|||
)
|
||||
private ResourcePackProfile.PackFactory onCreateVanillaBuiltinResourcePack(String name, Text displayName, boolean alwaysEnabled,
|
||||
ResourcePackProfile.PackFactory packFactory, ResourceType type, ResourcePackProfile.InsertionPosition position, ResourcePackSource source) {
|
||||
return factory -> new FabricWrappedVanillaResourcePack((AbstractFileResourcePack) packFactory.open(name), getModResourcePacks(name));
|
||||
return new ResourcePackProfile.PackFactory() {
|
||||
@Override
|
||||
public ResourcePack open(String name) {
|
||||
return new FabricWrappedVanillaResourcePack((AbstractFileResourcePack) packFactory.open(name), getModResourcePacks(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourcePack openWithOverlays(String string, ResourcePackProfile.Metadata metadata) {
|
||||
// VanillaResourcePackProvider does not handle overlays
|
||||
return open(name);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,6 +20,8 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.minecraft.resource.OverlayResourcePack;
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.resource.ResourcePackProfile;
|
||||
import net.minecraft.resource.ResourcePackProvider;
|
||||
import net.minecraft.resource.ResourcePackSource;
|
||||
|
@ -79,9 +81,33 @@ public class ModResourcePackCreator implements ResourcePackProvider {
|
|||
// Mod resource packs must always be enabled to avoid issues, and they are inserted
|
||||
// on top to ensure that they are applied after vanilla built-in resource packs.
|
||||
MutableText title = Text.translatable("pack.name.fabricMods");
|
||||
ResourcePackProfile resourcePackProfile = ResourcePackProfile.create("fabric", title,
|
||||
true, factory -> new FabricModResourcePack(this.type, packs), type, ResourcePackProfile.InsertionPosition.TOP,
|
||||
RESOURCE_PACK_SOURCE);
|
||||
ResourcePackProfile resourcePackProfile = ResourcePackProfile.create("fabric", title, true, new ResourcePackProfile.PackFactory() {
|
||||
@Override
|
||||
public ResourcePack open(String name) {
|
||||
return new FabricModResourcePack(type, packs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourcePack openWithOverlays(String name, ResourcePackProfile.Metadata metadata) {
|
||||
final ResourcePack basePack = open(name);
|
||||
final List<String> overlays = metadata.overlays();
|
||||
|
||||
if (overlays.isEmpty()) {
|
||||
return basePack;
|
||||
}
|
||||
|
||||
final List<ResourcePack> overlayedPacks = new ArrayList<>(overlays.size());
|
||||
|
||||
for (String overlay : overlays) {
|
||||
List<ModResourcePack> innerPacks = new ArrayList<>();
|
||||
ModResourcePackUtil.appendModResourcePacks(innerPacks, type, overlay);
|
||||
|
||||
overlayedPacks.add(new FabricModResourcePack(type, innerPacks));
|
||||
}
|
||||
|
||||
return new OverlayResourcePack(basePack, overlayedPacks);
|
||||
}
|
||||
}, type, ResourcePackProfile.InsertionPosition.TOP, RESOURCE_PACK_SOURCE);
|
||||
|
||||
if (resourcePackProfile != null) {
|
||||
consumer.accept(resourcePackProfile);
|
||||
|
|
|
@ -32,6 +32,7 @@ import com.google.common.collect.Lists;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import net.minecraft.resource.ResourcePack;
|
||||
import net.minecraft.resource.ResourcePackProfile;
|
||||
import net.minecraft.resource.ResourceReloader;
|
||||
import net.minecraft.resource.ResourceType;
|
||||
|
@ -111,15 +112,18 @@ public class ResourceManagerHelperImpl implements ResourceManagerHelper {
|
|||
// Add the built-in pack only if namespaces for the specified resource type are present.
|
||||
if (!pack.getNamespaces(resourceType).isEmpty()) {
|
||||
// Make the resource pack profile for built-in pack, should never be always enabled.
|
||||
ResourcePackProfile profile = ResourcePackProfile.create(
|
||||
entry.getRight().getName(),
|
||||
entry.getLeft(),
|
||||
pack.getActivationType() == ResourcePackActivationType.ALWAYS_ENABLED,
|
||||
ignored -> entry.getRight(),
|
||||
resourceType,
|
||||
ResourcePackProfile.InsertionPosition.TOP,
|
||||
new BuiltinModResourcePackSource(pack.getFabricModMetadata().getName())
|
||||
);
|
||||
ResourcePackProfile profile = ResourcePackProfile.create(entry.getRight().getName(), entry.getLeft(), pack.getActivationType() == ResourcePackActivationType.ALWAYS_ENABLED, new ResourcePackProfile.PackFactory() {
|
||||
@Override
|
||||
public ResourcePack open(String name) {
|
||||
return entry.getRight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourcePack openWithOverlays(String string, ResourcePackProfile.Metadata metadata) {
|
||||
// Don't support overlays in builtin res packs.
|
||||
return entry.getRight();
|
||||
}
|
||||
}, resourceType, ResourcePackProfile.InsertionPosition.TOP, new BuiltinModResourcePackSource(pack.getFabricModMetadata().getName()));
|
||||
consumer.accept(profile);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,8 +38,6 @@ abstract class MouseMixin {
|
|||
private MinecraftClient client;
|
||||
@Unique
|
||||
private Screen currentScreen;
|
||||
@Unique
|
||||
private Double horizontalScrollAmount;
|
||||
|
||||
// private synthetic method_1611([ZDDI)V
|
||||
@Inject(method = "method_1611([ZLnet/minecraft/client/gui/screen/Screen;DDI)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;mouseClicked(DDI)Z"), cancellable = true)
|
||||
|
@ -116,8 +114,8 @@ abstract class MouseMixin {
|
|||
thisRef.currentScreen = null;
|
||||
}
|
||||
|
||||
@Inject(method = "onMouseScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;mouseScrolled(DDD)Z"), locals = LocalCapture.CAPTURE_FAILEXCEPTION, cancellable = true)
|
||||
private void beforeMouseScrollEvent(long window, double horizontal, double vertical, CallbackInfo ci, double verticalAmount, double mouseX, double mouseY) {
|
||||
@Inject(method = "onMouseScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;mouseScrolled(DDDD)Z"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
|
||||
private void beforeMouseScrollEvent(long window, double horizontal, double vertical, CallbackInfo ci, boolean sensitivity, double discreteScroll, double horizontalAmount, double verticalAmount, double mouseX, double mouseY) {
|
||||
// Store the screen in a variable in case someone tries to change the screen during this before event.
|
||||
// If someone changes the screen, the after event will likely have class cast exceptions or throw a NPE.
|
||||
this.currentScreen = this.client.currentScreen;
|
||||
|
@ -126,27 +124,22 @@ abstract class MouseMixin {
|
|||
return;
|
||||
}
|
||||
|
||||
// Apply same calculations to horizontal scroll as vertical scroll amount has
|
||||
this.horizontalScrollAmount = this.client.options.getDiscreteMouseScroll().getValue() ? Math.signum(horizontal) : horizontal * this.client.options.getMouseWheelSensitivity().getValue();
|
||||
|
||||
if (!ScreenMouseEvents.allowMouseScroll(this.currentScreen).invoker().allowMouseScroll(this.currentScreen, mouseX, mouseY, this.horizontalScrollAmount, verticalAmount)) {
|
||||
if (!ScreenMouseEvents.allowMouseScroll(this.currentScreen).invoker().allowMouseScroll(this.currentScreen, mouseX, mouseY, horizontalAmount, verticalAmount)) {
|
||||
this.currentScreen = null;
|
||||
this.horizontalScrollAmount = null;
|
||||
ci.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenMouseEvents.beforeMouseScroll(this.currentScreen).invoker().beforeMouseScroll(this.currentScreen, mouseX, mouseY, this.horizontalScrollAmount, verticalAmount);
|
||||
ScreenMouseEvents.beforeMouseScroll(this.currentScreen).invoker().beforeMouseScroll(this.currentScreen, mouseX, mouseY, horizontalAmount, verticalAmount);
|
||||
}
|
||||
|
||||
@Inject(method = "onMouseScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;mouseScrolled(DDD)Z", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
|
||||
private void afterMouseScrollEvent(long window, double horizontal, double vertical, CallbackInfo ci, double verticalAmount, double mouseX, double mouseY) {
|
||||
@Inject(method = "onMouseScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;mouseScrolled(DDDD)Z", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD)
|
||||
private void afterMouseScrollEvent(long window, double horizontal, double vertical, CallbackInfo ci, boolean sensitivity, double discreteScroll, double horizontalAmount, double verticalAmount, double mouseX, double mouseY) {
|
||||
if (this.currentScreen == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScreenMouseEvents.afterMouseScroll(this.currentScreen).invoker().afterMouseScroll(this.currentScreen, mouseX, mouseY, this.horizontalScrollAmount, verticalAmount);
|
||||
ScreenMouseEvents.afterMouseScroll(this.currentScreen).invoker().afterMouseScroll(this.currentScreen, mouseX, mouseY, horizontalAmount, verticalAmount);
|
||||
this.currentScreen = null;
|
||||
this.horizontalScrollAmount = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ import net.fabricmc.fabric.api.client.screen.v1.ScreenKeyboardEvents;
|
|||
import net.fabricmc.fabric.api.client.screen.v1.Screens;
|
||||
|
||||
public final class ScreenTests implements ClientModInitializer {
|
||||
public static final Identifier GUI_ICONS_TEXTURE = new Identifier("textures/gui/icons.png");
|
||||
public static final Identifier ARMOR_FULL_TEXTURE = new Identifier("hud/armor_full");
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("FabricScreenApiTests");
|
||||
|
||||
@Override
|
||||
|
@ -76,7 +76,7 @@ public final class ScreenTests implements ClientModInitializer {
|
|||
// Register render event to draw an icon on the screen
|
||||
ScreenEvents.afterRender(screen).register((_screen, drawContext, mouseX, mouseY, tickDelta) -> {
|
||||
// Render an armor icon to test
|
||||
drawContext.drawTexture(ScreenTests.GUI_ICONS_TEXTURE, (screen.width / 2) - 124, (screen.height / 4) + 96, 20, 20, 34, 9, 9, 9, 256, 256);
|
||||
drawContext.drawGuiTexture(ScreenTests.ARMOR_FULL_TEXTURE, (screen.width / 2) - 124, (screen.height / 4) + 96, 20, 20);
|
||||
});
|
||||
|
||||
ScreenKeyboardEvents.allowKeyPress(screen).register((_screen, key, scancode, modifiers) -> {
|
||||
|
|
|
@ -36,7 +36,7 @@ class StopSoundButton extends PressableWidget {
|
|||
@Override
|
||||
public void render(DrawContext drawContext, int mouseX, int mouseY, float tickDelta) {
|
||||
// Render the armor icon to test
|
||||
drawContext.drawTexture(ScreenTests.GUI_ICONS_TEXTURE, this.getX(), this.getY(), this.width, this.height, 43, 27, 9, 9, 256, 256);
|
||||
drawContext.drawGuiTexture(ScreenTests.ARMOR_FULL_TEXTURE, this.getX(), this.getY(), this.width, this.height);
|
||||
|
||||
if (this.isMouseOver(mouseX, mouseY)) {
|
||||
drawContext.drawTooltip(Screens.getTextRenderer(this.screen), Text.literal("Click to stop all sounds"), this.getX(), this.getY());
|
||||
|
|
|
@ -48,7 +48,7 @@ public class PositionedScreen extends HandledScreen<ScreenHandler> {
|
|||
|
||||
@Override
|
||||
public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) {
|
||||
renderBackground(drawContext);
|
||||
renderBackground(drawContext, mouseX, mouseY, delta);
|
||||
super.render(drawContext, mouseX, mouseY, delta);
|
||||
drawMouseoverTooltip(drawContext, mouseX, mouseY);
|
||||
}
|
||||
|
|
|
@ -29,14 +29,15 @@ transitive-accessible field net/minecraft/loot/LootTable pools [Lnet/minecraft/l
|
|||
transitive-accessible field net/minecraft/loot/LootTable functions [Lnet/minecraft/loot/function/LootFunction;
|
||||
|
||||
# Villager trade factories
|
||||
transitive-accessible class net/minecraft/village/TradeOffers$BuyForOneEmeraldFactory
|
||||
transitive-accessible class net/minecraft/village/TradeOffers$TypedWrapperFactory
|
||||
transitive-accessible class net/minecraft/village/TradeOffers$EnchantBookFactory
|
||||
transitive-accessible class net/minecraft/village/TradeOffers$BuyItemFactory
|
||||
transitive-accessible class net/minecraft/village/TradeOffers$SellItemFactory
|
||||
transitive-accessible class net/minecraft/village/TradeOffers$SellSuspiciousStewFactory
|
||||
transitive-accessible class net/minecraft/village/TradeOffers$ProcessItemFactory
|
||||
transitive-accessible class net/minecraft/village/TradeOffers$SellEnchantedToolFactory
|
||||
transitive-accessible class net/minecraft/village/TradeOffers$TypeAwareBuyForOneEmeraldFactory
|
||||
transitive-accessible class net/minecraft/village/TradeOffers$SellPotionHoldingItemFactory
|
||||
transitive-accessible class net/minecraft/village/TradeOffers$EnchantBookFactory
|
||||
transitive-accessible class net/minecraft/village/TradeOffers$SellMapFactory
|
||||
transitive-accessible class net/minecraft/village/TradeOffers$SellDyedArmorFactory
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue