This commit is contained in:
Todd 2024-02-26 22:17:31 +01:00 committed by GitHub
commit b7619975b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 255 additions and 49 deletions

View File

@ -22,6 +22,7 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
@ -161,6 +162,17 @@ public static PacketNetwork getWirelessNetwork(MinecraftServer server) {
return getInstance().getWirelessNetwork(server);
}
/**
* Attempt to get the NFC network for a player.
*
* @param server The current Minecraft server.
* @param entity The entity whose NFC network should be obtained.
* @return The NFC network, or {@code null} if it could not be fetched.
*/
public static PacketNetwork getNfcNetwork(MinecraftServer server, Entity entity) {
return getInstance().getNfcNetwork(server, entity);
}
/**
* Register a custom {@link ILuaAPI}, which may be added onto all computers without requiring a peripheral.
* <p>

View File

@ -53,4 +53,19 @@ public interface PacketNetwork {
* @see PacketReceiver#receiveDifferentDimension(Packet)
*/
void transmitInterdimensional(Packet packet);
static void tryTransmit(PacketReceiver receiver, Packet packet, double range, boolean interdimensional) {
var sender = packet.sender();
if (receiver.getLevel() == sender.getLevel()) {
var receiveRange = Math.max(range, receiver.getRange()); // Ensure range is symmetrical
var distanceSq = receiver.getPosition().distanceToSqr(sender.getPosition());
if (interdimensional || receiver.isInterdimensional() || distanceSq <= receiveRange * receiveRange) {
receiver.receiveSameDimension(packet, Math.sqrt(distanceSq));
}
} else {
if (interdimensional || receiver.isInterdimensional()) {
receiver.receiveDifferentDimension(packet);
}
}
}
}

View File

@ -47,22 +47,40 @@ public interface IPocketAccess {
void setColour(int colour);
/**
* Get the colour of this pocket computer's light as a RGB number.
* Get the primary colour of this pocket computer's light as a RGB number.
*
* @return The colour this light is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or
* @return The primary colour this light is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or
* -1 if it has no colour.
* @see #setLight(int)
* @see #setLightPrimary(int)
*/
int getLight();
int getLightPrimary();
/**
* Set the colour of the pocket computer's light to a RGB number.
* Set the primary colour of the pocket computer's light to a RGB number.
*
* @param colour The colour this modem's light will be changed to. This should be a RGB colour between
* @param colour The primary colour this modem's light will be changed to. This should be a RGB colour between
* {@code 0x000000} and {@code 0xFFFFFF} or -1 to reset to the default colour.
* @see #getLight()
* @see #getLightPrimary()
*/
void setLight(int colour);
void setLightPrimary(int colour);
/**
* Get the secondary colour of this pocket computer's light as a RGB number.
*
* @return The secondary colour this light is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or
* -1 if it has no colour.
* @see #setLightSecondary(int)
*/
int getLightSecondary();
/**
* Set the secondary colour of the pocket computer's light to a RGB number.
*
* @param colour The secondary colour this modem's light will be changed to. This should be a RGB colour between
* {@code 0x000000} and {@code 0xFFFFFF} or -1 to reset to the default colour.
* @see #getLightSecondary()
*/
void setLightSecondary(int colour);
/**
* Get the upgrade-specific NBT.

View File

@ -24,6 +24,7 @@
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.ApiStatus;
@ -61,6 +62,8 @@ static ComputerCraftAPIService get() {
PacketNetwork getWirelessNetwork(MinecraftServer server);
PacketNetwork getNfcNetwork(MinecraftServer server, Entity entity);
void registerAPIFactory(ILuaAPIFactory factory);
WiredNode createWiredNodeForElement(WiredElement element);

View File

@ -24,6 +24,10 @@ public static long getRenderFrame() {
return renderFrame;
}
public static int getTick() {
return tick;
}
public static void onTick() {
tick++;
}

View File

@ -67,9 +67,9 @@ public void handlePlayRecord(BlockPos pos, @Nullable SoundEvent sound, @Nullable
}
@Override
public void handlePocketComputerData(int instanceId, ComputerState state, int lightState, TerminalState terminal) {
public void handlePocketComputerData(int instanceId, ComputerState state, int primaryLightState, int secondaryLightState, TerminalState terminal) {
var computer = ClientPocketComputers.get(instanceId, terminal.colour);
computer.setState(state, lightState);
computer.setState(state, primaryLightState, secondaryLightState);
if (terminal.hasTerminal()) computer.setTerminal(terminal);
}

View File

@ -4,6 +4,7 @@
package dan200.computercraft.client.pocket;
import dan200.computercraft.client.FrameInfo;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.shared.computer.core.ComputerState;
import dan200.computercraft.shared.computer.terminal.NetworkedTerminal;
@ -24,14 +25,42 @@
public class PocketComputerData {
private final NetworkedTerminal terminal;
private ComputerState state = ComputerState.OFF;
private int lightColour = -1;
private int primaryLightColour = -1;
private int secondaryLightColour = -1;
public PocketComputerData(boolean colour) {
terminal = new NetworkedTerminal(Config.pocketTermWidth, Config.pocketTermHeight, colour);
}
public int getLightState() {
return state != ComputerState.OFF ? lightColour : -1;
if (state != ComputerState.OFF) {
if (secondaryLightColour == -1) {
return primaryLightColour;
} else if (primaryLightColour == -1) {
return secondaryLightColour;
} else {
double weight = (Math.sin(((double)(FrameInfo.getTick() % 41) / 40) * Math.PI * 2) + 1) / 2;
return blend(primaryLightColour, secondaryLightColour, weight);
}
}
return -1;
}
private static int blend(int a, int b, double weight) {
int[][] rgb = {
{ a >> 16, b >> 16 },
{ (a & 0x00ff00) >> 8, (b & 0x00ff00) >> 8 },
{ a & 0x0000ff, b & 0x0000ff },
};
int[] channels = new int[3];
for (int i = 0; i < 3; i++) {
channels[i] = (int)Math.sqrt(Math.pow(rgb[i][0], 2) * weight + Math.pow(rgb[i][1], 2) * (1 - weight));
}
int color = 0;
for (int channel : channels) {
color = (color << 8) + channel;
}
return color;
}
public Terminal getTerminal() {
@ -42,9 +71,10 @@ public ComputerState getState() {
return state;
}
public void setState(ComputerState state, int lightColour) {
public void setState(ComputerState state, int primaryLightColour, int secondaryLightColor) {
this.state = state;
this.lightColour = lightColour;
this.primaryLightColour = primaryLightColour;
this.secondaryLightColour = secondaryLightColor;
}
public void setTerminal(TerminalState state) {

View File

@ -32,6 +32,7 @@
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
@ -100,6 +101,11 @@ public final PacketNetwork getWirelessNetwork(MinecraftServer server) {
return ServerContext.get(server).wirelessNetwork();
}
@Override
public final PacketNetwork getNfcNetwork(MinecraftServer server, Entity entity) {
return ServerContext.get(server).nfcNetwork(entity);
}
@Override
public final void registerAPIFactory(ILuaAPIFactory factory) {
ApiFactories.register(factory);

View File

@ -22,10 +22,12 @@
import dan200.computercraft.shared.CommonHooks;
import dan200.computercraft.shared.computer.metrics.GlobalMetrics;
import dan200.computercraft.shared.config.ConfigSpec;
import dan200.computercraft.shared.peripheral.modem.wireless.NFCNetworkManager;
import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork;
import dan200.computercraft.shared.util.IDAssigner;
import net.minecraft.SharedConstants;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.storage.LevelResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -64,6 +66,7 @@ public final class ServerContext {
private final MainThread mainThread;
private final IDAssigner idAssigner;
private final WirelessNetwork wirelessNetwork = new WirelessNetwork();
private final NFCNetworkManager nfcNetworkManager = new NFCNetworkManager();
private final Path storageDir;
private ServerContext(MinecraftServer server) {
@ -209,6 +212,18 @@ public PacketNetwork wirelessNetwork() {
return wirelessNetwork;
}
/**
* Get a player's NFC network.
* <p>
* Use {@link ComputerCraftAPI#getNfcNetwork(MinecraftServer, Entity)} instead of this method.
* @param entity The entity whose NFC network should be obtained.
* @return The NFC network.
*/
public PacketNetwork nfcNetwork(Entity entity) {
PacketNetwork network = nfcNetworkManager.get(entity);
return network == null ? nfcNetworkManager.addNetwork(entity) : network;
}
private record Environment(MinecraftServer server) implements GlobalEnvironment {
@Override
public @Nullable Mount createResourceMount(String domain, String subPath) {

View File

@ -30,7 +30,7 @@ public interface ClientNetworkContext {
void handlePlayRecord(BlockPos pos, @Nullable SoundEvent sound, @Nullable String name);
void handlePocketComputerData(int instanceId, ComputerState state, int lightState, TerminalState terminal);
void handlePocketComputerData(int instanceId, ComputerState state, int primaryLightColor, int secondaryLightColor, TerminalState terminal);
void handlePocketComputerDeleted(int instanceId);

View File

@ -19,20 +19,23 @@
public class PocketComputerDataMessage implements NetworkMessage<ClientNetworkContext> {
private final int instanceId;
private final ComputerState state;
private final int lightState;
private final int primaryLightState;
private final int secondaryLightState;
private final TerminalState terminal;
public PocketComputerDataMessage(PocketServerComputer computer, boolean sendTerminal) {
instanceId = computer.getInstanceID();
state = computer.getState();
lightState = computer.getLight();
primaryLightState = computer.getLightPrimary();
secondaryLightState = computer.getLightSecondary();
terminal = sendTerminal ? computer.getTerminalState() : new TerminalState((NetworkedTerminal) null);
}
public PocketComputerDataMessage(FriendlyByteBuf buf) {
instanceId = buf.readVarInt();
state = buf.readEnum(ComputerState.class);
lightState = buf.readVarInt();
primaryLightState = buf.readVarInt();
secondaryLightState = buf.readVarInt();
terminal = new TerminalState(buf);
}
@ -40,13 +43,14 @@ public PocketComputerDataMessage(FriendlyByteBuf buf) {
public void write(FriendlyByteBuf buf) {
buf.writeVarInt(instanceId);
buf.writeEnum(state);
buf.writeVarInt(lightState);
buf.writeVarInt(primaryLightState);
buf.writeVarInt(secondaryLightState);
terminal.write(buf);
}
@Override
public void handle(ClientNetworkContext context) {
context.handlePocketComputerData(instanceId, state, lightState, terminal);
context.handlePocketComputerData(instanceId, state, primaryLightState, secondaryLightState, terminal);
}
@Override

View File

@ -0,0 +1,30 @@
// SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.shared.peripheral.modem.wireless;
import net.minecraft.world.entity.Entity;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class NFCNetworkManager {
private final Map<Entity, WirelessNetwork> networks = new ConcurrentHashMap<>();
public WirelessNetwork addNetwork(Entity entity) {
if (!networks.containsKey(entity)) {
networks.put(entity, new WirelessNetwork(() -> networks.remove(entity)));
}
return networks.get(entity);
}
public void removeNetwork(Entity entity) {
networks.remove(entity);
}
public @Nullable WirelessNetwork get(Entity entity) {
return networks.get(entity);
}
}

View File

@ -8,6 +8,7 @@
import dan200.computercraft.api.network.PacketNetwork;
import dan200.computercraft.api.network.PacketReceiver;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
@ -15,6 +16,15 @@
public class WirelessNetwork implements PacketNetwork {
private final Set<PacketReceiver> receivers = Collections.newSetFromMap(new ConcurrentHashMap<>());
private final @Nullable Runnable onEmpty;
public WirelessNetwork() {
onEmpty = null;
}
public WirelessNetwork(Runnable onEmpty) {
this.onEmpty = onEmpty;
}
@Override
public void addReceiver(PacketReceiver receiver) {
@ -26,33 +36,19 @@ public void addReceiver(PacketReceiver receiver) {
public void removeReceiver(PacketReceiver receiver) {
Objects.requireNonNull(receiver, "device cannot be null");
receivers.remove(receiver);
if (receivers.isEmpty() && onEmpty != null) onEmpty.run();
}
@Override
public void transmitSameDimension(Packet packet, double range) {
Objects.requireNonNull(packet, "packet cannot be null");
for (var device : receivers) tryTransmit(device, packet, range, false);
for (var device : receivers) PacketNetwork.tryTransmit(device, packet, range, false);
}
@Override
public void transmitInterdimensional(Packet packet) {
Objects.requireNonNull(packet, "packet cannot be null");
for (var device : receivers) tryTransmit(device, packet, 0, true);
}
private static void tryTransmit(PacketReceiver receiver, Packet packet, double range, boolean interdimensional) {
var sender = packet.sender();
if (receiver.getLevel() == sender.getLevel()) {
var receiveRange = Math.max(range, receiver.getRange()); // Ensure range is symmetrical
var distanceSq = receiver.getPosition().distanceToSqr(sender.getPosition());
if (interdimensional || receiver.isInterdimensional() || distanceSq <= receiveRange * receiveRange) {
receiver.receiveSameDimension(packet, Math.sqrt(distanceSq));
}
} else {
if (interdimensional || receiver.isInterdimensional()) {
receiver.receiveDifferentDimension(packet);
}
}
for (var device : receivers) PacketNetwork.tryTransmit(device, packet, 0, true);
}
@Override

View File

@ -17,6 +17,7 @@
import dan200.computercraft.shared.network.client.PocketComputerDeletedClientMessage;
import dan200.computercraft.shared.network.server.ServerNetworking;
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
import dan200.computercraft.shared.pocket.peripherals.PocketNFCPeripheral;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
@ -33,11 +34,14 @@
public class PocketServerComputer extends ServerComputer implements IPocketAccess {
private @Nullable IPocketUpgrade upgrade;
private final PocketNFCPeripheral nfc = new PocketNFCPeripheral(this);
private @Nullable Entity entity;
private ItemStack stack = ItemStack.EMPTY;
private int lightColour = -1;
private boolean lightChanged = false;
private int primaryLightColour = -1;
private boolean primaryLightChanged = false;
private int secondaryLightColour = -1;
private boolean secondaryLightChanged = false;
private final Set<ServerPlayer> tracking = new HashSet<>();
@ -75,17 +79,31 @@ public void setColour(int colour) {
}
@Override
public int getLight() {
return lightColour;
public int getLightPrimary() {
return primaryLightColour;
}
@Override
public void setLight(int colour) {
public void setLightPrimary(int colour) {
if (colour < 0 || colour > 0xFFFFFF) colour = -1;
if (lightColour == colour) return;
lightColour = colour;
lightChanged = true;
if (primaryLightColour == colour) return;
primaryLightColour = colour;
primaryLightChanged = true;
}
@Override
public int getLightSecondary() {
return secondaryLightColour;
}
@Override
public void setLightSecondary(int colour) {
if (colour < 0 || colour > 0xFFFFFF) colour = -1;
if (secondaryLightColour == colour) return;
secondaryLightColour = colour;
secondaryLightChanged = true;
}
@Override
@ -142,6 +160,9 @@ public synchronized void updateValues(@Nullable Entity entity, ItemStack stack,
this.entity = entity;
this.stack = stack;
nfc.update(this);
if (getPeripheral(ComputerSide.TOP) != nfc) setPeripheral(ComputerSide.TOP, nfc);
if (this.upgrade != upgrade) {
this.upgrade = upgrade;
invalidatePeripheral();
@ -156,8 +177,9 @@ public void tickServer() {
tracking.removeIf(player -> !player.isAlive() || player.level() != getLevel());
// And now find any new players, add them to the tracking list, and broadcast state where appropriate.
var sendState = hasOutputChanged() || lightChanged;
lightChanged = false;
var sendState = hasOutputChanged() || primaryLightChanged || secondaryLightChanged;
primaryLightChanged = false;
secondaryLightChanged = false;
if (sendState) {
// Broadcast the state to all players
tracking.addAll(getLevel().players());

View File

@ -34,6 +34,6 @@ public void update(IPocketAccess access, @Nullable IPeripheral peripheral) {
modem.setLocation(access);
var state = modem.getModemState();
if (state.pollChanged()) access.setLight(state.isOpen() ? 0xBA0000 : -1);
if (state.pollChanged()) access.setLightPrimary(state.isOpen() ? 0xBA0000 : -1);
}
}

View File

@ -0,0 +1,51 @@
// SPDX-FileCopyrightText: 2017 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.shared.pocket.peripherals;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.network.PacketNetwork;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.pocket.IPocketAccess;
import dan200.computercraft.core.util.Nullability;
import net.minecraft.world.entity.Entity;
import javax.annotation.Nullable;
public class PocketNFCPeripheral extends PocketModemPeripheral {
private @Nullable Entity entity = null;
public PocketNFCPeripheral(IPocketAccess access) {
super(false, access);
}
public void update(IPocketAccess access) {
setLocation(access);
var state = getModemState();
if (state.pollChanged()) access.setLightSecondary(state.isOpen() ? 0xf39d20 : -1);
}
@Override
void setLocation(IPocketAccess access) {
entity = access.getEntity();
super.setLocation(access);
}
@Override
public double getRange() {
return 0;
}
@Override
public boolean equals(@Nullable IPeripheral other) {
return other instanceof PocketNFCPeripheral;
}
@Override
protected PacketNetwork getNetwork() {
return ComputerCraftAPI.getNfcNetwork(Nullability.assertNonNull(getLevel().getServer()), Nullability.assertNonNull(entity));
}
}

View File

@ -43,6 +43,6 @@ public void update() {
super.update();
access.setLight(madeSound() ? 0x3320fc : -1);
access.setLightPrimary(madeSound() ? 0x3320fc : -1);
}
}