mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-01-10 01:10:30 +00:00
Simplify our networking multi-platform code
Historically we used Forge's SimpleChannel methods (and PacketDistributor) to send the packets to the client. However, we don't need to do that - it is sufficient to convert it to a vanilla packet, and send the packet ourselves. Given we need to do this on Fabric, it makes sense to do this on Forge as well. This allows us to unify (and thus simplify) a lot of how packet sending works. At the same time, we also remove the handling of speaker audio during decoding. We originally did this to avoid the additional copy of audio data. However, this doesn't work on 1.20.4 (as packets aren't encoded/decoded on singleplayer), so it makes sense to do this Correctly(TM). This also allows us to get rid of ClientNetworkContext.get(). We do still need to service load this class (as Forge's networking isn't split up in the same way Fabric's is), but we'll be able to drop that in 1.20.4. Finally, we move the record playing code from ClientNetworkContext to ClientPlatformHelper. This means the network context no longer needs to be platform-specific!
This commit is contained in:
parent
be4512d1c3
commit
30dc4cb38c
@ -7,7 +7,7 @@ package dan200.computercraft.client.gui;
|
||||
import dan200.computercraft.client.gui.widgets.ComputerSidebar;
|
||||
import dan200.computercraft.client.gui.widgets.DynamicImageButton;
|
||||
import dan200.computercraft.client.gui.widgets.TerminalWidget;
|
||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||
import dan200.computercraft.client.network.ClientNetworking;
|
||||
import dan200.computercraft.core.terminal.Terminal;
|
||||
import dan200.computercraft.shared.computer.core.ComputerFamily;
|
||||
import dan200.computercraft.shared.computer.core.InputHandler;
|
||||
@ -207,7 +207,7 @@ public abstract class AbstractComputerScreen<T extends AbstractComputerMenu> ext
|
||||
return;
|
||||
}
|
||||
|
||||
if (toUpload.size() > 0) UploadFileMessage.send(menu, toUpload, ClientPlatformHelper.get()::sendToServer);
|
||||
if (toUpload.size() > 0) UploadFileMessage.send(menu, toUpload, ClientNetworking::sendToServer);
|
||||
}
|
||||
|
||||
public void uploadResult(UploadResult result, @Nullable Component message) {
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
package dan200.computercraft.client.gui;
|
||||
|
||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||
import dan200.computercraft.client.network.ClientNetworking;
|
||||
import dan200.computercraft.shared.computer.core.InputHandler;
|
||||
import dan200.computercraft.shared.computer.menu.ComputerMenu;
|
||||
import dan200.computercraft.shared.network.server.ComputerActionServerMessage;
|
||||
@ -29,51 +29,51 @@ public final class ClientInputHandler implements InputHandler {
|
||||
|
||||
@Override
|
||||
public void turnOn() {
|
||||
ClientPlatformHelper.get().sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.TURN_ON));
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.TURN_ON));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
ClientPlatformHelper.get().sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.SHUTDOWN));
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.SHUTDOWN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reboot() {
|
||||
ClientPlatformHelper.get().sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.REBOOT));
|
||||
ClientNetworking.sendToServer(new ComputerActionServerMessage(menu, ComputerActionServerMessage.Action.REBOOT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void queueEvent(String event, @Nullable Object[] arguments) {
|
||||
ClientPlatformHelper.get().sendToServer(new QueueEventServerMessage(menu, event, arguments));
|
||||
ClientNetworking.sendToServer(new QueueEventServerMessage(menu, event, arguments));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyDown(int key, boolean repeat) {
|
||||
ClientPlatformHelper.get().sendToServer(new KeyEventServerMessage(menu, repeat ? KeyEventServerMessage.TYPE_REPEAT : KeyEventServerMessage.TYPE_DOWN, key));
|
||||
ClientNetworking.sendToServer(new KeyEventServerMessage(menu, repeat ? KeyEventServerMessage.TYPE_REPEAT : KeyEventServerMessage.TYPE_DOWN, key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyUp(int key) {
|
||||
ClientPlatformHelper.get().sendToServer(new KeyEventServerMessage(menu, KeyEventServerMessage.TYPE_UP, key));
|
||||
ClientNetworking.sendToServer(new KeyEventServerMessage(menu, KeyEventServerMessage.TYPE_UP, key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClick(int button, int x, int y) {
|
||||
ClientPlatformHelper.get().sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_CLICK, button, x, y));
|
||||
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_CLICK, button, x, y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseUp(int button, int x, int y) {
|
||||
ClientPlatformHelper.get().sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_UP, button, x, y));
|
||||
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_UP, button, x, y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDrag(int button, int x, int y) {
|
||||
ClientPlatformHelper.get().sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_DRAG, button, x, y));
|
||||
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_DRAG, button, x, y));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseScroll(int direction, int x, int y) {
|
||||
ClientPlatformHelper.get().sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_SCROLL, direction, x, y));
|
||||
ClientNetworking.sendToServer(new MouseEventServerMessage(menu, MouseEventServerMessage.TYPE_SCROLL, direction, x, y));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.client.network;
|
||||
|
||||
import dan200.computercraft.client.platform.ClientPlatformHelper;
|
||||
import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworkContext;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
/**
|
||||
* Methods for sending packets from clients to the server.
|
||||
*/
|
||||
public class ClientNetworking {
|
||||
/**
|
||||
* Send a network message to the server.
|
||||
*
|
||||
* @param message The message to send.
|
||||
*/
|
||||
public static void sendToServer(NetworkMessage<ServerNetworkContext> message) {
|
||||
var connection = Minecraft.getInstance().getConnection();
|
||||
if (connection != null) connection.send(ClientPlatformHelper.get().createPacket(message));
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
|
||||
package dan200.computercraft.client.platform;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import dan200.computercraft.client.ClientTableFormatter;
|
||||
import dan200.computercraft.client.gui.AbstractComputerScreen;
|
||||
import dan200.computercraft.client.gui.OptionScreen;
|
||||
@ -17,30 +18,30 @@ import dan200.computercraft.shared.computer.upload.UploadResult;
|
||||
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* The base implementation of {@link ClientNetworkContext}.
|
||||
* <p>
|
||||
* This should be extended by mod loader specific modules with the remaining abstract methods.
|
||||
* The client-side implementation of {@link ClientNetworkContext}.
|
||||
*/
|
||||
public abstract class AbstractClientNetworkContext implements ClientNetworkContext {
|
||||
@AutoService(ClientNetworkContext.class)
|
||||
public final class ClientNetworkContextImpl implements ClientNetworkContext {
|
||||
@Override
|
||||
public final void handleChatTable(TableBuilder table) {
|
||||
public void handleChatTable(TableBuilder table) {
|
||||
ClientTableFormatter.INSTANCE.display(table);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleComputerTerminal(int containerId, TerminalState terminal) {
|
||||
public void handleComputerTerminal(int containerId, TerminalState terminal) {
|
||||
Player player = Minecraft.getInstance().player;
|
||||
if (player != null && player.containerMenu.containerId == containerId && player.containerMenu instanceof ComputerMenu menu) {
|
||||
menu.updateTerminal(terminal);
|
||||
@ -48,7 +49,7 @@ public abstract class AbstractClientNetworkContext implements ClientNetworkConte
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleMonitorData(BlockPos pos, TerminalState terminal) {
|
||||
public void handleMonitorData(BlockPos pos, TerminalState terminal) {
|
||||
var player = Minecraft.getInstance().player;
|
||||
if (player == null) return;
|
||||
|
||||
@ -59,44 +60,46 @@ public abstract class AbstractClientNetworkContext implements ClientNetworkConte
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handlePocketComputerData(int instanceId, ComputerState state, int lightState, TerminalState terminal) {
|
||||
public void handlePlayRecord(BlockPos pos, @Nullable SoundEvent sound, @Nullable String name) {
|
||||
var mc = Minecraft.getInstance();
|
||||
ClientPlatformHelper.get().playStreamingMusic(pos, sound);
|
||||
if (name != null) mc.gui.setNowPlaying(Component.literal(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePocketComputerData(int instanceId, ComputerState state, int lightState, TerminalState terminal) {
|
||||
var computer = ClientPocketComputers.get(instanceId, terminal.colour);
|
||||
computer.setState(state, lightState);
|
||||
if (terminal.hasTerminal()) computer.setTerminal(terminal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handlePocketComputerDeleted(int instanceId) {
|
||||
public void handlePocketComputerDeleted(int instanceId) {
|
||||
ClientPocketComputers.remove(instanceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleSpeakerAudio(UUID source, SpeakerPosition.Message position, float volume) {
|
||||
SpeakerManager.getSound(source).playAudio(reifyPosition(position), volume);
|
||||
public void handleSpeakerAudio(UUID source, SpeakerPosition.Message position, float volume, ByteBuffer buffer) {
|
||||
SpeakerManager.getSound(source).playAudio(reifyPosition(position), volume, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleSpeakerAudioPush(UUID source, ByteBuf buffer) {
|
||||
SpeakerManager.getSound(source).pushAudio(buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleSpeakerMove(UUID source, SpeakerPosition.Message position) {
|
||||
public void handleSpeakerMove(UUID source, SpeakerPosition.Message position) {
|
||||
SpeakerManager.moveSound(source, reifyPosition(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleSpeakerPlay(UUID source, SpeakerPosition.Message position, ResourceLocation sound, float volume, float pitch) {
|
||||
public void handleSpeakerPlay(UUID source, SpeakerPosition.Message position, ResourceLocation sound, float volume, float pitch) {
|
||||
SpeakerManager.getSound(source).playSound(reifyPosition(position), sound, volume, pitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleSpeakerStop(UUID source) {
|
||||
public void handleSpeakerStop(UUID source) {
|
||||
SpeakerManager.stopSound(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void handleUploadResult(int containerId, UploadResult result, @Nullable Component errorMessage) {
|
||||
public void handleUploadResult(int containerId, UploadResult result, @Nullable Component errorMessage) {
|
||||
var minecraft = Minecraft.getInstance();
|
||||
|
||||
var screen = OptionScreen.unwrap(minecraft.screen);
|
@ -9,6 +9,10 @@ import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworkContext;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ServerGamePacketListener;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ -18,11 +22,12 @@ public interface ClientPlatformHelper extends dan200.computercraft.impl.client.C
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a network message to the server.
|
||||
* Convert a serverbound {@link NetworkMessage} to a Minecraft {@link Packet}.
|
||||
*
|
||||
* @param message The message to send.
|
||||
* @param message The messsge to convert.
|
||||
* @return The converted message.
|
||||
*/
|
||||
void sendToServer(NetworkMessage<ServerNetworkContext> message);
|
||||
Packet<ServerGamePacketListener> createPacket(NetworkMessage<ServerNetworkContext> message);
|
||||
|
||||
/**
|
||||
* Render a {@link BakedModel}, using any loader-specific hooks.
|
||||
@ -35,4 +40,13 @@ public interface ClientPlatformHelper extends dan200.computercraft.impl.client.C
|
||||
* @param tints Block colour tints to apply to the model.
|
||||
*/
|
||||
void renderBakedModel(PoseStack transform, MultiBufferSource buffers, BakedModel model, int lightmapCoord, int overlayLight, @Nullable int[] tints);
|
||||
|
||||
/**
|
||||
* Play a record at a particular position.
|
||||
*
|
||||
* @param pos The position to play this record.
|
||||
* @param sound The record to play, or {@code null} to stop it.
|
||||
* @see net.minecraft.client.renderer.LevelRenderer#playStreamingMusic(SoundEvent, BlockPos)
|
||||
*/
|
||||
void playStreamingMusic(BlockPos pos, @Nullable SoundEvent sound);
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ package dan200.computercraft.client.sound;
|
||||
|
||||
import com.mojang.blaze3d.audio.Channel;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPeripheral;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
||||
import net.minecraft.client.sounds.AudioStream;
|
||||
import net.minecraft.client.sounds.SoundEngine;
|
||||
import org.lwjgl.BufferUtils;
|
||||
@ -36,7 +36,7 @@ class DfpwmStream implements AudioStream {
|
||||
/**
|
||||
* The {@link Channel} which this sound is playing on.
|
||||
*
|
||||
* @see SpeakerInstance#pushAudio(ByteBuf)
|
||||
* @see SpeakerInstance#playAudio(SpeakerPosition, float, ByteBuffer)
|
||||
*/
|
||||
@Nullable
|
||||
Channel channel;
|
||||
@ -44,7 +44,7 @@ class DfpwmStream implements AudioStream {
|
||||
/**
|
||||
* The underlying {@link SoundEngine} executor.
|
||||
*
|
||||
* @see SpeakerInstance#pushAudio(ByteBuf)
|
||||
* @see SpeakerInstance#playAudio(SpeakerPosition, float, ByteBuffer)
|
||||
* @see SoundEngine#executor
|
||||
*/
|
||||
@Nullable
|
||||
@ -58,12 +58,12 @@ class DfpwmStream implements AudioStream {
|
||||
DfpwmStream() {
|
||||
}
|
||||
|
||||
void push(ByteBuf input) {
|
||||
var readable = input.readableBytes();
|
||||
void push(ByteBuffer input) {
|
||||
var readable = input.remaining();
|
||||
var output = ByteBuffer.allocate(readable * 8).order(ByteOrder.nativeOrder());
|
||||
|
||||
for (var i = 0; i < readable; i++) {
|
||||
var inputByte = input.readByte();
|
||||
var inputByte = input.get();
|
||||
for (var j = 0; j < 8; j++) {
|
||||
var currentBit = (inputByte & 1) != 0;
|
||||
var target = currentBit ? 127 : -128;
|
||||
|
@ -7,11 +7,11 @@ package dan200.computercraft.client.sound;
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.core.util.Nullability;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* An instance of a speaker, which is either playing a {@link DfpwmStream} stream or a normal sound.
|
||||
@ -25,7 +25,7 @@ public class SpeakerInstance {
|
||||
SpeakerInstance() {
|
||||
}
|
||||
|
||||
public synchronized void pushAudio(ByteBuf buffer) {
|
||||
private void pushAudio(ByteBuffer buffer) {
|
||||
var sound = this.sound;
|
||||
|
||||
var stream = currentStream;
|
||||
@ -43,7 +43,9 @@ public class SpeakerInstance {
|
||||
}
|
||||
}
|
||||
|
||||
public void playAudio(SpeakerPosition position, float volume) {
|
||||
public void playAudio(SpeakerPosition position, float volume, ByteBuffer buffer) {
|
||||
pushAudio(buffer);
|
||||
|
||||
var soundManager = Minecraft.getInstance().getSoundManager();
|
||||
|
||||
if (sound != null && sound.stream != currentStream) {
|
||||
|
@ -7,7 +7,7 @@ package dan200.computercraft.shared.command.text;
|
||||
import dan200.computercraft.core.util.Nullability;
|
||||
import dan200.computercraft.shared.command.CommandUtils;
|
||||
import dan200.computercraft.shared.network.client.ChatTableClientMessage;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
@ -105,7 +105,7 @@ public class TableBuilder {
|
||||
if (CommandUtils.isPlayer(source)) {
|
||||
trim(18);
|
||||
var player = (ServerPlayer) Nullability.assertNonNull(source.getEntity());
|
||||
PlatformHelper.get().sendToPlayer(new ChatTableClientMessage(this), player);
|
||||
ServerNetworking.sendToPlayer(new ChatTableClientMessage(this), player);
|
||||
} else {
|
||||
trim(100);
|
||||
new ServerTableFormatter(source).display(this);
|
||||
|
@ -20,7 +20,7 @@ import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
||||
import dan200.computercraft.shared.network.client.ComputerTerminalClientMessage;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
@ -142,7 +142,7 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
|
||||
|
||||
for (var player : server.getPlayerList().getPlayers()) {
|
||||
if (player.containerMenu instanceof ComputerMenu && ((ComputerMenu) player.containerMenu).getComputer() == this) {
|
||||
PlatformHelper.get().sendToPlayer(createPacket.apply(player.containerMenu), player);
|
||||
ServerNetworking.sendToPlayer(createPacket.apply(player.containerMenu), player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import dan200.computercraft.shared.computer.upload.FileSlice;
|
||||
import dan200.computercraft.shared.computer.upload.FileUpload;
|
||||
import dan200.computercraft.shared.computer.upload.UploadResult;
|
||||
import dan200.computercraft.shared.network.client.UploadResultMessage;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import net.minecraft.network.chat.Component;
|
||||
@ -138,7 +138,7 @@ public class ServerInputState<T extends AbstractContainerMenu & ComputerMenu> im
|
||||
return;
|
||||
}
|
||||
|
||||
PlatformHelper.get().sendToPlayer(finishUpload(uploader), uploader);
|
||||
ServerNetworking.sendToPlayer(finishUpload(uploader), uploader);
|
||||
}
|
||||
|
||||
private UploadResultMessage finishUpload(ServerPlayer player) {
|
||||
@ -159,7 +159,7 @@ public class ServerInputState<T extends AbstractContainerMenu & ComputerMenu> im
|
||||
toUpload.stream().map(x -> new TransferredFile(x.getName(), new ByteBufferChannel(x.getBytes()))).toList(),
|
||||
() -> {
|
||||
if (player.isAlive() && player.containerMenu == owner) {
|
||||
PlatformHelper.get().sendToPlayer(UploadResultMessage.consumed(owner), player);
|
||||
ServerNetworking.sendToPlayer(UploadResultMessage.consumed(owner), player);
|
||||
}
|
||||
}),
|
||||
});
|
||||
|
@ -4,30 +4,24 @@
|
||||
|
||||
package dan200.computercraft.shared.network.client;
|
||||
|
||||
import dan200.computercraft.impl.Services;
|
||||
import dan200.computercraft.shared.command.text.TableBuilder;
|
||||
import dan200.computercraft.shared.computer.core.ComputerState;
|
||||
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||
import dan200.computercraft.shared.computer.upload.UploadResult;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* The context under which clientbound packets are evaluated.
|
||||
*/
|
||||
public interface ClientNetworkContext {
|
||||
static ClientNetworkContext get() {
|
||||
var instance = Instance.INSTANCE;
|
||||
return instance == null ? Services.raise(ClientNetworkContext.class, Instance.ERROR) : instance;
|
||||
}
|
||||
|
||||
void handleChatTable(TableBuilder table);
|
||||
|
||||
void handleComputerTerminal(int containerId, TerminalState terminal);
|
||||
@ -40,9 +34,7 @@ public interface ClientNetworkContext {
|
||||
|
||||
void handlePocketComputerDeleted(int instanceId);
|
||||
|
||||
void handleSpeakerAudio(UUID source, SpeakerPosition.Message position, float volume);
|
||||
|
||||
void handleSpeakerAudioPush(UUID source, ByteBuf buffer);
|
||||
void handleSpeakerAudio(UUID source, SpeakerPosition.Message position, float volume, ByteBuffer audio);
|
||||
|
||||
void handleSpeakerMove(UUID source, SpeakerPosition.Message position);
|
||||
|
||||
@ -51,18 +43,4 @@ public interface ClientNetworkContext {
|
||||
void handleSpeakerStop(UUID source);
|
||||
|
||||
void handleUploadResult(int containerId, UploadResult result, @Nullable Component errorMessage);
|
||||
|
||||
final class Instance {
|
||||
static final @Nullable ClientNetworkContext INSTANCE;
|
||||
static final @Nullable Throwable ERROR;
|
||||
|
||||
static {
|
||||
var helper = Services.tryLoad(ClientNetworkContext.class);
|
||||
INSTANCE = helper.instance();
|
||||
ERROR = helper.error();
|
||||
}
|
||||
|
||||
private Instance() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,12 +11,9 @@ import dan200.computercraft.shared.peripheral.speaker.SpeakerBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.UUID;
|
||||
|
||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
||||
|
||||
/**
|
||||
* Starts a sound on the client.
|
||||
* <p>
|
||||
@ -27,7 +24,7 @@ import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
||||
public class SpeakerAudioClientMessage implements NetworkMessage<ClientNetworkContext> {
|
||||
private final UUID source;
|
||||
private final SpeakerPosition.Message pos;
|
||||
private final @Nullable ByteBuffer content;
|
||||
private final ByteBuffer content;
|
||||
private final float volume;
|
||||
|
||||
public SpeakerAudioClientMessage(UUID source, SpeakerPosition pos, float volume, ByteBuffer content) {
|
||||
@ -42,10 +39,9 @@ public class SpeakerAudioClientMessage implements NetworkMessage<ClientNetworkCo
|
||||
pos = SpeakerPosition.Message.read(buf);
|
||||
volume = buf.readFloat();
|
||||
|
||||
// TODO: Remove this, so we no longer need a getter for ClientNetworkContext. However, doing so without
|
||||
// leaking or redundantly copying the buffer is hard.
|
||||
ClientNetworkContext.get().handleSpeakerAudioPush(source, buf);
|
||||
content = null;
|
||||
var bytes = new byte[buf.readableBytes()];
|
||||
buf.readBytes(bytes);
|
||||
content = ByteBuffer.wrap(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -53,12 +49,12 @@ public class SpeakerAudioClientMessage implements NetworkMessage<ClientNetworkCo
|
||||
buf.writeUUID(source);
|
||||
pos.write(buf);
|
||||
buf.writeFloat(volume);
|
||||
buf.writeBytes(assertNonNull(content).duplicate());
|
||||
buf.writeBytes(content.duplicate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ClientNetworkContext context) {
|
||||
context.handleSpeakerAudio(source, pos, volume);
|
||||
context.handleSpeakerAudio(source, pos, volume, content);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,82 @@
|
||||
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.shared.network.server;
|
||||
|
||||
import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Methods for sending network messages from the server to clients.
|
||||
*/
|
||||
public final class ServerNetworking {
|
||||
private ServerNetworking() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to a specific player.
|
||||
*
|
||||
* @param message The message to send.
|
||||
* @param player The player to send it to.
|
||||
*/
|
||||
public static void sendToPlayer(NetworkMessage<ClientNetworkContext> message, ServerPlayer player) {
|
||||
player.connection.send(PlatformHelper.get().createPacket(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to a set of players.
|
||||
*
|
||||
* @param message The message to send.
|
||||
* @param players The players to send it to.
|
||||
*/
|
||||
public static void sendToPlayers(NetworkMessage<ClientNetworkContext> message, Collection<ServerPlayer> players) {
|
||||
if (players.isEmpty()) return;
|
||||
var packet = PlatformHelper.get().createPacket(message);
|
||||
for (var player : players) player.connection.send(packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to all players.
|
||||
*
|
||||
* @param message The message to send.
|
||||
* @param server The current server.
|
||||
*/
|
||||
public static void sendToAllPlayers(NetworkMessage<ClientNetworkContext> message, MinecraftServer server) {
|
||||
server.getPlayerList().broadcastAll(PlatformHelper.get().createPacket(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to all players around a point.
|
||||
*
|
||||
* @param message The message to send.
|
||||
* @param level The level the point is in.
|
||||
* @param pos The centre position.
|
||||
* @param distance The distance to the centre players must be within.
|
||||
*/
|
||||
public static void sendToAllAround(NetworkMessage<ClientNetworkContext> message, ServerLevel level, Vec3 pos, float distance) {
|
||||
level.getServer().getPlayerList().broadcast(null, pos.x, pos.y, pos.z, distance, level.dimension(), PlatformHelper.get().createPacket(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message to all players tracking a chunk.
|
||||
*
|
||||
* @param message The message to send.
|
||||
* @param chunk The chunk players must be tracking.
|
||||
*/
|
||||
public static void sendToAllTracking(NetworkMessage<ClientNetworkContext> message, LevelChunk chunk) {
|
||||
var packet = PlatformHelper.get().createPacket(message);
|
||||
for (var player : ((ServerChunkCache) chunk.getLevel().getChunkSource()).chunkMap.getPlayers(chunk.getPos(), false)) {
|
||||
player.connection.send(packet);
|
||||
}
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.shared.common.AbstractContainerBlockEntity;
|
||||
import dan200.computercraft.shared.network.client.PlayRecordClientMessage;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
import dan200.computercraft.shared.util.WorldUtil;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@ -315,7 +315,7 @@ public final class DiskDriveBlockEntity extends AbstractContainerBlockEntity {
|
||||
}
|
||||
|
||||
private void sendMessage(PlayRecordClientMessage message) {
|
||||
PlatformHelper.get().sendToAllAround(message, (ServerLevel) getLevel(), Vec3.atCenterOf(getBlockPos()), 64);
|
||||
ServerNetworking.sendToAllAround(message, (ServerLevel) getLevel(), Vec3.atCenterOf(getBlockPos()), 64);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -7,7 +7,7 @@ package dan200.computercraft.shared.peripheral.monitor;
|
||||
import dan200.computercraft.shared.computer.terminal.TerminalState;
|
||||
import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.network.client.MonitorClientMessage;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
@ -40,7 +40,7 @@ public final class MonitorWatcher {
|
||||
if (serverMonitor == null || monitor.enqueued) continue;
|
||||
|
||||
var state = getState(monitor, serverMonitor);
|
||||
PlatformHelper.get().sendToPlayer(new MonitorClientMessage(monitor.getBlockPos(), state), player);
|
||||
ServerNetworking.sendToPlayer(new MonitorClientMessage(monitor.getBlockPos(), state), player);
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,7 +66,7 @@ public final class MonitorWatcher {
|
||||
}
|
||||
|
||||
var state = getState(tile, monitor);
|
||||
PlatformHelper.get().sendToAllTracking(new MonitorClientMessage(pos, state), chunk);
|
||||
ServerNetworking.sendToAllTracking(new MonitorClientMessage(pos, state), chunk);
|
||||
|
||||
limit -= state.size();
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ package dan200.computercraft.shared.peripheral.speaker;
|
||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||
import dan200.computercraft.core.util.Nullability;
|
||||
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
@ -32,7 +32,7 @@ public class SpeakerBlockEntity extends BlockEntity {
|
||||
public void setRemoved() {
|
||||
super.setRemoved();
|
||||
if (level != null && !level.isClientSide) {
|
||||
PlatformHelper.get().sendToAllPlayers(new SpeakerStopClientMessage(peripheral.getSource()), Nullability.assertNonNull(getLevel().getServer()));
|
||||
ServerNetworking.sendToAllPlayers(new SpeakerStopClientMessage(peripheral.getSource()), Nullability.assertNonNull(getLevel().getServer()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ import dan200.computercraft.shared.network.client.SpeakerAudioClientMessage;
|
||||
import dan200.computercraft.shared.network.client.SpeakerMoveClientMessage;
|
||||
import dan200.computercraft.shared.network.client.SpeakerPlayClientMessage;
|
||||
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
import dan200.computercraft.shared.util.PauseAwareTimer;
|
||||
import net.minecraft.ResourceLocationException;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@ -116,14 +116,14 @@ public abstract class SpeakerPeripheral implements IPeripheral {
|
||||
// Stop the speaker and nuke the position, so we don't update it again.
|
||||
if (shouldStop && lastPosition != null) {
|
||||
lastPosition = null;
|
||||
PlatformHelper.get().sendToAllPlayers(new SpeakerStopClientMessage(getSource()), server);
|
||||
ServerNetworking.sendToAllPlayers(new SpeakerStopClientMessage(getSource()), server);
|
||||
return;
|
||||
}
|
||||
|
||||
var now = PauseAwareTimer.getTime();
|
||||
if (sound != null) {
|
||||
lastPlayTime = clock;
|
||||
PlatformHelper.get().sendToAllAround(
|
||||
ServerNetworking.sendToAllAround(
|
||||
new SpeakerPlayClientMessage(getSource(), position, sound.sound, sound.volume, sound.pitch),
|
||||
(ServerLevel) level, pos, sound.volume * 16
|
||||
);
|
||||
@ -131,7 +131,7 @@ public abstract class SpeakerPeripheral implements IPeripheral {
|
||||
} else if (dfpwmState != null && dfpwmState.shouldSendPending(now)) {
|
||||
// If clients need to receive another batch of audio, send it and then notify computers our internal buffer is
|
||||
// free again.
|
||||
PlatformHelper.get().sendToAllTracking(
|
||||
ServerNetworking.sendToAllTracking(
|
||||
new SpeakerAudioClientMessage(getSource(), position, dfpwmState.getVolume(), dfpwmState.pullPending(now)),
|
||||
level.getChunkAt(BlockPos.containing(pos))
|
||||
);
|
||||
@ -150,7 +150,7 @@ public abstract class SpeakerPeripheral implements IPeripheral {
|
||||
// in the last second.
|
||||
if (lastPosition != null && (clock - lastPositionTime) >= 20 && !lastPosition.withinDistance(position, 0.1)) {
|
||||
// TODO: What to do when entities move away? How do we notify people left behind that they're gone.
|
||||
PlatformHelper.get().sendToAllTracking(
|
||||
ServerNetworking.sendToAllTracking(
|
||||
new SpeakerMoveClientMessage(getSource(), position),
|
||||
level.getChunkAt(BlockPos.containing(pos))
|
||||
);
|
||||
|
@ -6,7 +6,7 @@ package dan200.computercraft.shared.peripheral.speaker;
|
||||
|
||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||
import dan200.computercraft.shared.network.client.SpeakerStopClientMessage;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
|
||||
|
||||
/**
|
||||
@ -25,6 +25,6 @@ public abstract class UpgradeSpeakerPeripheral extends SpeakerPeripheral {
|
||||
var server = level.getServer();
|
||||
if (server == null || server.isStopped()) return;
|
||||
|
||||
PlatformHelper.get().sendToAllPlayers(new SpeakerStopClientMessage(getSource()), server);
|
||||
ServerNetworking.sendToAllPlayers(new SpeakerStopClientMessage(getSource()), server);
|
||||
}
|
||||
}
|
||||
|
@ -20,9 +20,10 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.level.ServerPlayerGameMode;
|
||||
@ -44,12 +45,10 @@ import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
@ -178,46 +177,12 @@ public interface PlatformHelper extends dan200.computercraft.impl.PlatformHelper
|
||||
<T extends NetworkMessage<?>> MessageType<T> createMessageType(int id, ResourceLocation channel, Class<T> klass, FriendlyByteBuf.Reader<T> reader);
|
||||
|
||||
/**
|
||||
* Send a message to a specific player.
|
||||
* Convert a clientbound {@link NetworkMessage} to a Minecraft {@link Packet}.
|
||||
*
|
||||
* @param message The message to send.
|
||||
* @param player The player to send it to.
|
||||
* @param message The messsge to convert.
|
||||
* @return The converted message.
|
||||
*/
|
||||
void sendToPlayer(NetworkMessage<ClientNetworkContext> message, ServerPlayer player);
|
||||
|
||||
/**
|
||||
* Send a message to a set of players.
|
||||
*
|
||||
* @param message The message to send.
|
||||
* @param players The players to send it to.
|
||||
*/
|
||||
void sendToPlayers(NetworkMessage<ClientNetworkContext> message, Collection<ServerPlayer> players);
|
||||
|
||||
/**
|
||||
* Send a message to all players.
|
||||
*
|
||||
* @param message The message to send.
|
||||
* @param server The current server.
|
||||
*/
|
||||
void sendToAllPlayers(NetworkMessage<ClientNetworkContext> message, MinecraftServer server);
|
||||
|
||||
/**
|
||||
* Send a message to all players around a point.
|
||||
*
|
||||
* @param message The message to send.
|
||||
* @param level The level the point is in.
|
||||
* @param pos The centre position.
|
||||
* @param distance The distance to the centre players must be within.
|
||||
*/
|
||||
void sendToAllAround(NetworkMessage<ClientNetworkContext> message, ServerLevel level, Vec3 pos, float distance);
|
||||
|
||||
/**
|
||||
* Send a message to all players tracking a chunk.
|
||||
*
|
||||
* @param message The message to send.
|
||||
* @param chunk The chunk players must be tracking.
|
||||
*/
|
||||
void sendToAllTracking(NetworkMessage<ClientNetworkContext> message, LevelChunk chunk);
|
||||
Packet<ClientGamePacketListener> createPacket(NetworkMessage<ClientNetworkContext> message);
|
||||
|
||||
/**
|
||||
* Create a {@link ComponentAccess} for surrounding peripherals.
|
||||
|
@ -15,7 +15,7 @@ import dan200.computercraft.shared.computer.core.ServerComputer;
|
||||
import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.network.client.PocketComputerDataMessage;
|
||||
import dan200.computercraft.shared.network.client.PocketComputerDeletedClientMessage;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
@ -161,7 +161,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
|
||||
if (sendState) {
|
||||
// Broadcast the state to all players
|
||||
tracking.addAll(getLevel().players());
|
||||
PlatformHelper.get().sendToPlayers(new PocketComputerDataMessage(this, false), tracking);
|
||||
ServerNetworking.sendToPlayers(new PocketComputerDataMessage(this, false), tracking);
|
||||
} else {
|
||||
// Broadcast the state to new players.
|
||||
List<ServerPlayer> added = new ArrayList<>();
|
||||
@ -169,7 +169,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
|
||||
if (tracking.add(player)) added.add(player);
|
||||
}
|
||||
if (!added.isEmpty()) {
|
||||
PlatformHelper.get().sendToPlayers(new PocketComputerDataMessage(this, false), added);
|
||||
ServerNetworking.sendToPlayers(new PocketComputerDataMessage(this, false), added);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -180,13 +180,13 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces
|
||||
|
||||
if (entity instanceof ServerPlayer player && entity.isAlive()) {
|
||||
// Broadcast the terminal to the current player.
|
||||
PlatformHelper.get().sendToPlayer(new PocketComputerDataMessage(this, true), player);
|
||||
ServerNetworking.sendToPlayer(new PocketComputerDataMessage(this, true), player);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRemoved() {
|
||||
super.onRemoved();
|
||||
PlatformHelper.get().sendToAllPlayers(new PocketComputerDeletedClientMessage(getInstanceID()), getLevel().getServer());
|
||||
ServerNetworking.sendToAllPlayers(new PocketComputerDeletedClientMessage(getInstanceID()), getLevel().getServer());
|
||||
}
|
||||
}
|
||||
|
@ -18,15 +18,18 @@ import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
||||
import dan200.computercraft.shared.network.container.ContainerData;
|
||||
import dan200.computercraft.shared.platform.*;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.tags.TagKey;
|
||||
@ -47,12 +50,10 @@ import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
@ -129,31 +130,6 @@ public class TestPlatformHelper extends AbstractComputerCraftAPI implements Plat
|
||||
throw new UnsupportedOperationException("Cannot register ArgumentTypeInfo inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToPlayer(NetworkMessage<ClientNetworkContext> message, ServerPlayer player) {
|
||||
throw new UnsupportedOperationException("Cannot send NetworkMessages inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToPlayers(NetworkMessage<ClientNetworkContext> message, Collection<ServerPlayer> players) {
|
||||
throw new UnsupportedOperationException("Cannot send NetworkMessages inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToAllPlayers(NetworkMessage<ClientNetworkContext> message, MinecraftServer server) {
|
||||
throw new UnsupportedOperationException("Cannot send NetworkMessages inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToAllAround(NetworkMessage<ClientNetworkContext> message, ServerLevel level, Vec3 pos, float distance) {
|
||||
throw new UnsupportedOperationException("Cannot send NetworkMessages inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToAllTracking(NetworkMessage<ClientNetworkContext> message, LevelChunk chunk) {
|
||||
throw new UnsupportedOperationException("Cannot send NetworkMessages inside tests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TagKey<Item>> getDyeTags() {
|
||||
throw new UnsupportedOperationException("Cannot query tags inside tests");
|
||||
@ -169,11 +145,21 @@ public class TestPlatformHelper extends AbstractComputerCraftAPI implements Plat
|
||||
throw new UnsupportedOperationException("Cannot open menu inside tests");
|
||||
}
|
||||
|
||||
record TypeImpl<T extends NetworkMessage<?>>(
|
||||
ResourceLocation id, Function<FriendlyByteBuf, T> reader
|
||||
) implements MessageType<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends NetworkMessage<?>> MessageType<T> createMessageType(int id, ResourceLocation channel, Class<T> klass, FriendlyByteBuf.Reader<T> reader) {
|
||||
record TypeImpl<T extends NetworkMessage<?>>(Function<FriendlyByteBuf, T> reader) implements MessageType<T> {
|
||||
return new TypeImpl<>(channel, reader);
|
||||
}
|
||||
return new TypeImpl<>(reader);
|
||||
|
||||
@Override
|
||||
public Packet<ClientGamePacketListener> createPacket(NetworkMessage<ClientNetworkContext> message) {
|
||||
var buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
message.write(buf);
|
||||
return new ClientboundCustomPayloadPacket(((TypeImpl<?>) message.type()).id(), buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -4,9 +4,10 @@
|
||||
|
||||
package dan200.computercraft.client.sound;
|
||||
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class DfpwmStreamTest {
|
||||
@ -14,8 +15,7 @@ public class DfpwmStreamTest {
|
||||
public void testDecodesBytes() {
|
||||
var stream = new DfpwmStream();
|
||||
|
||||
var input = ByteBufAllocator.DEFAULT.buffer();
|
||||
input.writeBytes(new byte[]{ 43, -31, 33, 44, 30, -16, -85, 23, -3, -55, 46, -70, 68, -67, 74, -96, -68, 16, 94, -87, -5, 87, 11, -16, 19, 92, 85, -71, 126, 5, -84, 64, 17, -6, 85, -11, -1, -87, -12, 1, 85, -56, 33, -80, 82, 104, -93, 17, 126, 23, 91, -30, 37, -32, 117, -72, -58, 11, -76, 19, -108, 86, -65, -10, -1, -68, -25, 10, -46, 85, 124, -54, 15, -24, 43, -94, 117, 63, -36, 15, -6, 88, 87, -26, -83, 106, 41, 13, -28, -113, -10, -66, 119, -87, -113, 68, -55, 40, -107, 62, 20, 72, 3, -96, 114, -87, -2, 39, -104, 30, 20, 42, 84, 24, 47, 64, 43, 61, -35, 95, -65, 42, 61, 42, -50, 4, -9, 81 });
|
||||
var input = ByteBuffer.wrap(new byte[]{ 43, -31, 33, 44, 30, -16, -85, 23, -3, -55, 46, -70, 68, -67, 74, -96, -68, 16, 94, -87, -5, 87, 11, -16, 19, 92, 85, -71, 126, 5, -84, 64, 17, -6, 85, -11, -1, -87, -12, 1, 85, -56, 33, -80, 82, 104, -93, 17, 126, 23, 91, -30, 37, -32, 117, -72, -58, 11, -76, 19, -108, 86, -65, -10, -1, -68, -25, 10, -46, 85, 124, -54, 15, -24, 43, -94, 117, 63, -36, 15, -6, 88, 87, -26, -83, 106, 41, 13, -28, -113, -10, -66, 119, -87, -113, 68, -55, 40, -107, 62, 20, 72, 3, -96, 114, -87, -2, 39, -104, 30, 20, 42, 84, 24, 47, 64, 43, 61, -35, 95, -65, 42, 61, 42, -50, 4, -9, 81 });
|
||||
stream.push(input);
|
||||
|
||||
var buffer = stream.read(1024 + 1);
|
||||
|
@ -6,6 +6,7 @@ package dan200.computercraft.client;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.client.model.CustomModelLoader;
|
||||
import dan200.computercraft.impl.Services;
|
||||
import dan200.computercraft.shared.ModRegistry;
|
||||
import dan200.computercraft.shared.config.ConfigSpec;
|
||||
import dan200.computercraft.shared.network.NetworkMessages;
|
||||
@ -31,9 +32,10 @@ import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
||||
|
||||
public class ComputerCraftClient {
|
||||
public static void init() {
|
||||
var clientNetwork = Services.load(ClientNetworkContext.class);
|
||||
for (var type : NetworkMessages.getClientbound()) {
|
||||
ClientPlayNetworking.registerGlobalReceiver(
|
||||
FabricMessageType.toFabricType(type), (packet, player, responseSender) -> packet.payload().handle(ClientNetworkContext.get())
|
||||
FabricMessageType.toFabricType(type), (packet, player, responseSender) -> packet.payload().handle(clientNetwork)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,24 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.client.platform;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@AutoService(ClientNetworkContext.class)
|
||||
public class ClientNetworkHandlerImpl extends AbstractClientNetworkContext {
|
||||
@Override
|
||||
public void handlePlayRecord(BlockPos pos, @Nullable SoundEvent sound, @Nullable String name) {
|
||||
var mc = Minecraft.getInstance();
|
||||
mc.levelRenderer.playStreamingMusic(sound, pos);
|
||||
if (name != null) mc.gui.setNowPlaying(Component.literal(name));
|
||||
}
|
||||
}
|
@ -12,13 +12,19 @@ import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworkContext;
|
||||
import dan200.computercraft.shared.platform.FabricMessageType;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
|
||||
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
|
||||
import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.Sheets;
|
||||
import net.minecraft.client.renderer.entity.ItemRenderer;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ServerGamePacketListener;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.util.RandomSource;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@ -28,8 +34,10 @@ public class ClientPlatformHelperImpl implements ClientPlatformHelper {
|
||||
private static final RandomSource random = RandomSource.create(0);
|
||||
|
||||
@Override
|
||||
public void sendToServer(NetworkMessage<ServerNetworkContext> message) {
|
||||
ClientPlayNetworking.send(FabricMessageType.toFabricPacket(message));
|
||||
public Packet<ServerGamePacketListener> createPacket(NetworkMessage<ServerNetworkContext> message) {
|
||||
var buf = PacketByteBufs.create();
|
||||
message.write(buf);
|
||||
return ClientPlayNetworking.createC2SPacket(FabricMessageType.toFabricType(message.type()).getId(), buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -55,4 +63,9 @@ public class ClientPlatformHelperImpl implements ClientPlatformHelper {
|
||||
ModelRenderer.renderQuads(transform, buffer, model.getQuads(null, face, random), lightmapCoord, overlayLight, tints);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playStreamingMusic(BlockPos pos, @Nullable SoundEvent sound) {
|
||||
Minecraft.getInstance().levelRenderer.playStreamingMusic(sound, pos);
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import dan200.computercraft.shared.config.ConfigSpec;
|
||||
import dan200.computercraft.shared.details.FluidDetails;
|
||||
import dan200.computercraft.shared.network.NetworkMessages;
|
||||
import dan200.computercraft.shared.network.client.UpgradesLoadedMessage;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral;
|
||||
import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableBlockEntity;
|
||||
@ -22,7 +23,6 @@ import dan200.computercraft.shared.peripheral.modem.wired.WiredModemFullBlockEnt
|
||||
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemBlockEntity;
|
||||
import dan200.computercraft.shared.platform.FabricConfigFile;
|
||||
import dan200.computercraft.shared.platform.FabricMessageType;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||
@ -92,7 +92,7 @@ public class ComputerCraft {
|
||||
CommonHooks.onServerStopped();
|
||||
((FabricConfigFile) ConfigSpec.serverSpec).unload();
|
||||
});
|
||||
ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS.register((player, joined) -> PlatformHelper.get().sendToPlayer(new UpgradesLoadedMessage(), player));
|
||||
ServerLifecycleEvents.SYNC_DATA_PACK_CONTENTS.register((player, joined) -> ServerNetworking.sendToPlayer(new UpgradesLoadedMessage(), player));
|
||||
|
||||
ServerTickEvents.START_SERVER_TICK.register(CommonHooks::onServerTickStart);
|
||||
ServerTickEvents.START_SERVER_TICK.register(s -> CommonHooks.onServerTickEnd());
|
||||
|
@ -51,8 +51,6 @@ import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.tags.ItemTags;
|
||||
@ -77,13 +75,15 @@ import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.EntityHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.*;
|
||||
|
||||
@AutoService(dan200.computercraft.impl.PlatformHelper.class)
|
||||
@ -177,42 +177,13 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
return new FabricMessageType<>(channel, reader);
|
||||
}
|
||||
|
||||
private Packet<ClientGamePacketListener> encodeClientbound(NetworkMessage<ClientNetworkContext> message) {
|
||||
@Override
|
||||
public Packet<ClientGamePacketListener> createPacket(NetworkMessage<ClientNetworkContext> message) {
|
||||
var buf = PacketByteBufs.create();
|
||||
message.write(buf);
|
||||
return ServerPlayNetworking.createS2CPacket(FabricMessageType.toFabricType(message.type()).getId(), buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToPlayer(NetworkMessage<ClientNetworkContext> message, ServerPlayer player) {
|
||||
player.connection.send(encodeClientbound(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToPlayers(NetworkMessage<ClientNetworkContext> message, Collection<ServerPlayer> players) {
|
||||
if (players.isEmpty()) return;
|
||||
var packet = encodeClientbound(message);
|
||||
for (var player : players) player.connection.send(packet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToAllPlayers(NetworkMessage<ClientNetworkContext> message, MinecraftServer server) {
|
||||
server.getPlayerList().broadcastAll(encodeClientbound(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToAllAround(NetworkMessage<ClientNetworkContext> message, ServerLevel level, Vec3 pos, float distance) {
|
||||
level.getServer().getPlayerList().broadcast(null, pos.x, pos.y, pos.z, distance, level.dimension(), encodeClientbound(message));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToAllTracking(NetworkMessage<ClientNetworkContext> message, LevelChunk chunk) {
|
||||
var packet = encodeClientbound(message);
|
||||
for (var player : ((ServerChunkCache) chunk.getLevel().getChunkSource()).chunkMap.getPlayers(chunk.getPos(), false)) {
|
||||
player.connection.send(packet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComponentAccess<IPeripheral> createPeripheralAccess(BlockEntity owner, Consumer<Direction> invalidate) {
|
||||
return new PeripheralAccessImpl(owner, invalidate);
|
||||
|
@ -1,24 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.client.platform;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@AutoService(ClientNetworkContext.class)
|
||||
public class ClientNetworkContextImpl extends AbstractClientNetworkContext {
|
||||
@Override
|
||||
public void handlePlayRecord(BlockPos pos, @Nullable SoundEvent sound, @Nullable String name) {
|
||||
var mc = Minecraft.getInstance();
|
||||
mc.levelRenderer.playStreamingMusic(sound, pos, null);
|
||||
if (name != null) mc.gui.setNowPlaying(Component.literal(name));
|
||||
}
|
||||
}
|
@ -11,11 +11,16 @@ import dan200.computercraft.client.render.ModelRenderer;
|
||||
import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworkContext;
|
||||
import dan200.computercraft.shared.platform.NetworkHandler;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.resources.model.BakedModel;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ServerGamePacketListener;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.client.model.data.ModelData;
|
||||
@ -39,8 +44,8 @@ public class ClientPlatformHelperImpl implements ClientPlatformHelper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToServer(NetworkMessage<ServerNetworkContext> message) {
|
||||
NetworkHandler.sendToServer(message);
|
||||
public Packet<ServerGamePacketListener> createPacket(NetworkMessage<ServerNetworkContext> message) {
|
||||
return NetworkHandler.createServerboundPacket(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -54,4 +59,9 @@ public class ClientPlatformHelperImpl implements ClientPlatformHelper {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playStreamingMusic(BlockPos pos, @Nullable SoundEvent sound) {
|
||||
Minecraft.getInstance().levelRenderer.playStreamingMusic(sound, pos, null);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import dan200.computercraft.shared.command.CommandComputerCraft;
|
||||
import dan200.computercraft.shared.computer.blocks.ComputerBlockEntity;
|
||||
import dan200.computercraft.shared.config.Config;
|
||||
import dan200.computercraft.shared.network.client.UpgradesLoadedMessage;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworking;
|
||||
import dan200.computercraft.shared.peripheral.commandblock.CommandBlockPeripheral;
|
||||
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.modem.wired.CableBlockEntity;
|
||||
@ -17,7 +18,6 @@ import dan200.computercraft.shared.peripheral.modem.wireless.WirelessModemBlockE
|
||||
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.printer.PrinterBlockEntity;
|
||||
import dan200.computercraft.shared.peripheral.speaker.SpeakerBlockEntity;
|
||||
import dan200.computercraft.shared.platform.PlatformHelper;
|
||||
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
|
||||
import dan200.computercraft.shared.util.CapabilityProvider;
|
||||
import dan200.computercraft.shared.util.SidedCapabilityProvider;
|
||||
@ -81,9 +81,9 @@ public class ForgeCommonHooks {
|
||||
public static void onDatapackSync(OnDatapackSyncEvent event) {
|
||||
var packet = new UpgradesLoadedMessage();
|
||||
if (event.getPlayer() == null) {
|
||||
PlatformHelper.get().sendToAllPlayers(packet, event.getPlayerList().getServer());
|
||||
ServerNetworking.sendToAllPlayers(packet, event.getPlayerList().getServer());
|
||||
} else {
|
||||
PlatformHelper.get().sendToPlayer(packet, event.getPlayer());
|
||||
ServerNetworking.sendToPlayer(packet, event.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,26 +5,25 @@
|
||||
package dan200.computercraft.shared.platform;
|
||||
|
||||
import dan200.computercraft.api.ComputerCraftAPI;
|
||||
import dan200.computercraft.impl.Services;
|
||||
import dan200.computercraft.shared.network.MessageType;
|
||||
import dan200.computercraft.shared.network.NetworkMessage;
|
||||
import dan200.computercraft.shared.network.NetworkMessages;
|
||||
import dan200.computercraft.shared.network.client.ClientNetworkContext;
|
||||
import dan200.computercraft.shared.network.server.ServerNetworkContext;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.network.protocol.game.ServerGamePacketListener;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.network.NetworkDirection;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import net.minecraftforge.network.NetworkRegistry;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
import net.minecraftforge.network.simple.SimpleChannel;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static dan200.computercraft.core.util.Nullability.assertNonNull;
|
||||
@ -53,36 +52,18 @@ public final class NetworkHandler {
|
||||
|
||||
for (var type : NetworkMessages.getClientbound()) {
|
||||
var forgeType = (MessageTypeImpl<? extends NetworkMessage<ClientNetworkContext>>) type;
|
||||
registerMainThread(forgeType, NetworkDirection.PLAY_TO_CLIENT, x -> ClientNetworkContext.get());
|
||||
registerMainThread(forgeType, NetworkDirection.PLAY_TO_CLIENT, x -> ClientHolder.get());
|
||||
}
|
||||
}
|
||||
|
||||
static void sendToPlayer(NetworkMessage<ClientNetworkContext> packet, ServerPlayer player) {
|
||||
network.sendTo(packet, player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Packet<ClientGamePacketListener> createClientboundPacket(NetworkMessage<ClientNetworkContext> packet) {
|
||||
return (Packet<ClientGamePacketListener>) network.toVanillaPacket(packet, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
|
||||
static void sendToPlayers(NetworkMessage<ClientNetworkContext> packet, Collection<ServerPlayer> players) {
|
||||
if (players.isEmpty()) return;
|
||||
|
||||
var vanillaPacket = network.toVanillaPacket(packet, NetworkDirection.PLAY_TO_CLIENT);
|
||||
for (var player : players) player.connection.send(vanillaPacket);
|
||||
}
|
||||
|
||||
static void sendToAllPlayers(NetworkMessage<ClientNetworkContext> packet) {
|
||||
network.send(PacketDistributor.ALL.noArg(), packet);
|
||||
}
|
||||
|
||||
static void sendToAllAround(NetworkMessage<ClientNetworkContext> packet, Level world, Vec3 pos, double range) {
|
||||
var target = new PacketDistributor.TargetPoint(pos.x, pos.y, pos.z, range, world.dimension());
|
||||
network.send(PacketDistributor.NEAR.with(() -> target), packet);
|
||||
}
|
||||
|
||||
static void sendToAllTracking(NetworkMessage<ClientNetworkContext> packet, LevelChunk chunk) {
|
||||
network.send(PacketDistributor.TRACKING_CHUNK.with(() -> chunk), packet);
|
||||
}
|
||||
|
||||
public static void sendToServer(NetworkMessage<ServerNetworkContext> packet) {
|
||||
network.sendToServer(packet);
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Packet<ServerGamePacketListener> createServerboundPacket(NetworkMessage<ServerNetworkContext> packet) {
|
||||
return (Packet<ServerGamePacketListener>) network.toVanillaPacket(packet, NetworkDirection.PLAY_TO_SERVER);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -115,4 +96,24 @@ public final class NetworkHandler {
|
||||
int id, Class<T> klass, Function<FriendlyByteBuf, T> reader
|
||||
) implements MessageType<T> {
|
||||
}
|
||||
|
||||
/**
|
||||
* This holds an instance of {@link ClientNetworkContext}. This is a separate class to ensure that the instance is
|
||||
* lazily created when needed on the client.
|
||||
*/
|
||||
private static final class ClientHolder {
|
||||
private static final @Nullable ClientNetworkContext INSTANCE;
|
||||
private static final @Nullable Throwable ERROR;
|
||||
|
||||
static {
|
||||
var helper = Services.tryLoad(ClientNetworkContext.class);
|
||||
INSTANCE = helper.instance();
|
||||
ERROR = helper.error();
|
||||
}
|
||||
|
||||
static ClientNetworkContext get() {
|
||||
var instance = INSTANCE;
|
||||
return instance == null ? Services.raise(ClientNetworkContext.class, ERROR) : instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,9 +28,10 @@ import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.tags.TagKey;
|
||||
@ -52,7 +53,6 @@ import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.common.ForgeHooks;
|
||||
@ -164,28 +164,8 @@ public class PlatformHelperImpl implements PlatformHelper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToPlayer(NetworkMessage<ClientNetworkContext> message, ServerPlayer player) {
|
||||
NetworkHandler.sendToPlayer(message, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToPlayers(NetworkMessage<ClientNetworkContext> message, Collection<ServerPlayer> players) {
|
||||
NetworkHandler.sendToPlayers(message, players);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToAllPlayers(NetworkMessage<ClientNetworkContext> message, MinecraftServer server) {
|
||||
NetworkHandler.sendToAllPlayers(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToAllAround(NetworkMessage<ClientNetworkContext> message, ServerLevel level, Vec3 pos, float distance) {
|
||||
NetworkHandler.sendToAllAround(message, level, pos, distance);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendToAllTracking(NetworkMessage<ClientNetworkContext> message, LevelChunk chunk) {
|
||||
NetworkHandler.sendToAllTracking(message, chunk);
|
||||
public Packet<ClientGamePacketListener> createPacket(NetworkMessage<ClientNetworkContext> message) {
|
||||
return NetworkHandler.createClientboundPacket(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user