From 497747e8b35b097dc3c1ab4e537cf76c534f0f3c Mon Sep 17 00:00:00 2001 From: Stuart Pomeroy Date: Wed, 24 Jul 2024 23:37:42 +0100 Subject: [PATCH 1/5] DMX networks WIP --- .../client/dmx/ArtNetToNetworkClientData.java | 52 ++++++ .../client/dmx/SavedClientNetworkManager.java | 58 ++++++ .../dev/imabad/theatrical/dmx/DMXNetwork.java | 171 ++++++++++++++++++ .../theatrical/dmx/DMXNetworkMember.java | 6 + .../theatrical/dmx/DMXNetworkMemberRole.java | 7 + .../imabad/theatrical/dmx/DMXNetworkMode.java | 9 + .../theatrical/items/ConfigurationCard.java | 24 +++ .../theatrical/net/artnet/NotifyNetworks.java | 53 ++++++ .../net/artnet/RequestNetworks.java | 46 +++++ .../dev/imabad/theatrical/util/UUIDUtil.java | 8 + 10 files changed, 434 insertions(+) create mode 100644 common/src/main/java/dev/imabad/theatrical/client/dmx/ArtNetToNetworkClientData.java create mode 100644 common/src/main/java/dev/imabad/theatrical/client/dmx/SavedClientNetworkManager.java create mode 100644 common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java create mode 100644 common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMember.java create mode 100644 common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMemberRole.java create mode 100644 common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMode.java create mode 100644 common/src/main/java/dev/imabad/theatrical/items/ConfigurationCard.java create mode 100644 common/src/main/java/dev/imabad/theatrical/net/artnet/NotifyNetworks.java create mode 100644 common/src/main/java/dev/imabad/theatrical/net/artnet/RequestNetworks.java create mode 100644 common/src/main/java/dev/imabad/theatrical/util/UUIDUtil.java diff --git a/common/src/main/java/dev/imabad/theatrical/client/dmx/ArtNetToNetworkClientData.java b/common/src/main/java/dev/imabad/theatrical/client/dmx/ArtNetToNetworkClientData.java new file mode 100644 index 0000000..149822c --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/client/dmx/ArtNetToNetworkClientData.java @@ -0,0 +1,52 @@ +package dev.imabad.theatrical.client.dmx; + +import dev.imabad.theatrical.util.UUIDUtil; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.saveddata.SavedData; + +import java.util.UUID; + +public class ArtNetToNetworkClientData extends SavedData { + + private static ArtNetToNetworkClientData INSTANCE; + private static final String KEY = "artnet_network_map"; + + private static final SavedData.Factory factory = new Factory<>( + ArtNetToNetworkClientData::new, + ArtNetToNetworkClientData::read, + null + ); + public static ArtNetToNetworkClientData getInstance(Level level){ + if(INSTANCE == null){ + INSTANCE = level.getServer() + .overworld().getDataStorage().computeIfAbsent(factory, KEY); + } + return INSTANCE; + } + + public static ArtNetToNetworkClientData read(CompoundTag tag) { + ArtNetToNetworkClientData data = new ArtNetToNetworkClientData(); + if(tag.contains("networkId")) { + data.setNetworkId(tag.getUUID("networkId")); + } + return data; + } + + + private UUID networkId = UUIDUtil.NULL; + + public UUID getNetworkId() { + return networkId; + } + + public void setNetworkId(UUID networkId) { + this.networkId = networkId; + } + + @Override + public CompoundTag save(CompoundTag compoundTag) { + compoundTag.putUUID("networkId", networkId); + return compoundTag; + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/client/dmx/SavedClientNetworkManager.java b/common/src/main/java/dev/imabad/theatrical/client/dmx/SavedClientNetworkManager.java new file mode 100644 index 0000000..f44ff9f --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/client/dmx/SavedClientNetworkManager.java @@ -0,0 +1,58 @@ +package dev.imabad.theatrical.client.dmx; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import net.minecraft.client.Minecraft; + +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class SavedClientNetworkManager { + + private static final SavedClientNetworkManager INSTANCE = new SavedClientNetworkManager(); + private static final Gson GSON = new Gson(); + + public static SavedClientNetworkManager getInstance(){ + return INSTANCE; + } + + private final Path savePath; + private final Map ipToNetworkIdMap = new HashMap<>(); + + public SavedClientNetworkManager(){ + savePath = new File(Minecraft.getInstance().gameDirectory, "local/dmx_networks.json").toPath(); + if(Files.exists(savePath)){ + try (Reader reader = Files.newBufferedReader(savePath)) { + JsonObject jsonObject = GSON.fromJson(reader, JsonObject.class); + for (String s : jsonObject.keySet()) { + ipToNetworkIdMap.put(s, UUID.fromString(jsonObject.get(s).getAsString())); + } + } catch (Exception ignored){} + } + } + + public UUID getNetworkFromIP(String ip) { + return ipToNetworkIdMap.get(ip); + } + + private void save(){ + String json = GSON.toJson(ipToNetworkIdMap); + try { + Files.writeString(savePath, json); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void saveNetworkForIP(String ip, UUID networkId){ + ipToNetworkIdMap.put(ip, networkId); + save(); + } + +} diff --git a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java new file mode 100644 index 0000000..f5ffe55 --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java @@ -0,0 +1,171 @@ +package dev.imabad.theatrical.dmx; + +import ch.bildspur.artnet.rdm.RDMDeviceId; +import dev.imabad.theatrical.api.dmx.DMXConsumer; +import dev.imabad.theatrical.net.artnet.NotifyConsumerChange; +import io.netty.util.collection.IntObjectHashMap; +import io.netty.util.collection.IntObjectMap; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; + +import java.util.*; + +public class DMXNetwork { + private final UUID id; + private final String name; + private final DMXNetworkMode mode; + private final Set members; + private final IntObjectMap> universeToNodeMap = new IntObjectHashMap<>(); + private final Set knownSenders = new HashSet<>(); + public DMXNetwork(UUID id, String name, DMXNetworkMode mode, Set members) { + this.id = id; + this.name = name; + this.mode = mode; + this.members = members; + } + public DMXNetwork(CompoundTag data){ + this.id = data.getUUID("id"); + this.name = data.getString("name"); + this.mode = DMXNetworkMode.valueOf(data.getString("mode")); + this.members = new HashSet<>(); + ListTag membersList = data.getList("members", CompoundTag.TAG_COMPOUND); + for (Tag tag : membersList) { + CompoundTag member = (CompoundTag) tag; + UUID player = member.getUUID("player"); + DMXNetworkMemberRole role = DMXNetworkMemberRole.valueOf(member.getString("role")); + members.add(new DMXNetworkMember(player, role)); + } + } + public DMXNetwork(String name){ + this.id = UUID.randomUUID(); + this.name = name; + this.mode = DMXNetworkMode.PRIVATE; + this.members = new HashSet<>(); + } + + public CompoundTag save(){ + CompoundTag tag = new CompoundTag(); + tag.putUUID("id", id); + tag.putString("mode", mode.toString()); + ListTag membersList = new ListTag(); + for (DMXNetworkMember member : members) { + CompoundTag memberTag = new CompoundTag(); + memberTag.putUUID("player", member.playerId()); + memberTag.putString("role", member.role().toString()); + membersList.add(memberTag); + } + tag.put("members", membersList); + return tag; + } + + public String name(){ return name;} + + public UUID id() { + return id; + } + + public DMXNetworkMode mode() { + return mode; + } + + public Set members() { + return members; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (DMXNetwork) obj; + return Objects.equals(this.id, that.id); + } + + @Override + public int hashCode() { + return Objects.hash(id); + } + + @Override + public String toString() { + return "DMXNetwork[" + + "id=" + id + ", " + + "mode=" + mode + ", " + + "members=" + members + ']'; + } + + public void addConsumer(BlockPos pos, DMXConsumer consumer){ + Map universe = universeToNodeMap.computeIfAbsent(consumer.getUniverse(), (uni) -> new HashMap<>()); + universe.put(pos, consumer); + universeToNodeMap.put(consumer.getUniverse(), universe); + new NotifyConsumerChange(consumer.getUniverse(), + NotifyConsumerChange.ChangeType.ADD, + new DMXDevice( + consumer.getDeviceId(), consumer.getChannelStart(), consumer.getChannelCount(), + consumer.getDeviceTypeId(), consumer.getActivePersonality(), consumer.getModelName(), consumer.getFixtureId())) + .sendTo(knownSenders); + } + + public void updateConsumer(DMXConsumer consumer){ + new NotifyConsumerChange(consumer.getUniverse(), + NotifyConsumerChange.ChangeType.UPDATE, + new DMXDevice(consumer.getDeviceId(), consumer.getChannelStart(), consumer.getChannelCount(), + consumer.getDeviceTypeId(),consumer.getActivePersonality(), consumer.getModelName(), consumer.getFixtureId())) + .sendTo(knownSenders); + } + + public void removeConsumer(DMXConsumer consumer, BlockPos pos){ + if(!universeToNodeMap.containsKey(consumer.getUniverse())){ + return; + } + Map universe = universeToNodeMap.get(consumer.getUniverse()); + universe.remove(pos); + new NotifyConsumerChange(consumer.getUniverse(), NotifyConsumerChange.ChangeType.REMOVE, + new DMXDevice(consumer.getDeviceId(), 0, 0,0, + 0, "", new ResourceLocation(""))) + .sendTo(knownSenders); + } + public Collection getConsumers(int universe){ + if(universeToNodeMap.get(universe) != null) { + return universeToNodeMap.get(universe).values(); + } + return null; + } + + public BlockPos getConsumerPos(int universe, RDMDeviceId deviceId){ + for (Map.Entry blockPosDMXConsumerEntry : universeToNodeMap.get(universe).entrySet()) { + if(blockPosDMXConsumerEntry.getValue().getDeviceId().equals(deviceId)){ + return blockPosDMXConsumerEntry.getKey(); + } + } + return null; + } + + public Collection getConsumersInRange(int universe, BlockPos fromPos, int radius){ + Collection consumers = new HashSet<>(); + if(!universeToNodeMap.containsKey(universe) || universeToNodeMap.get(universe).isEmpty()){ + return consumers; + } + for(Map.Entry entry : universeToNodeMap.get(universe).entrySet()){ + if(Math.sqrt(fromPos.distToCenterSqr(entry.getKey().getX(), entry.getKey().getY(), entry.getKey().getZ())) <= radius){ + consumers.add(entry.getValue()); + } + } + return consumers; + } + + public Set getUniverses(){ + return universeToNodeMap.keySet(); + } + + public void addMember(UUID playerUUID, DMXNetworkMemberRole role){ + members.add(new DMXNetworkMember(playerUUID, role)); + } + + public boolean isMember(UUID playerUUID){ + return members.stream().anyMatch(x -> x.playerId().equals(playerUUID)); + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMember.java b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMember.java new file mode 100644 index 0000000..0ab0a91 --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMember.java @@ -0,0 +1,6 @@ +package dev.imabad.theatrical.dmx; + +import java.util.UUID; + +public record DMXNetworkMember(UUID playerId, DMXNetworkMemberRole role) { +} diff --git a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMemberRole.java b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMemberRole.java new file mode 100644 index 0000000..a117b88 --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMemberRole.java @@ -0,0 +1,7 @@ +package dev.imabad.theatrical.dmx; + +public enum DMXNetworkMemberRole { + NONE, + SEND, + ADMIN; +} diff --git a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMode.java b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMode.java new file mode 100644 index 0000000..df97066 --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMode.java @@ -0,0 +1,9 @@ +package dev.imabad.theatrical.dmx; + +public enum DMXNetworkMode { + + PUBLIC, + INVITE, + PRIVATE; + +} diff --git a/common/src/main/java/dev/imabad/theatrical/items/ConfigurationCard.java b/common/src/main/java/dev/imabad/theatrical/items/ConfigurationCard.java new file mode 100644 index 0000000..1fceb7d --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/items/ConfigurationCard.java @@ -0,0 +1,24 @@ +package dev.imabad.theatrical.items; + +import dev.imabad.theatrical.Theatrical; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +public class ConfigurationCard extends Item { + public ConfigurationCard() { + super(new Item.Properties().arch$tab(Theatrical.TAB)); + } + + @Override + public InteractionResultHolder use(Level level, Player player, InteractionHand usedHand) { + if(player.isCrouching()){ + //TODO: Open UI + return InteractionResultHolder.pass(player.getItemInHand(usedHand)); + } + return super.use(level, player, usedHand); + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/net/artnet/NotifyNetworks.java b/common/src/main/java/dev/imabad/theatrical/net/artnet/NotifyNetworks.java new file mode 100644 index 0000000..dc5ee83 --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/net/artnet/NotifyNetworks.java @@ -0,0 +1,53 @@ +package dev.imabad.theatrical.net.artnet; + +import dev.architectury.networking.NetworkManager; +import dev.architectury.networking.simple.BaseS2CMessage; +import dev.architectury.networking.simple.MessageType; +import dev.imabad.theatrical.TheatricalClient; +import dev.imabad.theatrical.client.dmx.ArtNetManager; +import dev.imabad.theatrical.dmx.DMXNetwork; +import dev.imabad.theatrical.net.TheatricalNet; +import net.minecraft.network.FriendlyByteBuf; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class NotifyNetworks extends BaseS2CMessage { + + private final Map networks; + + public NotifyNetworks(Map networks) { + this.networks = networks; + } + + public NotifyNetworks(FriendlyByteBuf buf) { + networks = new HashMap<>(); + int count = buf.readInt(); + for(int i = 0; i < count; i++){ + String name = buf.readUtf(); + UUID uuid = buf.readUUID(); + networks.put(uuid, name); + } + } + + @Override + public MessageType getType() { + return TheatricalNet.NOTIFY_NETWORKS; + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeInt(networks.size()); + for (UUID u : networks.keySet()) { + buf.writeUtf(networks.get(u)); + buf.writeUUID(u); + } + } + + @Override + public void handle(NetworkManager.PacketContext context) { + TheatricalClient.getArtNetManager().populateNetworks(networks); + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestNetworks.java b/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestNetworks.java new file mode 100644 index 0000000..f6738da --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestNetworks.java @@ -0,0 +1,46 @@ +package dev.imabad.theatrical.net.artnet; + +import dev.architectury.networking.NetworkManager; +import dev.architectury.networking.simple.BaseC2SMessage; +import dev.architectury.networking.simple.MessageType; +import dev.imabad.theatrical.Theatrical; +import dev.imabad.theatrical.api.dmx.DMXConsumer; +import dev.imabad.theatrical.dmx.DMXDevice; +import dev.imabad.theatrical.dmx.DMXNetwork; +import dev.imabad.theatrical.dmx.DMXNetworkData; +import dev.imabad.theatrical.net.TheatricalNet; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; + +import java.util.*; +import java.util.stream.Collectors; + +public class RequestNetworks extends BaseC2SMessage { + + public RequestNetworks() { + } + + public RequestNetworks(FriendlyByteBuf buf){} + + @Override + public MessageType getType() { + return TheatricalNet.REQUEST_NETWORKS; + } + + @Override + public void write(FriendlyByteBuf buf) { + + } + + @Override + public void handle(NetworkManager.PacketContext context) { + Level level = context.getPlayer().level(); + if(level.getServer() != null ) { + List networksForPlayer = DMXNetworkData.getInstance(level) + .getNetworksForPlayer(context.getPlayer().getUUID()); + Map collect = networksForPlayer.stream().collect(Collectors.toMap(DMXNetwork::id, DMXNetwork::name)); + new NotifyNetworks(collect).sendTo((ServerPlayer) context.getPlayer()); + } + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/util/UUIDUtil.java b/common/src/main/java/dev/imabad/theatrical/util/UUIDUtil.java new file mode 100644 index 0000000..efd319b --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/util/UUIDUtil.java @@ -0,0 +1,8 @@ +package dev.imabad.theatrical.util; + +import java.util.UUID; + +public class UUIDUtil { + + public static final UUID NULL = new UUID( 0 , 0 ); +} From 1021cc8e02efe111ee14718ba92763b7b7ea83dc Mon Sep 17 00:00:00 2001 From: Stuart Pomeroy Date: Mon, 29 Jul 2024 01:03:11 +0100 Subject: [PATCH 2/5] wip: networks - needs more work for the commands --- .../dev/imabad/theatrical/Theatrical.java | 83 +++++-- .../imabad/theatrical/TheatricalClient.java | 7 +- .../theatrical/api/dmx/BelongsToNetwork.java | 10 + .../theatrical/api/dmx/DMXConsumer.java | 5 +- .../control/BasicLightingDeskBlockEntity.java | 39 +++- .../ArtNetInterfaceBlockEntity.java | 39 ++-- .../RedstoneInterfaceBlockEntity.java | 30 ++- .../BaseDMXConsumerLightBlockEntity.java | 36 ++- .../control/BasicLightingDeskBlock.java | 2 +- .../interfaces/ArtNetInterfaceBlock.java | 2 +- .../blocks/light/BaseLightBlock.java | 20 ++ .../theatrical/client/dmx/ArtNetManager.java | 87 ++++++++ .../dmx/TheatricalArtNetClient.java | 26 ++- .../gui/screen/ArtNetConfigurationScreen.java | 26 ++- .../gui/screen/ArtNetInterfaceScreen.java | 38 ++-- .../gui/screen/BasicLightingDeskScreen.java | 29 ++- .../client/gui/screen/FresnelScreen.java | 93 ++------ .../screen/GenericDMXConfigurationScreen.java | 103 +++++++-- .../client/gui/widgets/LabeledEditBox.java | 46 +++- .../dev/imabad/theatrical/dmx/DMXNetwork.java | 10 + .../imabad/theatrical/dmx/DMXNetworkData.java | 209 ++++++++++++------ .../mixin/client/OptionsScreenMixin.java | 5 +- .../imabad/theatrical/net/TheatricalNet.java | 3 + .../theatrical/net/UpdateArtNetInterface.java | 6 +- .../theatrical/net/UpdateDMXFixture.java | 2 + .../theatrical/net/UpdateNetworkId.java | 46 ++++ .../net/artnet/RDMUpdateConsumer.java | 22 +- .../net/artnet/RequestConsumers.java | 15 +- .../theatrical/net/artnet/SendArtNetData.java | 37 ++-- .../protocols/artnet/ArtNetManager.java | 42 ---- 30 files changed, 790 insertions(+), 328 deletions(-) create mode 100644 common/src/main/java/dev/imabad/theatrical/api/dmx/BelongsToNetwork.java create mode 100644 common/src/main/java/dev/imabad/theatrical/client/dmx/ArtNetManager.java rename common/src/main/java/dev/imabad/theatrical/{ => client}/dmx/TheatricalArtNetClient.java (97%) create mode 100644 common/src/main/java/dev/imabad/theatrical/net/UpdateNetworkId.java delete mode 100644 common/src/main/java/dev/imabad/theatrical/protocols/artnet/ArtNetManager.java diff --git a/common/src/main/java/dev/imabad/theatrical/Theatrical.java b/common/src/main/java/dev/imabad/theatrical/Theatrical.java index 133c1f8..1e11348 100644 --- a/common/src/main/java/dev/imabad/theatrical/Theatrical.java +++ b/common/src/main/java/dev/imabad/theatrical/Theatrical.java @@ -1,5 +1,8 @@ package dev.imabad.theatrical; +import com.mojang.authlib.GameProfile; +import com.mojang.brigadier.arguments.StringArgumentType; +import dev.architectury.event.events.common.CommandRegistrationEvent; import dev.architectury.event.events.common.PlayerEvent; import dev.architectury.platform.Platform; import dev.architectury.registry.CreativeTabRegistry; @@ -10,20 +13,29 @@ import dev.imabad.theatrical.config.ConfigHandler; import dev.imabad.theatrical.config.TheatricalConfig; import dev.imabad.theatrical.dmx.DMXDevice; +import dev.imabad.theatrical.dmx.DMXNetwork; import dev.imabad.theatrical.dmx.DMXNetworkData; +import dev.imabad.theatrical.dmx.DMXNetworkMember; import dev.imabad.theatrical.fixtures.Fixtures; import dev.imabad.theatrical.items.Items; import dev.imabad.theatrical.net.artnet.ListConsumers; import dev.imabad.theatrical.net.TheatricalNet; +import net.minecraft.commands.Commands; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; +import net.minecraft.server.players.GameProfileCache; +import net.minecraft.util.Tuple; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.ItemStack; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.swing.text.html.Option; import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; public class Theatrical { public static final String MOD_ID = "theatrical"; @@ -50,21 +62,66 @@ public static void init() { BlockEntities.BLOCK_ENTITIES.register(); dev.imabad.theatrical.items.Items.ITEMS.register(); PlayerEvent.PLAYER_JOIN.register((event) -> { - if(event.connection.player.hasPermissions(event.getServer().getOperatorUserPermissionLevel())){ - DMXNetworkData.getInstance().addKnownSender(event.connection.player); - } - for (Integer universe : DMXNetworkData.getInstance().getUniverses()) { - List devices = new ArrayList<>(); - DMXNetworkData.getInstance().getConsumers(universe).forEach(consumer -> { - devices.add(new DMXDevice(consumer.getDeviceId(), consumer.getChannelStart(), - consumer.getChannelCount(), consumer.getDeviceTypeId(), consumer.getActivePersonality(), consumer.getModelName(), - consumer.getFixtureId())); - }); - new ListConsumers(universe, devices).sendTo(event.connection.player); + DMXNetworkData instance = DMXNetworkData.getInstance(event.server.overworld()); + for (DMXNetwork network : instance.getNetworksForPlayer(event.connection.player.getUUID())) { + for (Integer universe : network.getUniverses()) { + List devices = new ArrayList<>(); + network.getConsumers(universe).forEach(consumer -> { + devices.add(new DMXDevice(consumer.getDeviceId(), consumer.getChannelStart(), + consumer.getChannelCount(), consumer.getDeviceTypeId(), consumer.getActivePersonality(), consumer.getModelName(), + consumer.getFixtureId())); + }); + new ListConsumers(universe, devices).sendTo(event.connection.player); + } } }); - PlayerEvent.PLAYER_QUIT.register((event) -> { - DMXNetworkData.getInstance().removeKnownSender(event.connection.player); + CommandRegistrationEvent.EVENT.register((dispatcher, registry, selection) -> { + dispatcher.register(Commands.literal("theatrical") + .then(Commands.literal("networks") + .executes(context -> { + DMXNetworkData instance = DMXNetworkData. + getInstance(context.getSource().getServer().overworld()); + String networks; + if(context.getSource().hasPermission(context.getSource().getServer().getOperatorUserPermissionLevel())){ + networks = instance.getAllNetworks().stream() + .map(DMXNetwork::name).collect(Collectors.joining(",")); + } else { + networks = instance.getNetworksForPlayer(context.getSource().getPlayer().getUUID()).stream() + .map(DMXNetwork::name).collect(Collectors.joining(",")); + } + context.getSource().sendSystemMessage(Component.literal("Networks: " + networks)); + return 1; + }) + ) + .then(Commands.literal("network") + .then(Commands.argument("id", StringArgumentType.string()) + .then(Commands.literal("members") + .executes(context -> { + DMXNetworkData instance = DMXNetworkData. + getInstance(context.getSource().getServer().overworld()); + try { + String id = context.getArgument("id", String.class); + UUID uuid = UUID.fromString(id); + DMXNetwork network = instance.getNetwork(uuid); + if(network != null) { + GameProfileCache profileCache = context.getSource().getServer().getProfileCache(); + String collect = network.members() + .stream().map(DMXNetworkMember::playerId) + .map((playerUUID) -> new Tuple<>(playerUUID, profileCache.get(playerUUID))) + .map(uuidOptionalTuple -> uuidOptionalTuple.getB().isPresent() ? uuidOptionalTuple.getB().get().getName() : uuidOptionalTuple.getA().toString()) + .toList().stream().collect(Collectors.joining(",")); + context.getSource().sendSystemMessage(Component.literal("Members: " + collect)); + } + } catch (Exception e){ + context.getSource().sendSystemMessage(Component.literal("Invalid network")); + return -1; + } + return 1; + }) + ) + ) + ) + ); }); } } diff --git a/common/src/main/java/dev/imabad/theatrical/TheatricalClient.java b/common/src/main/java/dev/imabad/theatrical/TheatricalClient.java index 927531e..7b35291 100644 --- a/common/src/main/java/dev/imabad/theatrical/TheatricalClient.java +++ b/common/src/main/java/dev/imabad/theatrical/TheatricalClient.java @@ -5,7 +5,6 @@ import com.mojang.math.Axis; import dev.architectury.event.events.client.ClientPlayerEvent; import dev.architectury.registry.client.rendering.BlockEntityRendererRegistry; -import dev.architectury.registry.client.rendering.RenderTypeRegistry; import dev.imabad.theatrical.blockentities.BlockEntities; import dev.imabad.theatrical.blockentities.light.BaseLightBlockEntity; import dev.imabad.theatrical.blocks.light.MovingLightBlock; @@ -15,11 +14,12 @@ import dev.imabad.theatrical.client.blockentities.MovingLightRenderer; import dev.imabad.theatrical.config.TheatricalConfig; import dev.imabad.theatrical.dmx.DMXDevice; -import dev.imabad.theatrical.dmx.TheatricalArtNetClient; +import dev.imabad.theatrical.client.dmx.TheatricalArtNetClient; import dev.imabad.theatrical.lighting.LightManager; import dev.imabad.theatrical.net.artnet.ListConsumers; import dev.imabad.theatrical.net.artnet.NotifyConsumerChange; -import dev.imabad.theatrical.protocols.artnet.ArtNetManager; +import dev.imabad.theatrical.client.dmx.ArtNetManager; +import dev.imabad.theatrical.net.artnet.RequestNetworks; import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; @@ -52,6 +52,7 @@ public static void init() { // BlockEntityRendererRegistry.register(BlockEntities.CABLE.get(), CableRenderer::new); artNetManager = new ArtNetManager(); ClientPlayerEvent.CLIENT_PLAYER_JOIN.register((event) -> { + new RequestNetworks().sendToServer(); if(TheatricalConfig.INSTANCE.CLIENT.artnetEnabled){ artNetManager.getClient(); } diff --git a/common/src/main/java/dev/imabad/theatrical/api/dmx/BelongsToNetwork.java b/common/src/main/java/dev/imabad/theatrical/api/dmx/BelongsToNetwork.java new file mode 100644 index 0000000..6e8d53f --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/api/dmx/BelongsToNetwork.java @@ -0,0 +1,10 @@ +package dev.imabad.theatrical.api.dmx; + +import java.util.UUID; + +public interface BelongsToNetwork { + + UUID getNetworkId(); + + void setNetworkId(UUID newNetworkId); +} diff --git a/common/src/main/java/dev/imabad/theatrical/api/dmx/DMXConsumer.java b/common/src/main/java/dev/imabad/theatrical/api/dmx/DMXConsumer.java index cdf3bbc..e6a8442 100644 --- a/common/src/main/java/dev/imabad/theatrical/api/dmx/DMXConsumer.java +++ b/common/src/main/java/dev/imabad/theatrical/api/dmx/DMXConsumer.java @@ -3,7 +3,9 @@ import ch.bildspur.artnet.rdm.RDMDeviceId; import net.minecraft.resources.ResourceLocation; -public interface DMXConsumer { +import java.util.UUID; + +public interface DMXConsumer extends BelongsToNetwork { int getChannelCount(); @@ -23,4 +25,5 @@ public interface DMXConsumer { int getActivePersonality(); + UUID getNetworkId(); } diff --git a/common/src/main/java/dev/imabad/theatrical/blockentities/control/BasicLightingDeskBlockEntity.java b/common/src/main/java/dev/imabad/theatrical/blockentities/control/BasicLightingDeskBlockEntity.java index 26b42f5..48e77f1 100644 --- a/common/src/main/java/dev/imabad/theatrical/blockentities/control/BasicLightingDeskBlockEntity.java +++ b/common/src/main/java/dev/imabad/theatrical/blockentities/control/BasicLightingDeskBlockEntity.java @@ -1,5 +1,6 @@ package dev.imabad.theatrical.blockentities.control; +import dev.imabad.theatrical.api.dmx.BelongsToNetwork; import dev.imabad.theatrical.blockentities.BlockEntities; import dev.imabad.theatrical.blockentities.ClientSyncBlockEntity; import dev.imabad.theatrical.blocks.control.BasicLightingDeskBlock; @@ -13,12 +14,9 @@ import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import java.util.Arrays; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Optional; +import java.util.*; -public class BasicLightingDeskBlockEntity extends ClientSyncBlockEntity { +public class BasicLightingDeskBlockEntity extends ClientSyncBlockEntity implements BelongsToNetwork { public static class StoredCue { private byte[] faders; private int fadeInTicks; @@ -75,9 +73,11 @@ public int getFadeOutTicks() { private int fadeOutTicksRemaining = 0; private byte[] perTickOut, perTickIn; private boolean isFadingOut = false; - private byte grandMaster = -1; + private UUID networkId; + private int universe = 0; + public BasicLightingDeskBlockEntity(BlockPos blockPos, BlockState blockState) { super(BlockEntities.BASIC_LIGHTING_DESK.get(), blockPos, blockState); } @@ -119,9 +119,9 @@ public void tick(){ public void update(byte[] data) { if(level != null && level.getServer() != null) { - var dmxData = DMXNetworkData.getInstance(); + var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); if(dmxData != null) { - dmxData.getConsumersInRange(getBlockPos(), TheatricalConfig.INSTANCE.COMMON.wirelessDMXRadius).forEach(dmxConsumer -> dmxConsumer.consume(data)); + dmxData.getConsumers(universe).forEach(consumer -> consumer.consume(data)); } } } @@ -151,6 +151,10 @@ public void write(CompoundTag compoundTag) { compoundTag.putBoolean("isRunMode", isRunMode); compoundTag.putInt("fadeInTicks", fadeInTicks); compoundTag.putInt("fadeOutTicks", fadeOutTicks); + if(networkId != null){ + compoundTag.putUUID("network", networkId); + } + compoundTag.putInt("universe", universe); } @Override @@ -181,6 +185,12 @@ public void read(CompoundTag compoundTag) { if(compoundTag.contains("fadeOutTicks")){ fadeOutTicks = compoundTag.getInt("fadeOutTicks"); } + if(compoundTag.contains("network")){ + networkId = compoundTag.getUUID("network"); + } + if(compoundTag.contains("universe")){ + universe = compoundTag.getInt("universe"); + } } public void setFaders(byte[] faders){ @@ -345,4 +355,17 @@ public void setFadeOutTicks(int fadeOutTicks) { this.fadeOutTicks = fadeOutTicks; } + public UUID getNetworkId() { + return networkId; + } + + @Override + public void setNetworkId(UUID newNetworkId) { + if(newNetworkId == this.networkId){ + return; + } + this.networkId = newNetworkId; + setChanged(); + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); + } } diff --git a/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/ArtNetInterfaceBlockEntity.java b/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/ArtNetInterfaceBlockEntity.java index 6832ead..fa38c18 100644 --- a/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/ArtNetInterfaceBlockEntity.java +++ b/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/ArtNetInterfaceBlockEntity.java @@ -31,7 +31,7 @@ public static void tick(Level level, BlockPos pos, Block private int subnet, universe, tickTimer = 0; private String ip = "127.0.0.1"; - private UUID ownerUUID; + private UUID networkId; public ArtNetInterfaceBlockEntity(BlockPos blockPos, BlockState blockState) { super(BlockEntities.ART_NET_INTERFACE.get(), blockPos, blockState); @@ -42,8 +42,8 @@ public void write(CompoundTag compoundTag) { compoundTag.putString("ip", ip); compoundTag.putInt("subnet", subnet); compoundTag.putInt("universe", universe); - if(ownerUUID != null) { - compoundTag.putUUID("ownerUUID", ownerUUID); + if(networkId != null) { + compoundTag.putUUID("networkId", networkId); } } @@ -52,30 +52,19 @@ public void read(CompoundTag compoundTag) { this.ip = compoundTag.getString("ip"); this.subnet = compoundTag.getInt("subnet"); this.universe = compoundTag.getInt("universe"); - if(compoundTag.contains("ownerUUID")) { - this.ownerUUID = compoundTag.getUUID("ownerUUID"); + if(compoundTag.contains("networkId")) { + this.networkId = compoundTag.getUUID("networkId"); } } public void update(byte[] data) { if(level != null && level.getServer() != null) { - var dmxData = DMXNetworkData.getInstance(); + var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); if(dmxData != null) { dmxData.getConsumersInRange(universe, getBlockPos(), TheatricalConfig.INSTANCE.COMMON.wirelessDMXRadius).forEach(dmxConsumer -> dmxConsumer.consume(data)); } } } - - public boolean isOwnedByCurrentClient(){ - if(!TheatricalConfig.INSTANCE.CLIENT.doOwnerCheck){ - return true; - } - if(level != null && level.isClientSide){ - return ownerUUID != null && ownerUUID.equals(Minecraft.getInstance().getUser().getProfileId()); - } - return false; - } - public boolean hasReceivedPacket(){ // if(level != null && level.isClientSide){ // return TheatricalClient.getArtNetManager().getClient(this.ip).hasReceivedPacket(); @@ -98,9 +87,9 @@ public String getIp() { return ip; } - public UUID getOwnerUUID() { - return ownerUUID; - } +// public UUID getOwnerUUID() { +// return ownerUUID; +// } public void updateConfig(String ipAddress, int dmxUniverse){ this.ip = ipAddress; @@ -109,9 +98,9 @@ public void updateConfig(String ipAddress, int dmxUniverse){ level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); } - public void setOwnerUUID(UUID ownerUUID) { - this.ownerUUID = ownerUUID; - setChanged(); - level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); - } +// public void setOwnerUUID(UUID ownerUUID) { +// this.ownerUUID = ownerUUID; +// setChanged(); +// level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); +// } } diff --git a/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/RedstoneInterfaceBlockEntity.java b/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/RedstoneInterfaceBlockEntity.java index e385a57..cd4431f 100644 --- a/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/RedstoneInterfaceBlockEntity.java +++ b/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/RedstoneInterfaceBlockEntity.java @@ -19,12 +19,14 @@ import java.util.Arrays; import java.util.Random; +import java.util.UUID; public class RedstoneInterfaceBlockEntity extends ClientSyncBlockEntity implements DMXConsumer { private int channelStartPoint, dmxUniverse = 0; private int redstoneOutput = 0; private RDMDeviceId deviceId; + private UUID networkId; public RedstoneInterfaceBlockEntity(BlockPos blockPos, BlockState blockState) { super(BlockEntities.REDSTONE_INTERFACE.get(), blockPos, blockState); @@ -36,6 +38,9 @@ public void write(CompoundTag compoundTag) { compoundTag.putInt("channelStartPoint", channelStartPoint); compoundTag.putInt("dmxUniverse", dmxUniverse); compoundTag.putByteArray("deviceId", deviceId.toBytes()); + if(networkId != null){ + compoundTag.putUUID("network", networkId); + } } @Override @@ -47,6 +52,9 @@ public void read(CompoundTag compoundTag) { if(compoundTag.contains("deviceId")){ deviceId = new RDMDeviceId(compoundTag.getByteArray("deviceId")); } + if(compoundTag.contains("network")){ + networkId = compoundTag.getUUID("network"); + } } @Override @@ -93,6 +101,22 @@ public int getActivePersonality() { return 0; } + @Override + public UUID getNetworkId() { + return networkId; + } + + public void setNetworkId(UUID networkId) { + if(networkId == this.networkId){ + return; + } + removeConsumer(); + this.networkId = networkId; + addConsumer(); + setChanged(); + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); + } + private void generateDeviceId(){ byte[] bytes = new byte[4]; if(level != null) { @@ -138,14 +162,14 @@ public void setUniverse(int universe) { } private void updateConsumer(){ - var dmxData = DMXNetworkData.getInstance(); + var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); if (dmxData != null) { dmxData.updateConsumer(this); } } private void addConsumer(){ - var dmxData = DMXNetworkData.getInstance(); + var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); if (dmxData != null) { if(deviceId == null){ generateDeviceId(); @@ -155,7 +179,7 @@ private void addConsumer(){ } private void removeConsumer(){ - var dmxData = DMXNetworkData.getInstance(); + var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); if (dmxData != null) { dmxData.removeConsumer(this, getBlockPos()); } diff --git a/common/src/main/java/dev/imabad/theatrical/blockentities/light/BaseDMXConsumerLightBlockEntity.java b/common/src/main/java/dev/imabad/theatrical/blockentities/light/BaseDMXConsumerLightBlockEntity.java index 529dc9d..09a241f 100644 --- a/common/src/main/java/dev/imabad/theatrical/blockentities/light/BaseDMXConsumerLightBlockEntity.java +++ b/common/src/main/java/dev/imabad/theatrical/blockentities/light/BaseDMXConsumerLightBlockEntity.java @@ -3,8 +3,10 @@ import ch.bildspur.artnet.rdm.RDMDeviceId; import dev.imabad.theatrical.Constants; import dev.imabad.theatrical.api.dmx.DMXConsumer; +import dev.imabad.theatrical.dmx.DMXNetwork; import dev.imabad.theatrical.dmx.DMXNetworkData; import dev.imabad.theatrical.util.RndUtils; +import dev.imabad.theatrical.util.UUIDUtil; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.world.level.Level; @@ -14,11 +16,13 @@ import java.util.Arrays; import java.util.Random; +import java.util.UUID; public abstract class BaseDMXConsumerLightBlockEntity extends BaseLightBlockEntity implements DMXConsumer { private int channelCount, channelStartPoint, dmxUniverse; private RDMDeviceId deviceId; + private UUID networkId = UUIDUtil.NULL; public BaseDMXConsumerLightBlockEntity(BlockEntityType blockEntityType, BlockPos blockPos, BlockState blockState) { super(blockEntityType, blockPos, blockState); @@ -30,7 +34,10 @@ public void write(CompoundTag compoundTag) { compoundTag.putInt("channelCount", channelCount); compoundTag.putInt("channelStartPoint", channelStartPoint); compoundTag.putInt("dmxUniverse", dmxUniverse); - compoundTag.putByteArray("deviceId", deviceId.toBytes()); + if(deviceId != null) { + compoundTag.putByteArray("deviceId", deviceId.toBytes()); + } + compoundTag.putUUID("network", networkId); } @Override @@ -44,6 +51,9 @@ public void read(CompoundTag compoundTag) { if(compoundTag.contains("deviceId")){ deviceId = new RDMDeviceId(compoundTag.getByteArray("deviceId")); } + if(compoundTag.contains("network")){ + networkId = compoundTag.getUUID("network"); + } } private void generateDeviceId(){ @@ -54,6 +64,7 @@ private void generateDeviceId(){ new Random().nextBytes(bytes); } deviceId = new RDMDeviceId(Constants.MANUFACTURER_ID, bytes); + setChanged(); level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); } @@ -77,6 +88,10 @@ public RDMDeviceId getDeviceId() { return deviceId; } + public UUID getNetworkId() { + return networkId; + } + public void setUniverse(int dmxUniverse) { if(this.dmxUniverse == dmxUniverse){ return; @@ -84,6 +99,7 @@ public void setUniverse(int dmxUniverse) { removeConsumer(); this.dmxUniverse = dmxUniverse; addConsumer(); + setChanged(); level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); } @@ -97,22 +113,23 @@ public void setChannelStartPoint(int channelStartPoint) { } this.channelStartPoint = channelStartPoint; updateConsumer(); + setChanged(); level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); } private void updateConsumer(){ - var dmxData = DMXNetworkData.getInstance(); + var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); if (dmxData != null) { dmxData.updateConsumer(this); } } private void removeConsumer(){ - var dmxData = DMXNetworkData.getInstance(); + var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); if (dmxData != null) { dmxData.removeConsumer(this, getBlockPos()); } } private void addConsumer(){ - var dmxData = DMXNetworkData.getInstance(); + var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); if (dmxData != null) { if(deviceId == null){ generateDeviceId(); @@ -136,4 +153,15 @@ public void setRemoved() { } super.setRemoved(); } + + public void setNetworkId(UUID networkId) { + if(networkId == this.networkId){ + return; + } + removeConsumer(); + this.networkId = networkId; + addConsumer(); + setChanged(); + level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); + } } diff --git a/common/src/main/java/dev/imabad/theatrical/blocks/control/BasicLightingDeskBlock.java b/common/src/main/java/dev/imabad/theatrical/blocks/control/BasicLightingDeskBlock.java index 1769ba6..bff4051 100644 --- a/common/src/main/java/dev/imabad/theatrical/blocks/control/BasicLightingDeskBlock.java +++ b/common/src/main/java/dev/imabad/theatrical/blocks/control/BasicLightingDeskBlock.java @@ -52,7 +52,7 @@ public BasicLightingDeskBlock() { @Nullable @Override public BlockState getStateForPlacement(BlockPlaceContext context) { - return this.defaultBlockState().setValue(FACING, context.getNearestLookingDirection().getOpposite()); + return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite()); } @Override diff --git a/common/src/main/java/dev/imabad/theatrical/blocks/interfaces/ArtNetInterfaceBlock.java b/common/src/main/java/dev/imabad/theatrical/blocks/interfaces/ArtNetInterfaceBlock.java index 337b104..a35ddef 100644 --- a/common/src/main/java/dev/imabad/theatrical/blocks/interfaces/ArtNetInterfaceBlock.java +++ b/common/src/main/java/dev/imabad/theatrical/blocks/interfaces/ArtNetInterfaceBlock.java @@ -62,7 +62,7 @@ public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable L if(!level.isClientSide){ BlockEntity be = level.getBlockEntity(pos); if(be instanceof ArtNetInterfaceBlockEntity interfaceBlock && placer != null){ - interfaceBlock.setOwnerUUID(placer.getUUID()); +// interfaceBlock.setOwnerUUID(placer.getUUID()); } } super.setPlacedBy(level, pos, state, placer, stack); diff --git a/common/src/main/java/dev/imabad/theatrical/blocks/light/BaseLightBlock.java b/common/src/main/java/dev/imabad/theatrical/blocks/light/BaseLightBlock.java index 801de97..07669f3 100644 --- a/common/src/main/java/dev/imabad/theatrical/blocks/light/BaseLightBlock.java +++ b/common/src/main/java/dev/imabad/theatrical/blocks/light/BaseLightBlock.java @@ -1,20 +1,29 @@ package dev.imabad.theatrical.blocks.light; +import dev.imabad.theatrical.blockentities.interfaces.ArtNetInterfaceBlockEntity; +import dev.imabad.theatrical.blockentities.light.BaseDMXConsumerLightBlockEntity; import dev.imabad.theatrical.blockentities.light.LightCollisionContext; import dev.imabad.theatrical.blocks.HangableBlock; +import dev.imabad.theatrical.dmx.DMXNetworkData; +import dev.imabad.theatrical.util.UUIDUtil; import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.Nullable; public abstract class BaseLightBlock extends HangableBlock implements EntityBlock { @@ -46,4 +55,15 @@ public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPo } return super.getCollisionShape(state, level, pos, context); } + + @Override + public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable LivingEntity placer, ItemStack stack) { + super.setPlacedBy(level, pos, state, placer, stack); + if(!level.isClientSide){ + BlockEntity be = level.getBlockEntity(pos); + if(be instanceof BaseDMXConsumerLightBlockEntity consumerLightBlockEntity && placer instanceof ServerPlayer player){ + consumerLightBlockEntity.setNetworkId(DMXNetworkData.getInstance(level).getDefaultNetworkForPlayer(player).id()); + } + } + } } diff --git a/common/src/main/java/dev/imabad/theatrical/client/dmx/ArtNetManager.java b/common/src/main/java/dev/imabad/theatrical/client/dmx/ArtNetManager.java new file mode 100644 index 0000000..ed6682c --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/client/dmx/ArtNetManager.java @@ -0,0 +1,87 @@ +package dev.imabad.theatrical.client.dmx; + +import dev.imabad.theatrical.config.TheatricalConfig; +import dev.imabad.theatrical.util.UUIDUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ServerData; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class ArtNetManager { + + private static final UUID NULL = UUIDUtil.NULL; + + private TheatricalArtNetClient artNetClient; + private final Map knownNetworks = new HashMap<>(); + + private UUID networkId = NULL; + + public Map getKnownNetworks() { + return knownNetworks; + } + + public void populateNetworks(Map networks){ + knownNetworks.clear(); + knownNetworks.putAll(networks); + } + + public void setNetworkId(UUID networkId) { + this.networkId = networkId; + if(artNetClient != null){ + artNetClient.networkChange(); + } + } + + public UUID getNetworkId(){ + return this.networkId; + } + + public UUID getSavedNetworkID(){ + ServerData currentServer = Minecraft.getInstance().getCurrentServer(); + if(currentServer != null){ + UUID networkFromIP = SavedClientNetworkManager.getInstance().getNetworkFromIP(currentServer.ip); + if(networkFromIP != null) { + return networkFromIP; + } + } else { + if(Minecraft.getInstance().getSingleplayerServer() != null) { + ArtNetToNetworkClientData instance = ArtNetToNetworkClientData.getInstance(Minecraft.getInstance().getSingleplayerServer().overworld()); + return instance.getNetworkId(); + } + } + return NULL; + } + + public TheatricalArtNetClient getClient(){ + if(this.artNetClient == null){ + this.artNetClient = newClient(); + } + return this.artNetClient; + } + + private TheatricalArtNetClient newClient(){ + try { + InetAddress byName = InetAddress.getByName(TheatricalConfig.INSTANCE.CLIENT.artNetIP); + networkId = getSavedNetworkID(); + TheatricalArtNetClient client = new TheatricalArtNetClient(byName, this); + client.start(byName); + return client; + } catch (UnknownHostException var3) { + var3.printStackTrace(); + } + return null; + } + + public void shutdownAll(){ + knownNetworks.clear(); + if(artNetClient == null){ + return; + } + artNetClient.stop(); + artNetClient = null; + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/dmx/TheatricalArtNetClient.java b/common/src/main/java/dev/imabad/theatrical/client/dmx/TheatricalArtNetClient.java similarity index 97% rename from common/src/main/java/dev/imabad/theatrical/dmx/TheatricalArtNetClient.java rename to common/src/main/java/dev/imabad/theatrical/client/dmx/TheatricalArtNetClient.java index 04b93fb..29f0212 100644 --- a/common/src/main/java/dev/imabad/theatrical/dmx/TheatricalArtNetClient.java +++ b/common/src/main/java/dev/imabad/theatrical/client/dmx/TheatricalArtNetClient.java @@ -1,4 +1,4 @@ -package dev.imabad.theatrical.dmx; +package dev.imabad.theatrical.client.dmx; import ch.bildspur.artnet.*; import ch.bildspur.artnet.events.ArtNetServerEventAdapter; @@ -13,6 +13,7 @@ import dev.imabad.theatrical.api.dmx.DMXPersonality; import dev.imabad.theatrical.api.dmx.DMXSlot; import dev.imabad.theatrical.config.TheatricalConfig; +import dev.imabad.theatrical.dmx.DMXDevice; import dev.imabad.theatrical.fixtures.Fixtures; import dev.imabad.theatrical.net.artnet.RDMUpdateConsumer; import dev.imabad.theatrical.net.artnet.RequestConsumers; @@ -21,6 +22,8 @@ import io.netty.util.collection.IntObjectHashMap; import io.netty.util.collection.IntObjectMap; import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ServerData; +import org.jetbrains.annotations.Nullable; import java.net.InetAddress; import java.net.SocketException; @@ -28,6 +31,7 @@ import java.util.*; public class TheatricalArtNetClient extends ArtNetClient { + private ArtNetManager manager; private InetAddress address; private final byte[] RDM_DEVICE_ID; @@ -38,15 +42,24 @@ public class TheatricalArtNetClient extends ArtNetClient { private Queue queuedMessages; private int[] universes = new int[]{-1, -1, -1, -1}; - public TheatricalArtNetClient(InetAddress address) { + public TheatricalArtNetClient(InetAddress address, ArtNetManager manager) { super(); + this.manager = manager; this.address = address; RDM_DEVICE_ID = buildDeviceId(); proxiedDevices = new IntObjectHashMap<>(); queuedMessages = new ArrayDeque<>(); universes = new int[]{TheatricalConfig.INSTANCE.CLIENT.universe1,TheatricalConfig.INSTANCE.CLIENT.universe2,TheatricalConfig.INSTANCE.CLIENT.universe3,TheatricalConfig.INSTANCE.CLIENT.universe4}; for (int i = 0; i < universes.length; i++) { - new RequestConsumers(i).sendToServer(); + new RequestConsumers(manager.getNetworkId(), i).sendToServer(); + } + } + + public void networkChange(){ + proxiedDevices.clear(); + queuedMessages.clear(); + for (int i = 0; i < universes.length; i++) { + new RequestConsumers(manager.getNetworkId(), i).sendToServer(); } } @@ -173,7 +186,7 @@ private void onPacketReceived(InetAddress sourceAddress, final ArtNetPacket pack lastPacketMS = System.currentTimeMillis(); getInputBuffer().setDmxData((short) subnet, (short) universe, dmxPacket.getDmxData()); - new SendArtNetData(universe, dmxPacket.getDmxData()).sendToServer(); + new SendArtNetData(manager.getNetworkId(), universe, dmxPacket.getDmxData()).sendToServer(); break; } case ART_TOD_REQUEST: { @@ -192,7 +205,6 @@ private void onPacketReceived(InetAddress sourceAddress, final ArtNetPacket pack ArtRdmPacket artRdmPacket = (ArtRdmPacket) packet; RDMPacket rdmPacket = artRdmPacket.getRdmPacket(); int universe = getUniverseFromPortAddress(artRdmPacket.getAddress()); - System.out.println("RECV: " + rdmPacket); RDMDeviceId destinationID = new RDMDeviceId(rdmPacket.getDestinationID()); if(!getProxyMap(universe).containsKey(destinationID) && !Arrays.equals(rdmPacket.getDestinationID(), RDM_DEVICE_ID)){ return; @@ -421,7 +433,6 @@ private void onPacketReceived(InetAddress sourceAddress, final ArtNetPacket pack return; } getCommandResponse.write(); - System.out.println("SEND: " + getCommandResponse); ArtRdmPacket sendArtRdmPacket = new ArtRdmPacket(); sendArtRdmPacket.setRdmPacket(getCommandResponse); sendArtRdmPacket.setNet(0); @@ -448,14 +459,13 @@ private void onPacketReceived(InetAddress sourceAddress, final ArtNetPacket pack setCommandResponse.setParameter(RDMParameter.DMX_START_ADDRESS); ch.bildspur.artnet.packets.ByteUtils inData = new ch.bildspur.artnet.packets.ByteUtils(rdmPacket.getParameterData()); int newAddress = inData.getInt16(0); - new RDMUpdateConsumer(universe, targetDevice.getDeviceId(), newAddress).sendToServer(); + new RDMUpdateConsumer(manager.getNetworkId(), universe, targetDevice.getDeviceId(), newAddress).sendToServer(); break; } default: break; } setCommandResponse.write(); - System.out.println("SEND: " + setCommandResponse); ArtRdmPacket sendArtRdmPacket = new ArtRdmPacket(); sendArtRdmPacket.setRdmPacket(setCommandResponse); sendArtRdmPacket.setNet(0); diff --git a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/ArtNetConfigurationScreen.java b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/ArtNetConfigurationScreen.java index de37f59..5591ebf 100644 --- a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/ArtNetConfigurationScreen.java +++ b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/ArtNetConfigurationScreen.java @@ -7,6 +7,7 @@ import dev.imabad.theatrical.config.ConfigHandler; import dev.imabad.theatrical.config.TheatricalConfig; import dev.imabad.theatrical.net.UpdateArtNetInterface; +import dev.imabad.theatrical.util.UUIDUtil; import net.minecraft.client.Minecraft; import net.minecraft.client.OptionInstance; import net.minecraft.client.gui.GuiGraphics; @@ -19,9 +20,9 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class ArtNetConfigurationScreen extends Screen { @@ -30,6 +31,7 @@ public class ArtNetConfigurationScreen extends Screen { private int[] universe; private String ipAddress; private boolean enabled; + private UUID networkId; private Screen lastScreen; private LinearLayout layout; @@ -42,6 +44,7 @@ public ArtNetConfigurationScreen(Screen lastScreen) { universe[3] = TheatricalConfig.INSTANCE.CLIENT.universe4; this.ipAddress = TheatricalConfig.INSTANCE.CLIENT.artNetIP; this.enabled = TheatricalConfig.INSTANCE.CLIENT.artnetEnabled; + this.networkId = TheatricalClient.getArtNetManager().getNetworkId(); this.lastScreen = lastScreen; } @@ -73,6 +76,20 @@ protected void init() { ).withValues(List.of(true, false)).displayOnlyValue().withInitialValue(enabled).create(xCenter, yCenter, 150, 20, Component.translatable("screen.artnetconfig.enabled"), (obj, val) -> { this.enabled = val; })); + layout.addChild(new CycleButton.Builder((networkId) -> + { + if (TheatricalClient.getArtNetManager().getKnownNetworks().containsKey(networkId)) { + return Component.literal(TheatricalClient.getArtNetManager().getKnownNetworks().get(networkId)); + } + return Component.literal("Unknown"); + } + ).withValues(CycleButton.ValueListSupplier.create(Stream.concat(Stream.of(UUIDUtil.NULL), + TheatricalClient.getArtNetManager().getKnownNetworks().keySet().stream()).collect(Collectors.toList()))) + .displayOnlyValue().withInitialValue(networkId) + .create(xCenter, yCenter, 150, 20, + Component.translatable("screen.artnetconfig.enabled"), (obj, val) -> { + this.networkId = val; + })); // layout.addChild(new Button.Builder( // , // button -> { @@ -150,6 +167,9 @@ private void update(){ } TheatricalConfig.INSTANCE.CLIENT.artNetIP = ipAddressBox.getValue(); TheatricalConfig.INSTANCE.CLIENT.artnetEnabled = enabled; + if(networkId != TheatricalClient.getArtNetManager().getNetworkId()) { + TheatricalClient.getArtNetManager().setNetworkId(networkId); + } ConfigHandler.INSTANCE.saveConfig(ConfigHandler.ConfigSide.CLIENT); boolean isInGame = Minecraft.getInstance().level != null; if(isInGame) { diff --git a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/ArtNetInterfaceScreen.java b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/ArtNetInterfaceScreen.java index 2f40736..cf83e7c 100644 --- a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/ArtNetInterfaceScreen.java +++ b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/ArtNetInterfaceScreen.java @@ -33,20 +33,20 @@ protected void init() { yCenter = (this.height - this.imageHeight) / 2; this.dmxUniverse = new EditBox(this.font, xCenter + 62, yCenter + 25, 50, 10, (Component)Component.translatable("artneti.dmxUniverse")); this.dmxUniverse.setValue(Integer.toString(this.be.getUniverse())); - this.dmxUniverse.setEditable(be.isOwnedByCurrentClient()); +// this.dmxUniverse.setEditable(be.isOwnedByCurrentClient()); this.addWidget(this.dmxUniverse); this.ipAddress = new EditBox(this.font, xCenter + 40, yCenter + 50, 100, 20, (Component)Component.translatable("artneti.ipAddress")); this.ipAddress.setValue(this.be.getIp()); - this.ipAddress.setEditable(be.isOwnedByCurrentClient()); +// this.ipAddress.setEditable(be.isOwnedByCurrentClient()); this.addWidget(this.ipAddress); - if(be.isOwnedByCurrentClient()) { - this.addRenderableWidget( - new Button.Builder(Component.translatable("artneti.save"), button -> this.update()) - .pos(xCenter + 40, yCenter + 90) - .size(100, 20) - .build() - ); - } +// if(be.isOwnedByCurrentClient()) { +// this.addRenderableWidget( +// new Button.Builder(Component.translatable("artneti.save"), button -> this.update()) +// .pos(xCenter + 40, yCenter + 90) +// .size(100, 20) +// .build() +// ); +// } } private void update(){ @@ -85,16 +85,16 @@ private void renderLabels(GuiGraphics guiGraphics) { renderLabel(guiGraphics, "block.theatrical.artnet_interface", 5,5); renderLabel(guiGraphics, "artneti.dmxUniverse", 0,15); renderLabel(guiGraphics, "artneti.ipAddress", 5,40); - if(!this.be.isOwnedByCurrentClient()){ +// if(!this.be.isOwnedByCurrentClient()){ renderLabel(guiGraphics, "artneti.notAuthorized", 5,75); - } else { - if(this.be.hasReceivedPacket()){ - long inSeconds = Math.round((float) (System.currentTimeMillis() - this.be.getLastReceivedPacket()) / 1000); - renderLabel(guiGraphics, "artneti.lastReceived", 5,75, inSeconds); - } else { - renderLabel(guiGraphics, "artneti.notConnected", 5,75); - } - } +// } else { +// if(this.be.hasReceivedPacket()){ +// long inSeconds = Math.round((float) (System.currentTimeMillis() - this.be.getLastReceivedPacket()) / 1000); +// renderLabel(guiGraphics, "artneti.lastReceived", 5,75, inSeconds); +// } else { +// renderLabel(guiGraphics, "artneti.notConnected", 5,75); +// } +// } } private void renderLabel(GuiGraphics guiGraphics, String translationKey, int offSetX, int offSetY, Object... replacements){ diff --git a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/BasicLightingDeskScreen.java b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/BasicLightingDeskScreen.java index 3132044..05c7036 100644 --- a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/BasicLightingDeskScreen.java +++ b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/BasicLightingDeskScreen.java @@ -2,20 +2,24 @@ import com.mojang.blaze3d.systems.RenderSystem; import dev.imabad.theatrical.Theatrical; +import dev.imabad.theatrical.TheatricalClient; import dev.imabad.theatrical.blockentities.control.BasicLightingDeskBlockEntity; import dev.imabad.theatrical.client.gui.widgets.FaderWidget; -import dev.imabad.theatrical.net.ControlGo; -import dev.imabad.theatrical.net.ControlModeToggle; -import dev.imabad.theatrical.net.ControlMoveStep; -import dev.imabad.theatrical.net.ControlUpdateFader; +import dev.imabad.theatrical.net.*; +import dev.imabad.theatrical.util.UUIDUtil; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.CycleButton; import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.ResourceLocation; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + public class BasicLightingDeskScreen extends Screen { private final ResourceLocation GUI = new ResourceLocation(Theatrical.MOD_ID, "textures/gui/lighting_console.png"); @@ -23,11 +27,13 @@ public class BasicLightingDeskScreen extends Screen { private int imageWidth, imageHeight, xCenter, yCenter; private BasicLightingDeskBlockEntity be; private EditBox fadeInTime, fadeOutTime; + private UUID networkId; public BasicLightingDeskScreen(BasicLightingDeskBlockEntity blockEntity) { super(Component.translatable("screen.basicLightingDesk")); this.imageWidth = 244; this.imageHeight = 126; this.be = blockEntity; + this.networkId = be.getNetworkId(); } @Override @@ -104,6 +110,21 @@ protected void init() { this.fadeOutTime.setValue(Integer.toString(be.getFadeOutTicks())); this.addRenderableWidget(fadeInTime); this.addRenderableWidget(fadeOutTime); + this.addRenderableWidget(new CycleButton.Builder((networkId) -> + { + if (TheatricalClient.getArtNetManager().getKnownNetworks().containsKey(networkId)) { + return Component.literal(TheatricalClient.getArtNetManager().getKnownNetworks().get(networkId)); + } + return Component.literal("Unknown"); + } + ).withValues(CycleButton.ValueListSupplier.create(Stream.concat(Stream.of(UUIDUtil.NULL), + TheatricalClient.getArtNetManager().getKnownNetworks().keySet().stream()).collect(Collectors.toList()))) + .displayOnlyValue().withInitialValue(networkId) + .create(xCenter, yCenter, 150, 20, + Component.translatable("screen.artnetconfig.network"), (obj, val) -> { + this.networkId = val; + new UpdateNetworkId(be.getBlockPos(), networkId).sendToServer(); + })); } private void moveStep(boolean forward){ diff --git a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/FresnelScreen.java b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/FresnelScreen.java index ccb3b32..b8d7da6 100644 --- a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/FresnelScreen.java +++ b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/FresnelScreen.java @@ -10,103 +10,46 @@ import net.minecraft.client.gui.components.AbstractSliderButton; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.StringWidget; +import net.minecraft.client.gui.layouts.LayoutSettings; import net.minecraft.client.gui.screens.Screen; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.ResourceLocation; -public class FresnelScreen extends Screen { - private final ResourceLocation GUI = new ResourceLocation(Theatrical.MOD_ID, "textures/gui/blank.png"); - - private int imageWidth, imageHeight, xCenter, yCenter; - private EditBox dmxAddress, dmxUniverse; +public class FresnelScreen extends GenericDMXConfigurationScreen { private BasicSlider tiltSlider, panSlider; - private FresnelBlockEntity be; + private final FresnelBlockEntity be; public FresnelScreen(FresnelBlockEntity be) { - super(Component.translatable("screen.fresnel")); - this.imageWidth = 176; - this.imageHeight = 126; + super(be, be.getBlockPos(), "block.theatrical.led_fresnel"); this.be = be; } @Override - protected void init() { - super.init(); - xCenter = (this.width - this.imageWidth) / 2; - yCenter = (this.height - this.imageHeight) / 2; - this.dmxAddress = new EditBox(this.font, xCenter + (((imageWidth / 2) / 2) - 25), yCenter + 25, 50, 10, Component.translatable("fixture.dmxStart")); - this.dmxAddress.setValue(Integer.toString(this.be.getChannelStart())); - this.dmxUniverse = new EditBox(this.font, xCenter + (imageWidth - (((imageWidth / 2) / 2) + 25)), yCenter + 25, 50, 10, Component.translatable("artneti.dmxUniverse")); - this.dmxUniverse.setValue(Integer.toString(this.be.getUniverse())); + public void addExtraWidgetsToUI() { this.tiltSlider = new BasicSlider(xCenter + 13, yCenter + 45, 150, 20, Component.empty(), be.getTilt(), -90, 90, (newTilt) -> { be.setTilt(newTilt.intValue()); }); - this.panSlider = new BasicSlider(xCenter + 13, yCenter + 75, 150, 20, Component.empty(), be.getPan(),-180, 180, (newPan) -> { + this.panSlider = new BasicSlider(xCenter, yCenter + 75, 150, 20, Component.empty(), be.getPan(),-180, 180, (newPan) -> { be.setPan(newPan.intValue()); }); - this.addRenderableWidget(this.dmxAddress); - this.addRenderableWidget(this.dmxUniverse); - this.addRenderableWidget(tiltSlider); - this.addRenderableWidget(panSlider); - this.addRenderableWidget( - new Button.Builder(Component.translatable("artneti.save"), button -> this.update()) - .pos(xCenter + 40, yCenter + 100) - .size(100, 20) - .build() - ); - } - - private void update() { - try { - int dmx = Integer.parseInt(this.dmxAddress.getValue()); - if (dmx > 512 || dmx < 0) { - return; - } - int universe = Integer.parseInt(this.dmxUniverse.getValue()); - if (universe > 16 || universe < 0) { - return; - } - new UpdateDMXFixture(be.getBlockPos(), dmx, universe).sendToServer(); - new UpdateFixturePosition(be.getBlockPos(), be.getTilt(), be.getPan()).sendToServer(); - } catch (NumberFormatException ignored) { - //We need a nicer way to show that this is invalid? - } - } - - @Override - public void renderBackground(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { - super.renderBackground(guiGraphics, mouseX, mouseY, partialTick); - this.renderWindow(guiGraphics); + LayoutSettings layoutSettings = layout.newCellSettings().paddingVertical(2); + layout.addChild(new StringWidget(Component.translatable("fixture.tilt"), font), layoutSettings); + layout.addChild(tiltSlider, layoutSettings); + layout.addChild(new StringWidget(Component.translatable("fixture.pan"), font), layoutSettings); + layout.addChild(panSlider, layoutSettings); } @Override - public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { - super.render(guiGraphics, mouseX, mouseY, partialTick); - this.renderLabels(guiGraphics); - } - - private void renderWindow(GuiGraphics guiGraphics) { - int relX = (this.width - this.imageWidth) / 2; - int relY = (this.height - this.imageHeight) / 2; - guiGraphics.blit(GUI, relX, relY, 0, 0, this.imageWidth, this.imageHeight); - } - - private void renderLabels(GuiGraphics guiGraphics) { - renderLabel(guiGraphics, "block.theatrical.led_fresnel", 5, 5); - renderLabel(guiGraphics, "fixture.dmxStart", -44, 15); - renderLabel(guiGraphics, "artneti.dmxUniverse", 44, 15); - renderLabel(guiGraphics, "fixture.tilt", 0, 36); - renderLabel(guiGraphics, "fixture.pan", 0, 66); - } - - private void renderLabel(GuiGraphics guiGraphics, String translationKey, int offSetX, int offSetY) { - MutableComponent translatable = Component.translatable(translationKey); - guiGraphics.drawString(font, translatable, xCenter + (this.imageWidth / 2) - (this.font.width(translatable.getString()) / 2) + offSetX, yCenter + offSetY, 0x404040, false); + protected void update() { + new UpdateFixturePosition(be.getBlockPos(), be.getTilt(), be.getPan()).sendToServer(); } @Override - public void tick() { -// this.dmxAddress.tick(); + protected void renderLabels(GuiGraphics guiGraphics) { + super.renderLabels(guiGraphics); +// renderLabel(guiGraphics, "fixture.tilt", 0, 36); +// renderLabel(guiGraphics, "fixture.pan", 0, 66); } } \ No newline at end of file diff --git a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/GenericDMXConfigurationScreen.java b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/GenericDMXConfigurationScreen.java index 67b0e58..f1f0bb9 100644 --- a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/GenericDMXConfigurationScreen.java +++ b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/GenericDMXConfigurationScreen.java @@ -1,29 +1,44 @@ package dev.imabad.theatrical.client.gui.screen; import dev.imabad.theatrical.Theatrical; +import dev.imabad.theatrical.TheatricalClient; import dev.imabad.theatrical.api.dmx.DMXConsumer; import dev.imabad.theatrical.blockentities.light.MovingLightBlockEntity; +import dev.imabad.theatrical.client.gui.widgets.LabeledEditBox; import dev.imabad.theatrical.net.UpdateDMXFixture; +import dev.imabad.theatrical.net.UpdateNetworkId; +import dev.imabad.theatrical.util.UUIDUtil; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.CycleButton; import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.StringWidget; +import net.minecraft.client.gui.layouts.FrameLayout; +import net.minecraft.client.gui.layouts.LinearLayout; import net.minecraft.client.gui.screens.Screen; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.ResourceLocation; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + public class GenericDMXConfigurationScreen extends Screen { private final ResourceLocation GUI = new ResourceLocation(Theatrical.MOD_ID, "textures/gui/blank.png"); - private final int imageWidth; - private final int imageHeight; - private int xCenter; - private int yCenter; - private EditBox dmxAddress, dmxUniverse; + protected final int imageWidth; + protected final int imageHeight; + protected int xCenter; + protected int yCenter; + private LabeledEditBox dmxAddress, dmxUniverse; + private UUID networkId; private final T be; private final BlockPos blockPos; private final String titleTranslationKey; + protected LinearLayout layout; public GenericDMXConfigurationScreen(T be, BlockPos pos, String titleTranslationKey) { super(Component.translatable(titleTranslationKey)); @@ -32,29 +47,61 @@ public GenericDMXConfigurationScreen(T be, BlockPos pos, String titleTranslation this.be = be; this.blockPos = pos; this.titleTranslationKey = titleTranslationKey; + this.networkId = be.getNetworkId(); } + public void addExtraWidgetsToUI(){} + @Override protected void init() { super.init(); - xCenter = (this.width - this.imageWidth) / 2; - yCenter = (this.height - this.imageHeight) / 2; - this.dmxAddress = new EditBox(this.font, xCenter + 62, yCenter + 25, 50, 10, Component.translatable("fixture.dmxStart")); + layout = new LinearLayout(imageWidth, 1, LinearLayout.Orientation.VERTICAL); + layout.defaultCellSetting().alignHorizontallyCenter().padding(10); + layout.addChild(new StringWidget(Component.translatable(titleTranslationKey), this.font)); + this.dmxAddress = new LabeledEditBox(this.font, xCenter, yCenter, 50, 10, Component.translatable("fixture.dmxStart")); this.dmxAddress.setValue(Integer.toString(this.be.getChannelStart())); - this.addRenderableWidget(this.dmxAddress); - - this.dmxUniverse = new EditBox(this.font, xCenter + 62, yCenter + 50, 50, 10, Component.translatable("artneti.dmxUniverse")); - this.dmxUniverse.setValue(Integer.toString(this.be.getUniverse())); - this.addRenderableWidget(this.dmxUniverse); - this.addRenderableWidget( + layout.addChild(dmxAddress); + this.dmxUniverse = new LabeledEditBox(this.font, xCenter, yCenter, 50, 10, Component.translatable("artneti.dmxUniverse")); + this.dmxUniverse.setValue(Integer.toString(this.be.getChannelStart())); + layout.addChild(dmxUniverse); + addExtraWidgetsToUI(); + layout.addChild(new CycleButton.Builder((networkId) -> + { + if (TheatricalClient.getArtNetManager().getKnownNetworks().containsKey(networkId)) { + return Component.literal(TheatricalClient.getArtNetManager().getKnownNetworks().get(networkId)); + } + return Component.literal("Unknown"); + } + ).withValues(CycleButton.ValueListSupplier.create(Stream.concat(Stream.of(UUIDUtil.NULL), + TheatricalClient.getArtNetManager().getKnownNetworks().keySet().stream()).collect(Collectors.toList()))) + .displayOnlyValue().withInitialValue(networkId) + .create(xCenter, yCenter, 150, 20, + Component.translatable("screen.artnetconfig.network"), (obj, val) -> { + this.networkId = val; + })); + layout.addChild( new Button.Builder(Component.translatable("artneti.save"), button -> this.update()) - .pos(xCenter + 40, yCenter + 90) + .pos(xCenter, yCenter) .size(100, 20) .build() ); + refreshLayout(); + this.repositionElements(); + + } + protected void refreshLayout(){ + if(layout == null) + return; + layout.arrangeElements(); + layout.visitWidgets(this::addRenderableWidget); } - private void update(){ + protected void repositionElements() { + FrameLayout.centerInRectangle(this.layout, this.getRectangle()); + } + + + protected void update(){ try { int dmx = Integer.parseInt(this.dmxAddress.getValue()); if (dmx > 512 || dmx < 0) { @@ -66,6 +113,7 @@ private void update(){ return; } new UpdateDMXFixture(blockPos, dmx, universe).sendToServer(); + new UpdateNetworkId(blockPos, networkId).sendToServer(); } catch(NumberFormatException ignored) { //We need a nicer way to show that this is invalid? } @@ -83,20 +131,29 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia } private void renderWindow(GuiGraphics guiGraphics){ + int layoutHeight = 0; + if(layout != null) { + layoutHeight = layout.getHeight(); + } int relX = (this.width - this.imageWidth) / 2; - int relY = (this.height - this.imageHeight) / 2; - guiGraphics.blit(GUI, relX, relY, 0, 0, this.imageWidth, this.imageHeight); + int relY = (this.height - layoutHeight) / 2; + guiGraphics.blit(GUI, relX, relY, imageWidth, layoutHeight, 0, 0, this.imageWidth, this.imageHeight, 256,256); } - private void renderLabels(GuiGraphics guiGraphics) { - renderLabel(guiGraphics, titleTranslationKey, 5,5); - renderLabel(guiGraphics, "fixture.dmxStart", 0,15); - renderLabel(guiGraphics, "artneti.dmxUniverse", 0,40); + protected void renderLabels(GuiGraphics guiGraphics) { +// renderLabel(guiGraphics, titleTranslationKey, 5,5); +// renderLabel(guiGraphics, "fixture.dmxStart", 0,15); +// renderLabel(guiGraphics, "artneti.dmxUniverse", 0,40); +// renderLabel(guiGraphics, "artneti.network", 0,60); } - private void renderLabel(GuiGraphics guiGraphics, String translationKey, int offSetX, int offSetY){ + protected void renderLabel(GuiGraphics guiGraphics, String translationKey, int offSetX, int offSetY){ MutableComponent translatable = Component.translatable(translationKey); guiGraphics.drawString(font, translatable, xCenter + (this.imageWidth / 2) - (this.font.width(translatable.getString()) / 2), yCenter + offSetY, 0x404040, false); } + @Override + public boolean isPauseScreen() { + return false; + } } diff --git a/common/src/main/java/dev/imabad/theatrical/client/gui/widgets/LabeledEditBox.java b/common/src/main/java/dev/imabad/theatrical/client/gui/widgets/LabeledEditBox.java index b3948fa..066ee46 100644 --- a/common/src/main/java/dev/imabad/theatrical/client/gui/widgets/LabeledEditBox.java +++ b/common/src/main/java/dev/imabad/theatrical/client/gui/widgets/LabeledEditBox.java @@ -3,11 +3,20 @@ import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.StringWidget; +import net.minecraft.locale.Language; +import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.FormattedText; +import net.minecraft.util.FormattedCharSequence; import org.jetbrains.annotations.Nullable; public class LabeledEditBox extends EditBox { + private float alignX = 0.5F; private Font font; + + private int color = 0xffffff; + public LabeledEditBox(Font font, int width, int height, Component message) { super(font, width, height, message); this.width = width + 10; @@ -28,13 +37,44 @@ public LabeledEditBox(Font font, int x, int y, int width, int height, @Nullable public int getHeight() { return super.getHeight(); } + private LabeledEditBox horizontalAlignment(float horizontalAlignment) { + this.alignX = horizontalAlignment; + return this; + } + + public LabeledEditBox alignLeft() { + return this.horizontalAlignment(0.0F); + } + + public LabeledEditBox alignCenter() { + return this.horizontalAlignment(0.5F); + } + + public LabeledEditBox alignRight() { + return this.horizontalAlignment(1.0F); + } + + public LabeledEditBox color(int color) { + this.color = color; + return this; + } @Override public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { super.renderWidget(guiGraphics, mouseX, mouseY, partialTick); - int k = this.isBordered() ? this.getX() + 4 : this.getX(); - int l = this.isBordered() ? this.getY() + (this.height - 8) / 2 : this.getY(); + Component component = this.getMessage(); + int i = this.getWidth(); + int j = font.width(component); + int k = this.getX() + Math.round(this.alignX * (float)(i - j)); + int l = this.getY() + (this.getHeight() - 9) / 2; + // j > i ? this.clipText(component, i) : + FormattedCharSequence formattedCharSequence = component.getVisualOrderText(); + guiGraphics.drawString(font, formattedCharSequence, k, l - (font.lineHeight), color); + } - guiGraphics.drawString(font, this.getMessage(), k, l - (font.lineHeight * 2), 0xffffff); + private FormattedCharSequence clipText(Component message, int width) { + Font font = this.font; + FormattedText formattedText = font.substrByWidth(message, width - font.width(CommonComponents.ELLIPSIS)); + return Language.getInstance().getVisualOrder(FormattedText.composite(formattedText, CommonComponents.ELLIPSIS)); } } diff --git a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java index f5ffe55..32a8d6e 100644 --- a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java +++ b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java @@ -168,4 +168,14 @@ public void addMember(UUID playerUUID, DMXNetworkMemberRole role){ public boolean isMember(UUID playerUUID){ return members.stream().anyMatch(x -> x.playerId().equals(playerUUID)); } + + public boolean canSendDMX(UUID uuid) { + Optional first = members.stream() + .filter(dmxNetworkMember -> dmxNetworkMember.playerId() == uuid).findFirst(); + if(first.isEmpty()){ + return false; + } + DMXNetworkMember dmxNetworkMember = first.get(); + return dmxNetworkMember.role() == DMXNetworkMemberRole.SEND || dmxNetworkMember.role() == DMXNetworkMemberRole.ADMIN; + } } diff --git a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkData.java b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkData.java index 2a80bbc..ead3a63 100644 --- a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkData.java +++ b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkData.java @@ -3,94 +3,175 @@ import ch.bildspur.artnet.rdm.RDMDeviceId; import dev.imabad.theatrical.api.dmx.DMXConsumer; import dev.imabad.theatrical.net.artnet.NotifyConsumerChange; +import dev.imabad.theatrical.net.artnet.NotifyNetworks; import io.netty.util.collection.IntObjectHashMap; import io.netty.util.collection.IntObjectMap; import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.saveddata.SavedData; +import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.stream.Collectors; -public class DMXNetworkData { - private static final DMXNetworkData INSTANCE = new DMXNetworkData(); - public static DMXNetworkData getInstance(){ - return INSTANCE; - } +public class DMXNetworkData extends SavedData { private final Set knownSenders = new HashSet<>(); - private final IntObjectMap> universeToNodeMap = new IntObjectHashMap<>(); - public void addConsumer(BlockPos pos, DMXConsumer consumer){ - Map universe = universeToNodeMap.computeIfAbsent(consumer.getUniverse(), (uni) -> new HashMap<>()); - universe.put(pos, consumer); - universeToNodeMap.put(consumer.getUniverse(), universe); - new NotifyConsumerChange(consumer.getUniverse(), - NotifyConsumerChange.ChangeType.ADD, - new DMXDevice( - consumer.getDeviceId(), consumer.getChannelStart(), consumer.getChannelCount(), - consumer.getDeviceTypeId(), consumer.getActivePersonality(), consumer.getModelName(), consumer.getFixtureId())) - .sendTo(knownSenders); - } + private final Map networks = new HashMap<>(); + private static final String KEY = "dmx_networks"; - public void updateConsumer(DMXConsumer consumer){ - new NotifyConsumerChange(consumer.getUniverse(), - NotifyConsumerChange.ChangeType.UPDATE, - new DMXDevice(consumer.getDeviceId(), consumer.getChannelStart(), consumer.getChannelCount(), - consumer.getDeviceTypeId(),consumer.getActivePersonality(), consumer.getModelName(), consumer.getFixtureId())) - .sendTo(knownSenders); + private static DMXNetworkData INSTANCE; + private static final SavedData.Factory factory = new Factory<>( + DMXNetworkData::new, + DMXNetworkData::read, + null + ); + public static DMXNetworkData getInstance(Level level){ + if(INSTANCE == null){ + INSTANCE = level.getServer() + .overworld().getDataStorage().computeIfAbsent(factory, KEY); + } + return INSTANCE; } - public void removeConsumer(DMXConsumer consumer, BlockPos pos){ - if(!universeToNodeMap.containsKey(consumer.getUniverse())){ - return; - } - Map universe = universeToNodeMap.get(consumer.getUniverse()); - universe.remove(pos); - new NotifyConsumerChange(consumer.getUniverse(), NotifyConsumerChange.ChangeType.REMOVE, - new DMXDevice(consumer.getDeviceId(), 0, 0,0, - 0, "", new ResourceLocation(""))) - .sendTo(knownSenders); + @Nullable + public DMXNetwork getNetwork(UUID networkId){ + return networks.get(networkId); } - public Collection getConsumers(int universe){ - if(universeToNodeMap.get(universe) != null) { - return universeToNodeMap.get(universe).values(); - } - return null; + + public DMXNetwork createNetwork(Player player){ + DMXNetwork network = new DMXNetwork(player.getName().getString() + "'s Network"); + network.addMember(player.getUUID(), DMXNetworkMemberRole.ADMIN); + networks.put(network.id(), network); + notifyNetworks(player); + return network; } - public BlockPos getConsumerPos(int universe, RDMDeviceId deviceId){ - for (Map.Entry blockPosDMXConsumerEntry : universeToNodeMap.get(universe).entrySet()) { - if(blockPosDMXConsumerEntry.getValue().getDeviceId().equals(deviceId)){ - return blockPosDMXConsumerEntry.getKey(); - } - } - return null; + public void notifyNetworks(Player player){ + Map collect = getNetworksForPlayer(player.getUUID()).stream().collect(Collectors.toMap(DMXNetwork::id, DMXNetwork::name)); + new NotifyNetworks(collect).sendTo((ServerPlayer) player); } - public Collection getConsumersInRange(int universe, BlockPos fromPos, int radius){ - Collection consumers = new HashSet<>(); - if(!universeToNodeMap.containsKey(universe) || universeToNodeMap.get(universe).isEmpty()){ - return consumers; - } - for(Map.Entry entry : universeToNodeMap.get(universe).entrySet()){ - if(Math.sqrt(fromPos.distToCenterSqr(entry.getKey().getX(), entry.getKey().getY(), entry.getKey().getZ())) <= radius){ - consumers.add(entry.getValue()); - } - } - return consumers; + public List getNetworksForPlayer(UUID player){ + return networks.values() + .stream().filter(dmxNetwork -> dmxNetwork.mode() == DMXNetworkMode.PUBLIC || dmxNetwork.isMember(player)) + .collect(Collectors.toList()); } - public Set getUniverses(){ - return universeToNodeMap.keySet(); + public Collection getAllNetworks(){ + return networks.values(); } - public void addKnownSender(ServerPlayer player){ - this.knownSenders.add(player); + public DMXNetwork getDefaultNetworkForPlayer(Player player){ + UUID uuid = player.getUUID(); + Optional first = networks.values() + .stream().filter(dmxNetwork -> { + return dmxNetwork.isMember(uuid); + }) + .findFirst(); + return first.orElseGet(() -> createNetwork(player)); } - public void removeKnownSender(ServerPlayer player){ - this.knownSenders.remove(player); + public static DMXNetworkData read(CompoundTag tag) { + DMXNetworkData data = new DMXNetworkData(); + ListTag networksTag = tag.getList("networks", Tag.TAG_COMPOUND); + for (Tag networkTag : networksTag) { + DMXNetwork network = new DMXNetwork((CompoundTag) networkTag); + data.networks.put(network.id(), network); + } + return data; } - public boolean isKnownSender(ServerPlayer player){ - return this.knownSenders.contains(player); + @Override + public CompoundTag save(CompoundTag compoundTag) { + ListTag networksTag = new ListTag(); + for (DMXNetwork value : networks.values()) { + networksTag.add(value.save()); + } + compoundTag.put("networks", networksTag); + return compoundTag; } + +// private final IntObjectMap> universeToNodeMap = new IntObjectHashMap<>(); +// public void addConsumer(BlockPos pos, DMXConsumer consumer){ +// Map universe = universeToNodeMap.computeIfAbsent(consumer.getUniverse(), (uni) -> new HashMap<>()); +// universe.put(pos, consumer); +// universeToNodeMap.put(consumer.getUniverse(), universe); +// new NotifyConsumerChange(consumer.getUniverse(), +// NotifyConsumerChange.ChangeType.ADD, +// new DMXDevice( +// consumer.getDeviceId(), consumer.getChannelStart(), consumer.getChannelCount(), +// consumer.getDeviceTypeId(), consumer.getActivePersonality(), consumer.getModelName(), consumer.getFixtureId())) +// .sendTo(knownSenders); +// } +// +// public void updateConsumer(DMXConsumer consumer){ +// new NotifyConsumerChange(consumer.getUniverse(), +// NotifyConsumerChange.ChangeType.UPDATE, +// new DMXDevice(consumer.getDeviceId(), consumer.getChannelStart(), consumer.getChannelCount(), +// consumer.getDeviceTypeId(),consumer.getActivePersonality(), consumer.getModelName(), consumer.getFixtureId())) +// .sendTo(knownSenders); +// } +// +// public void removeConsumer(DMXConsumer consumer, BlockPos pos){ +// if(!universeToNodeMap.containsKey(consumer.getUniverse())){ +// return; +// } +// Map universe = universeToNodeMap.get(consumer.getUniverse()); +// universe.remove(pos); +// new NotifyConsumerChange(consumer.getUniverse(), NotifyConsumerChange.ChangeType.REMOVE, +// new DMXDevice(consumer.getDeviceId(), 0, 0,0, +// 0, "", new ResourceLocation(""))) +// .sendTo(knownSenders); +// } +// public Collection getConsumers(int universe){ +// if(universeToNodeMap.get(universe) != null) { +// return universeToNodeMap.get(universe).values(); +// } +// return null; +// } +// +// public BlockPos getConsumerPos(int universe, RDMDeviceId deviceId){ +// for (Map.Entry blockPosDMXConsumerEntry : universeToNodeMap.get(universe).entrySet()) { +// if(blockPosDMXConsumerEntry.getValue().getDeviceId().equals(deviceId)){ +// return blockPosDMXConsumerEntry.getKey(); +// } +// } +// return null; +// } +// +// public Collection getConsumersInRange(int universe, BlockPos fromPos, int radius){ +// Collection consumers = new HashSet<>(); +// if(!universeToNodeMap.containsKey(universe) || universeToNodeMap.get(universe).isEmpty()){ +// return consumers; +// } +// for(Map.Entry entry : universeToNodeMap.get(universe).entrySet()){ +// if(Math.sqrt(fromPos.distToCenterSqr(entry.getKey().getX(), entry.getKey().getY(), entry.getKey().getZ())) <= radius){ +// consumers.add(entry.getValue()); +// } +// } +// return consumers; +// } +// +// public Set getUniverses(){ +// return universeToNodeMap.keySet(); +// } +// +// public void addKnownSender(ServerPlayer player){ +// this.knownSenders.add(player); +// } +// +// public void removeKnownSender(ServerPlayer player){ +// this.knownSenders.remove(player); +// } +// +// public boolean isKnownSender(ServerPlayer player){ +// return this.knownSenders.contains(player); +// } } diff --git a/common/src/main/java/dev/imabad/theatrical/mixin/client/OptionsScreenMixin.java b/common/src/main/java/dev/imabad/theatrical/mixin/client/OptionsScreenMixin.java index b96c20f..c9d95a6 100644 --- a/common/src/main/java/dev/imabad/theatrical/mixin/client/OptionsScreenMixin.java +++ b/common/src/main/java/dev/imabad/theatrical/mixin/client/OptionsScreenMixin.java @@ -1,6 +1,7 @@ package dev.imabad.theatrical.mixin.client; import dev.imabad.theatrical.client.gui.screen.ArtNetConfigurationScreen; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.layouts.GridLayout; import net.minecraft.client.gui.screens.OptionsScreen; @@ -28,7 +29,9 @@ protected OptionsScreenMixin(Component title) { @Inject(method = "init()V", at = @At(value = "INVOKE", target="Lnet/minecraft/client/gui/layouts/GridLayout$RowHelper;addChild(Lnet/minecraft/client/gui/layouts/LayoutElement;ILnet/minecraft/client/gui/layouts/LayoutSettings;)Lnet/minecraft/client/gui/layouts/LayoutElement;"), locals = LocalCapture.CAPTURE_FAILHARD) private void onCreatePauseMenu(CallbackInfo ci, GridLayout gridLayout, GridLayout.RowHelper rowHelper){ - rowHelper.addChild(this.openScreenButton(Component.translatable("button.artnetconfig"), () -> new ArtNetConfigurationScreen((OptionsScreen)(Object) this))); + if(Minecraft.getInstance().level != null) { + rowHelper.addChild(this.openScreenButton(Component.translatable("button.artnetconfig"), () -> new ArtNetConfigurationScreen((OptionsScreen) (Object) this))); + } } } diff --git a/common/src/main/java/dev/imabad/theatrical/net/TheatricalNet.java b/common/src/main/java/dev/imabad/theatrical/net/TheatricalNet.java index 2cff569..fb324d6 100644 --- a/common/src/main/java/dev/imabad/theatrical/net/TheatricalNet.java +++ b/common/src/main/java/dev/imabad/theatrical/net/TheatricalNet.java @@ -18,10 +18,13 @@ public interface TheatricalNet { MessageType CONTROL_MOVE_STEP = MAIN.registerC2S("control_move_step", ControlMoveStep::new); MessageType CONTROL_MODE_TOGGLE = MAIN.registerC2S("control_mode_toggle", ControlModeToggle::new); MessageType CONTROL_GO = MAIN.registerC2S("control_go", ControlGo::new); + MessageType REQUEST_NETWORKS = MAIN.registerC2S("request_networks", RequestNetworks::new); + MessageType UPDATE_NETWORK_ID = MAIN.registerC2S("update_network_id", UpdateNetworkId::new); // S2C MessageType NOTIFY_CONSUMER_CHANGE = MAIN.registerS2C("notify_consumer_change", NotifyConsumerChange::new); MessageType LIST_CONSUMERS = MAIN.registerS2C("list_consumers", ListConsumers::new); + MessageType NOTIFY_NETWORKS = MAIN.registerS2C("notify_networks", NotifyNetworks::new); static void init(){} } diff --git a/common/src/main/java/dev/imabad/theatrical/net/UpdateArtNetInterface.java b/common/src/main/java/dev/imabad/theatrical/net/UpdateArtNetInterface.java index cf51495..9257250 100644 --- a/common/src/main/java/dev/imabad/theatrical/net/UpdateArtNetInterface.java +++ b/common/src/main/java/dev/imabad/theatrical/net/UpdateArtNetInterface.java @@ -42,9 +42,9 @@ public void write(FriendlyByteBuf buf) { public void handle(NetworkManager.PacketContext context) { BlockEntity be = context.getPlayer().level().getBlockEntity(pos); if(be instanceof ArtNetInterfaceBlockEntity artNetInterfaceBlockEntity){ - if(artNetInterfaceBlockEntity.getOwnerUUID().equals(context.getPlayer().getUUID())){ - artNetInterfaceBlockEntity.updateConfig(ipAddress, dmxUniverse); - } +// if(artNetInterfaceBlockEntity.getOwnerUUID().equals(context.getPlayer().getUUID())){ +// artNetInterfaceBlockEntity.updateConfig(ipAddress, dmxUniverse); +// } } } } diff --git a/common/src/main/java/dev/imabad/theatrical/net/UpdateDMXFixture.java b/common/src/main/java/dev/imabad/theatrical/net/UpdateDMXFixture.java index 35906d9..8a85056 100644 --- a/common/src/main/java/dev/imabad/theatrical/net/UpdateDMXFixture.java +++ b/common/src/main/java/dev/imabad/theatrical/net/UpdateDMXFixture.java @@ -9,6 +9,8 @@ import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.level.block.entity.BlockEntity; +import java.util.UUID; + public class UpdateDMXFixture extends BaseC2SMessage { private BlockPos pos; diff --git a/common/src/main/java/dev/imabad/theatrical/net/UpdateNetworkId.java b/common/src/main/java/dev/imabad/theatrical/net/UpdateNetworkId.java new file mode 100644 index 0000000..b810764 --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/net/UpdateNetworkId.java @@ -0,0 +1,46 @@ +package dev.imabad.theatrical.net; + +import dev.architectury.networking.NetworkManager; +import dev.architectury.networking.simple.BaseC2SMessage; +import dev.architectury.networking.simple.MessageType; +import dev.imabad.theatrical.api.dmx.BelongsToNetwork; +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.level.block.entity.BlockEntity; + +import java.util.UUID; + +public class UpdateNetworkId extends BaseC2SMessage { + + private BlockPos blockPos; + private UUID networkId; + + public UpdateNetworkId(BlockPos blockPos, UUID networkId) { + this.blockPos = blockPos; + this.networkId = networkId; + } + + UpdateNetworkId(FriendlyByteBuf friendlyByteBuf){ + blockPos = friendlyByteBuf.readBlockPos(); + networkId = friendlyByteBuf.readUUID(); + } + + @Override + public MessageType getType() { + return TheatricalNet.UPDATE_NETWORK_ID; + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeBlockPos(blockPos); + buf.writeUUID(networkId); + } + + @Override + public void handle(NetworkManager.PacketContext context) { + BlockEntity be = context.getPlayer().level().getBlockEntity(blockPos); + if(be instanceof BelongsToNetwork belongsToNetwork){ + belongsToNetwork.setNetworkId(networkId); + } + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/net/artnet/RDMUpdateConsumer.java b/common/src/main/java/dev/imabad/theatrical/net/artnet/RDMUpdateConsumer.java index 643ea58..8ea7882 100644 --- a/common/src/main/java/dev/imabad/theatrical/net/artnet/RDMUpdateConsumer.java +++ b/common/src/main/java/dev/imabad/theatrical/net/artnet/RDMUpdateConsumer.java @@ -7,27 +7,32 @@ import dev.imabad.theatrical.Theatrical; import dev.imabad.theatrical.blockentities.interfaces.RedstoneInterfaceBlockEntity; import dev.imabad.theatrical.blockentities.light.BaseDMXConsumerLightBlockEntity; -import dev.imabad.theatrical.dmx.DMXDevice; +import dev.imabad.theatrical.dmx.DMXNetwork; import dev.imabad.theatrical.dmx.DMXNetworkData; import dev.imabad.theatrical.net.TheatricalNet; import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; +import java.util.UUID; + public class RDMUpdateConsumer extends BaseC2SMessage { - private int universe, newAddress;; - private RDMDeviceId dmxDevice; + private final UUID networkId; + private final int universe; + private final int newAddress; + private final RDMDeviceId dmxDevice; - public RDMUpdateConsumer(int universe, RDMDeviceId dmxDevice, int newAddress){ + public RDMUpdateConsumer(UUID networkId, int universe, RDMDeviceId dmxDevice, int newAddress){ + this.networkId = networkId; this.universe = universe; this.dmxDevice = dmxDevice; this.newAddress = newAddress; } public RDMUpdateConsumer(FriendlyByteBuf buf){ + networkId = buf.readUUID(); universe = buf.readInt(); dmxDevice = new RDMDeviceId(buf.readByteArray(6)); newAddress = buf.readInt(); @@ -40,6 +45,7 @@ public MessageType getType() { @Override public void write(FriendlyByteBuf buf) { + buf.writeUUID(networkId); buf.writeInt(universe); buf.writeByteArray(dmxDevice.toBytes()); buf.writeInt(newAddress); @@ -50,7 +56,11 @@ public void handle(NetworkManager.PacketContext context) { Level level = context.getPlayer().level(); if(level.getServer() != null ) { if (context.getPlayer().hasPermissions(level.getServer().getOperatorUserPermissionLevel())) { - BlockPos consumerPos = DMXNetworkData.getInstance().getConsumerPos(universe, dmxDevice); + DMXNetwork network = DMXNetworkData.getInstance(level).getNetwork(networkId); + if(network == null){ + return; + } + BlockPos consumerPos = network.getConsumerPos(universe, dmxDevice); if(consumerPos != null){ BlockEntity be = context.getPlayer().level().getBlockEntity(consumerPos); if(be instanceof BaseDMXConsumerLightBlockEntity dmxConsumerLightBlock){ diff --git a/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestConsumers.java b/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestConsumers.java index 37d1320..ab34f41 100644 --- a/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestConsumers.java +++ b/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestConsumers.java @@ -6,6 +6,7 @@ import dev.imabad.theatrical.Theatrical; import dev.imabad.theatrical.api.dmx.DMXConsumer; import dev.imabad.theatrical.dmx.DMXDevice; +import dev.imabad.theatrical.dmx.DMXNetwork; import dev.imabad.theatrical.dmx.DMXNetworkData; import dev.imabad.theatrical.net.TheatricalNet; import net.minecraft.network.FriendlyByteBuf; @@ -15,16 +16,20 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.UUID; public class RequestConsumers extends BaseC2SMessage { - private int universe; + private final UUID networkId; + private final int universe; - public RequestConsumers(int universe){ + public RequestConsumers(UUID networkId, int universe){ + this.networkId = networkId; this.universe = universe; } public RequestConsumers(FriendlyByteBuf byteBuf){ + networkId = byteBuf.readUUID(); universe = byteBuf.readInt(); } @@ -35,6 +40,7 @@ public MessageType getType() { @Override public void write(FriendlyByteBuf buf) { + buf.writeUUID(networkId); buf.writeInt(universe); } @@ -43,9 +49,10 @@ public void handle(NetworkManager.PacketContext context) { Level level = context.getPlayer().level(); if(level.getServer() != null ) { if (context.getPlayer().hasPermissions(level.getServer().getOperatorUserPermissionLevel())) { - if(DMXNetworkData.getInstance().isKnownSender((ServerPlayer) context.getPlayer())){ + DMXNetwork network = DMXNetworkData.getInstance(level).getNetwork(networkId); + if(network != null && network.isMember(context.getPlayer().getUUID())){ List devices = new ArrayList<>(); - Collection consumers = DMXNetworkData.getInstance().getConsumers(universe); + Collection consumers = network.getConsumers(universe); if(consumers == null){ return; } diff --git a/common/src/main/java/dev/imabad/theatrical/net/artnet/SendArtNetData.java b/common/src/main/java/dev/imabad/theatrical/net/artnet/SendArtNetData.java index 5b91bda..1867779 100644 --- a/common/src/main/java/dev/imabad/theatrical/net/artnet/SendArtNetData.java +++ b/common/src/main/java/dev/imabad/theatrical/net/artnet/SendArtNetData.java @@ -4,25 +4,28 @@ import dev.architectury.networking.simple.BaseC2SMessage; import dev.architectury.networking.simple.MessageType; import dev.imabad.theatrical.Theatrical; -import dev.imabad.theatrical.blockentities.interfaces.ArtNetInterfaceBlockEntity; +import dev.imabad.theatrical.dmx.DMXNetwork; import dev.imabad.theatrical.dmx.DMXNetworkData; import dev.imabad.theatrical.net.TheatricalNet; -import net.minecraft.core.BlockPos; import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; + +import java.util.UUID; public class SendArtNetData extends BaseC2SMessage { - private int universe; - private byte[] artNetData; - public SendArtNetData(int universe, byte[] data){ + private final UUID networkId; + private final int universe; + private final byte[] artNetData; + + public SendArtNetData(UUID networkId, int universe, byte[] data){ + this.networkId = networkId; this.universe = universe; artNetData = data; } public SendArtNetData(FriendlyByteBuf buf){ + networkId = buf.readUUID(); universe = buf.readInt(); artNetData = buf.readByteArray(); } @@ -34,6 +37,7 @@ public MessageType getType() { @Override public void write(FriendlyByteBuf buf) { + buf.writeUUID(networkId); buf.writeInt(universe); buf.writeByteArray(artNetData); } @@ -41,14 +45,19 @@ public void write(FriendlyByteBuf buf) { @Override public void handle(NetworkManager.PacketContext context) { Level level = context.getPlayer().level(); - if(level.getServer() != null ) { - if (context.getPlayer().hasPermissions(level.getServer().getOperatorUserPermissionLevel())) { - DMXNetworkData.getInstance().getConsumers(universe).forEach(consumer -> { - consumer.consume(artNetData); - }); - DMXNetworkData.getInstance().addKnownSender((ServerPlayer) context.getPlayer()); + if(level.getServer() != null) { + DMXNetwork network = DMXNetworkData.getInstance(level).getNetwork(networkId); + UUID uuid = context.getPlayer().getUUID(); + if(network != null) { + if (network.isMember(uuid) && network.canSendDMX(uuid)) { + network.getConsumers(universe).forEach(consumer -> { + consumer.consume(artNetData); + }); + } else { + Theatrical.LOGGER.info("{} tried to send ArtNet data to a network ({}) that they don't have permissions for", context.getPlayer().getName(), network.name()); + } } else { - Theatrical.LOGGER.info("{} tried to send ArtNet data but is not authorized!", context.getPlayer().getName()); + Theatrical.LOGGER.info("{} tried to send ArtNet data to a network that doesn't exist.", context.getPlayer().getName()); } } } diff --git a/common/src/main/java/dev/imabad/theatrical/protocols/artnet/ArtNetManager.java b/common/src/main/java/dev/imabad/theatrical/protocols/artnet/ArtNetManager.java deleted file mode 100644 index f1349e8..0000000 --- a/common/src/main/java/dev/imabad/theatrical/protocols/artnet/ArtNetManager.java +++ /dev/null @@ -1,42 +0,0 @@ -package dev.imabad.theatrical.protocols.artnet; - -import ch.bildspur.artnet.ArtNetClient; -import dev.imabad.theatrical.TheatricalClient; -import dev.imabad.theatrical.config.TheatricalConfig; -import dev.imabad.theatrical.dmx.TheatricalArtNetClient; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.HashMap; - -public class ArtNetManager { - - private TheatricalArtNetClient artNetClient; - - public TheatricalArtNetClient getClient(){ - if(this.artNetClient == null){ - this.artNetClient = newClient(); - } - return this.artNetClient; - } - - private TheatricalArtNetClient newClient(){ - try { - InetAddress byName = InetAddress.getByName(TheatricalConfig.INSTANCE.CLIENT.artNetIP); - TheatricalArtNetClient client = new TheatricalArtNetClient(byName); - client.start(byName); - return client; - } catch (UnknownHostException var3) { - var3.printStackTrace(); - } - return null; - } - - public void shutdownAll(){ - if(artNetClient == null){ - return; - } - artNetClient.stop(); - artNetClient = null; - } -} From dfb7a1fe2a94ffd7c6add716c458c73b045b9d9e Mon Sep 17 00:00:00 2001 From: Stuart Pomeroy Date: Mon, 29 Jul 2024 23:53:32 +0100 Subject: [PATCH 3/5] more commands, need to list devices and create configuration card next --- .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 4 +- .../assets/theatrical/lang/en_us.json | 14 + .../dev/imabad/theatrical/Theatrical.java | 88 ++--- .../control/BasicLightingDeskBlockEntity.java | 4 +- .../ArtNetInterfaceBlockEntity.java | 2 +- .../RedstoneInterfaceBlockEntity.java | 6 +- .../BaseDMXConsumerLightBlockEntity.java | 6 +- .../blocks/light/BaseLightBlock.java | 2 +- .../gui/screen/BasicLightingDeskScreen.java | 2 +- .../theatrical/commands/CommandArguments.java | 15 + .../commands/DMXNetworkModeArgument.java | 48 +++ .../commands/MemberRoleArgument.java | 49 +++ .../theatrical/commands/NetworkCommand.java | 342 ++++++++++++++++++ .../dev/imabad/theatrical/dmx/DMXNetwork.java | 50 ++- .../imabad/theatrical/dmx/DMXNetworkData.java | 35 +- .../theatrical/dmx/DMXNetworkMember.java | 44 ++- .../theatrical/dmx/DMXNetworkMemberRole.java | 35 +- .../imabad/theatrical/dmx/DMXNetworkMode.java | 34 +- .../mixin/ArgumentTypeInfosAccessor.java | 18 + .../net/artnet/RDMUpdateConsumer.java | 2 +- .../net/artnet/RequestConsumers.java | 2 +- .../net/artnet/RequestNetworks.java | 2 +- .../theatrical/net/artnet/SendArtNetData.java | 2 +- .../resources/theatrical-common.mixins.json | 1 + .../imabad/theatrical/neoforge/DataEvent.java | 12 + 25 files changed, 720 insertions(+), 99 deletions(-) create mode 100644 common/src/main/java/dev/imabad/theatrical/commands/CommandArguments.java create mode 100644 common/src/main/java/dev/imabad/theatrical/commands/DMXNetworkModeArgument.java create mode 100644 common/src/main/java/dev/imabad/theatrical/commands/MemberRoleArgument.java create mode 100644 common/src/main/java/dev/imabad/theatrical/commands/NetworkCommand.java create mode 100644 common/src/main/java/dev/imabad/theatrical/mixin/ArgumentTypeInfosAccessor.java diff --git a/common/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/common/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index f2699fa..6cba800 100644 --- a/common/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/common/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.20.2 2024-07-20T12:53:36.9764242 Languages: en_us -e3979f69d6f26453fdf1227dc1d640cc4143c3ff assets/theatrical/lang/en_us.json +// 1.20.2 2024-07-29T23:11:39.1659592 Languages: en_us +51f24e3b8b2d0667dec3cce6b38b13b241264dc8 assets/theatrical/lang/en_us.json diff --git a/common/src/generated/resources/assets/theatrical/lang/en_us.json b/common/src/generated/resources/assets/theatrical/lang/en_us.json index 52058cc..f6bec6a 100644 --- a/common/src/generated/resources/assets/theatrical/lang/en_us.json +++ b/common/src/generated/resources/assets/theatrical/lang/en_us.json @@ -14,10 +14,24 @@ "block.theatrical.redstone_interface": "Redstone Interface", "block.theatrical.tank_trap": "Tank Trap", "block.theatrical.truss": "MT100 Truss", + "button.artnetconfig": "ArtNet Config", + "commands.network": "%s (%s) has %s member(s)", + "commands.network.created": "Network created", + "commands.network.deleted": "Network deleted", + "commands.network.invalid": "Unknown network mode: %s", + "commands.network.members": "There are %s network member(s): %s.", + "commands.network.members.add.failed": "Player already member of network.", + "commands.network.members.add.success": "Added %s to the network.", + "commands.network.members.remove.success": "Removed %s from the network.", + "commands.network.notfound": "Network not found.", + "commands.network.role.invalid": "Unknown member role: %s", + "commands.network.updated": "Network updated", + "commands.networks": "There are %s network(s): %s.", "fixture.dmxStart": "DMX Address", "fixture.pan": "Pan", "fixture.tilt": "Tilt", "itemGroup.theatrical": "Theatrical", + "screen.artnetconfig.enabled": "ArtNet Enabled: %s", "screen.movinglight": "Moving Light", "ui.control.cue": "Cue - %s", "ui.control.cues": "Cues", diff --git a/common/src/main/java/dev/imabad/theatrical/Theatrical.java b/common/src/main/java/dev/imabad/theatrical/Theatrical.java index 1e11348..51e9bf2 100644 --- a/common/src/main/java/dev/imabad/theatrical/Theatrical.java +++ b/common/src/main/java/dev/imabad/theatrical/Theatrical.java @@ -1,41 +1,40 @@ package dev.imabad.theatrical; -import com.mojang.authlib.GameProfile; -import com.mojang.brigadier.arguments.StringArgumentType; import dev.architectury.event.events.common.CommandRegistrationEvent; +import dev.architectury.event.events.common.LifecycleEvent; import dev.architectury.event.events.common.PlayerEvent; import dev.architectury.platform.Platform; import dev.architectury.registry.CreativeTabRegistry; import dev.architectury.registry.registries.DeferredRegister; +import dev.architectury.registry.registries.Registrar; import dev.architectury.registry.registries.RegistrySupplier; import dev.imabad.theatrical.blockentities.BlockEntities; import dev.imabad.theatrical.blocks.Blocks; +import dev.imabad.theatrical.commands.CommandArguments; +import dev.imabad.theatrical.commands.DMXNetworkModeArgument; +import dev.imabad.theatrical.commands.MemberRoleArgument; +import dev.imabad.theatrical.commands.NetworkCommand; import dev.imabad.theatrical.config.ConfigHandler; import dev.imabad.theatrical.config.TheatricalConfig; -import dev.imabad.theatrical.dmx.DMXDevice; -import dev.imabad.theatrical.dmx.DMXNetwork; -import dev.imabad.theatrical.dmx.DMXNetworkData; -import dev.imabad.theatrical.dmx.DMXNetworkMember; +import dev.imabad.theatrical.dmx.*; import dev.imabad.theatrical.fixtures.Fixtures; import dev.imabad.theatrical.items.Items; +import dev.imabad.theatrical.mixin.ArgumentTypeInfosAccessor; import dev.imabad.theatrical.net.artnet.ListConsumers; import dev.imabad.theatrical.net.TheatricalNet; -import net.minecraft.commands.Commands; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.commands.synchronization.SingletonArgumentInfo; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; -import net.minecraft.server.players.GameProfileCache; -import net.minecraft.util.Tuple; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.swing.text.html.Option; import java.util.ArrayList; import java.util.List; -import java.util.Optional; -import java.util.UUID; -import java.util.stream.Collectors; public class Theatrical { public static final String MOD_ID = "theatrical"; @@ -60,6 +59,11 @@ public static void init() { TheatricalNet.init(); Blocks.BLOCKS.register(); BlockEntities.BLOCK_ENTITIES.register(); + + DeferredRegister> argTypes = TheatricalRegistry.get(Registries.COMMAND_ARGUMENT_TYPE); + registerArgument(argTypes, SingletonArgumentInfo.contextFree(DMXNetworkModeArgument::networkMode), "network_mode", DMXNetworkModeArgument.class); + registerArgument(argTypes, SingletonArgumentInfo.contextFree(MemberRoleArgument::memberRole), "member_role", MemberRoleArgument.class); + dev.imabad.theatrical.items.Items.ITEMS.register(); PlayerEvent.PLAYER_JOIN.register((event) -> { DMXNetworkData instance = DMXNetworkData.getInstance(event.server.overworld()); @@ -75,53 +79,19 @@ public static void init() { } } }); + LifecycleEvent.SERVER_LEVEL_UNLOAD.register(world -> { + if(world.dimension().equals(Level.OVERWORLD)){ + DMXNetworkData.unloadLevel(); + } + }); CommandRegistrationEvent.EVENT.register((dispatcher, registry, selection) -> { - dispatcher.register(Commands.literal("theatrical") - .then(Commands.literal("networks") - .executes(context -> { - DMXNetworkData instance = DMXNetworkData. - getInstance(context.getSource().getServer().overworld()); - String networks; - if(context.getSource().hasPermission(context.getSource().getServer().getOperatorUserPermissionLevel())){ - networks = instance.getAllNetworks().stream() - .map(DMXNetwork::name).collect(Collectors.joining(",")); - } else { - networks = instance.getNetworksForPlayer(context.getSource().getPlayer().getUUID()).stream() - .map(DMXNetwork::name).collect(Collectors.joining(",")); - } - context.getSource().sendSystemMessage(Component.literal("Networks: " + networks)); - return 1; - }) - ) - .then(Commands.literal("network") - .then(Commands.argument("id", StringArgumentType.string()) - .then(Commands.literal("members") - .executes(context -> { - DMXNetworkData instance = DMXNetworkData. - getInstance(context.getSource().getServer().overworld()); - try { - String id = context.getArgument("id", String.class); - UUID uuid = UUID.fromString(id); - DMXNetwork network = instance.getNetwork(uuid); - if(network != null) { - GameProfileCache profileCache = context.getSource().getServer().getProfileCache(); - String collect = network.members() - .stream().map(DMXNetworkMember::playerId) - .map((playerUUID) -> new Tuple<>(playerUUID, profileCache.get(playerUUID))) - .map(uuidOptionalTuple -> uuidOptionalTuple.getB().isPresent() ? uuidOptionalTuple.getB().get().getName() : uuidOptionalTuple.getA().toString()) - .toList().stream().collect(Collectors.joining(",")); - context.getSource().sendSystemMessage(Component.literal("Members: " + collect)); - } - } catch (Exception e){ - context.getSource().sendSystemMessage(Component.literal("Invalid network")); - return -1; - } - return 1; - }) - ) - ) - ) - ); + NetworkCommand.register(dispatcher); }); } + + private static void registerArgument(DeferredRegister> argTypes, + ArgumentTypeInfo serializer, String id, Class clazz) { + argTypes.register(new ResourceLocation(Theatrical.MOD_ID, id), () -> serializer); + ArgumentTypeInfosAccessor.classMap().put(clazz, serializer); + } } diff --git a/common/src/main/java/dev/imabad/theatrical/blockentities/control/BasicLightingDeskBlockEntity.java b/common/src/main/java/dev/imabad/theatrical/blockentities/control/BasicLightingDeskBlockEntity.java index 48e77f1..76260b2 100644 --- a/common/src/main/java/dev/imabad/theatrical/blockentities/control/BasicLightingDeskBlockEntity.java +++ b/common/src/main/java/dev/imabad/theatrical/blockentities/control/BasicLightingDeskBlockEntity.java @@ -119,7 +119,7 @@ public void tick(){ public void update(byte[] data) { if(level != null && level.getServer() != null) { - var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); + var dmxData = DMXNetworkData.getInstance(level.getServer().overworld()).getNetwork(networkId); if(dmxData != null) { dmxData.getConsumers(universe).forEach(consumer -> consumer.consume(data)); } @@ -195,6 +195,7 @@ public void read(CompoundTag compoundTag) { public void setFaders(byte[] faders){ this.faders = Arrays.copyOf(faders, faders.length); + setChanged(); } public void setFader(int fader, int value){ @@ -203,6 +204,7 @@ public void setFader(int fader, int value){ } else { this.grandMaster = (byte) value; } + setChanged(); } public int getCurrentStep() { diff --git a/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/ArtNetInterfaceBlockEntity.java b/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/ArtNetInterfaceBlockEntity.java index fa38c18..af4b051 100644 --- a/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/ArtNetInterfaceBlockEntity.java +++ b/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/ArtNetInterfaceBlockEntity.java @@ -59,7 +59,7 @@ public void read(CompoundTag compoundTag) { public void update(byte[] data) { if(level != null && level.getServer() != null) { - var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); + var dmxData = DMXNetworkData.getInstance(level.getServer().overworld()).getNetwork(networkId); if(dmxData != null) { dmxData.getConsumersInRange(universe, getBlockPos(), TheatricalConfig.INSTANCE.COMMON.wirelessDMXRadius).forEach(dmxConsumer -> dmxConsumer.consume(data)); } diff --git a/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/RedstoneInterfaceBlockEntity.java b/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/RedstoneInterfaceBlockEntity.java index cd4431f..4b62732 100644 --- a/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/RedstoneInterfaceBlockEntity.java +++ b/common/src/main/java/dev/imabad/theatrical/blockentities/interfaces/RedstoneInterfaceBlockEntity.java @@ -162,14 +162,14 @@ public void setUniverse(int universe) { } private void updateConsumer(){ - var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); + var dmxData = DMXNetworkData.getInstance(level.getServer().overworld()).getNetwork(networkId); if (dmxData != null) { dmxData.updateConsumer(this); } } private void addConsumer(){ - var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); + var dmxData = DMXNetworkData.getInstance(level.getServer().overworld()).getNetwork(networkId); if (dmxData != null) { if(deviceId == null){ generateDeviceId(); @@ -179,7 +179,7 @@ private void addConsumer(){ } private void removeConsumer(){ - var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); + var dmxData = DMXNetworkData.getInstance(level.getServer().overworld()).getNetwork(networkId); if (dmxData != null) { dmxData.removeConsumer(this, getBlockPos()); } diff --git a/common/src/main/java/dev/imabad/theatrical/blockentities/light/BaseDMXConsumerLightBlockEntity.java b/common/src/main/java/dev/imabad/theatrical/blockentities/light/BaseDMXConsumerLightBlockEntity.java index 09a241f..9124eeb 100644 --- a/common/src/main/java/dev/imabad/theatrical/blockentities/light/BaseDMXConsumerLightBlockEntity.java +++ b/common/src/main/java/dev/imabad/theatrical/blockentities/light/BaseDMXConsumerLightBlockEntity.java @@ -117,19 +117,19 @@ public void setChannelStartPoint(int channelStartPoint) { level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); } private void updateConsumer(){ - var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); + var dmxData = DMXNetworkData.getInstance(level.getServer().overworld()).getNetwork(networkId); if (dmxData != null) { dmxData.updateConsumer(this); } } private void removeConsumer(){ - var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); + var dmxData = DMXNetworkData.getInstance(level.getServer().overworld()).getNetwork(networkId); if (dmxData != null) { dmxData.removeConsumer(this, getBlockPos()); } } private void addConsumer(){ - var dmxData = DMXNetworkData.getInstance(level).getNetwork(networkId); + var dmxData = DMXNetworkData.getInstance(level.getServer().overworld()).getNetwork(networkId); if (dmxData != null) { if(deviceId == null){ generateDeviceId(); diff --git a/common/src/main/java/dev/imabad/theatrical/blocks/light/BaseLightBlock.java b/common/src/main/java/dev/imabad/theatrical/blocks/light/BaseLightBlock.java index 07669f3..4f624d7 100644 --- a/common/src/main/java/dev/imabad/theatrical/blocks/light/BaseLightBlock.java +++ b/common/src/main/java/dev/imabad/theatrical/blocks/light/BaseLightBlock.java @@ -62,7 +62,7 @@ public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable L if(!level.isClientSide){ BlockEntity be = level.getBlockEntity(pos); if(be instanceof BaseDMXConsumerLightBlockEntity consumerLightBlockEntity && placer instanceof ServerPlayer player){ - consumerLightBlockEntity.setNetworkId(DMXNetworkData.getInstance(level).getDefaultNetworkForPlayer(player).id()); + consumerLightBlockEntity.setNetworkId(DMXNetworkData.getInstance(level.getServer().overworld()).getDefaultNetworkForPlayer(player).id()); } } } diff --git a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/BasicLightingDeskScreen.java b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/BasicLightingDeskScreen.java index 05c7036..b930aef 100644 --- a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/BasicLightingDeskScreen.java +++ b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/BasicLightingDeskScreen.java @@ -120,7 +120,7 @@ protected void init() { ).withValues(CycleButton.ValueListSupplier.create(Stream.concat(Stream.of(UUIDUtil.NULL), TheatricalClient.getArtNetManager().getKnownNetworks().keySet().stream()).collect(Collectors.toList()))) .displayOnlyValue().withInitialValue(networkId) - .create(xCenter, yCenter, 150, 20, + .create(xCenter + 45, yCenter + 130, 150, 20, Component.translatable("screen.artnetconfig.network"), (obj, val) -> { this.networkId = val; new UpdateNetworkId(be.getBlockPos(), networkId).sendToServer(); diff --git a/common/src/main/java/dev/imabad/theatrical/commands/CommandArguments.java b/common/src/main/java/dev/imabad/theatrical/commands/CommandArguments.java new file mode 100644 index 0000000..3b16d47 --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/commands/CommandArguments.java @@ -0,0 +1,15 @@ +package dev.imabad.theatrical.commands; + +import dev.architectury.registry.registries.DeferredRegister; +import dev.architectury.registry.registries.RegistrySupplier; +import dev.imabad.theatrical.TheatricalRegistry; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.commands.synchronization.SingletonArgumentInfo; +import net.minecraft.core.registries.Registries; + +public class CommandArguments { + + public static final DeferredRegister> ARGUMENTS = TheatricalRegistry.get(Registries.COMMAND_ARGUMENT_TYPE); + + public static final RegistrySupplier> NETWORK_MODE = ARGUMENTS.register("network_mode", () -> SingletonArgumentInfo.contextFree(DMXNetworkModeArgument::networkMode)); +} diff --git a/common/src/main/java/dev/imabad/theatrical/commands/DMXNetworkModeArgument.java b/common/src/main/java/dev/imabad/theatrical/commands/DMXNetworkModeArgument.java new file mode 100644 index 0000000..d94ef0b --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/commands/DMXNetworkModeArgument.java @@ -0,0 +1,48 @@ +package dev.imabad.theatrical.commands; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import dev.imabad.theatrical.dmx.DMXNetworkMode; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.network.chat.Component; + +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; + +public class DMXNetworkModeArgument implements ArgumentType { + private static final DynamicCommandExceptionType ERROR_INVALID = new DynamicCommandExceptionType( + object -> Component.translatable("commands.network.invalid", object) + ); + private static final DMXNetworkMode[] VALUES = DMXNetworkMode.values(); + + @Override + public CompletableFuture listSuggestions(CommandContext commandContext, SuggestionsBuilder suggestionsBuilder) { + return commandContext.getSource() instanceof SharedSuggestionProvider + ? SharedSuggestionProvider.suggest(Arrays.stream(VALUES).map(DMXNetworkMode::getName), suggestionsBuilder) + : Suggestions.empty(); + } + + @Override + public DMXNetworkMode parse(StringReader reader) throws CommandSyntaxException { + String string = reader.readUnquotedString(); + DMXNetworkMode networkMode = DMXNetworkMode.byName(string); + if (networkMode == null) { + throw ERROR_INVALID.createWithContext(reader, string); + } else { + return networkMode; + } + } + + public static DMXNetworkModeArgument networkMode() { + return new DMXNetworkModeArgument(); + } + public static DMXNetworkMode getMode(CommandContext context, String name) { + return context.getArgument(name, DMXNetworkMode.class); + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/commands/MemberRoleArgument.java b/common/src/main/java/dev/imabad/theatrical/commands/MemberRoleArgument.java new file mode 100644 index 0000000..3f7ead4 --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/commands/MemberRoleArgument.java @@ -0,0 +1,49 @@ +package dev.imabad.theatrical.commands; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import dev.imabad.theatrical.dmx.DMXNetworkMemberRole; +import dev.imabad.theatrical.dmx.DMXNetworkMode; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.network.chat.Component; + +import java.util.Arrays; +import java.util.concurrent.CompletableFuture; + +public class MemberRoleArgument implements ArgumentType { + private static final DynamicCommandExceptionType ERROR_INVALID = new DynamicCommandExceptionType( + object -> Component.translatable("commands.network.role.invalid", object) + ); + private static final DMXNetworkMemberRole[] VALUES = DMXNetworkMemberRole.values(); + + @Override + public CompletableFuture listSuggestions(CommandContext commandContext, SuggestionsBuilder suggestionsBuilder) { + return commandContext.getSource() instanceof SharedSuggestionProvider + ? SharedSuggestionProvider.suggest(Arrays.stream(VALUES).map(DMXNetworkMemberRole::getName), suggestionsBuilder) + : Suggestions.empty(); + } + + @Override + public DMXNetworkMemberRole parse(StringReader reader) throws CommandSyntaxException { + String string = reader.readUnquotedString(); + DMXNetworkMemberRole networkMode = DMXNetworkMemberRole.byName(string); + if (networkMode == null) { + throw ERROR_INVALID.createWithContext(reader, string); + } else { + return networkMode; + } + } + + public static MemberRoleArgument memberRole() { + return new MemberRoleArgument(); + } + public static DMXNetworkMemberRole getMode(CommandContext context, String name) { + return context.getArgument(name, DMXNetworkMemberRole.class); + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/commands/NetworkCommand.java b/common/src/main/java/dev/imabad/theatrical/commands/NetworkCommand.java new file mode 100644 index 0000000..da9c554 --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/commands/NetworkCommand.java @@ -0,0 +1,342 @@ +package dev.imabad.theatrical.commands; + +import com.mojang.authlib.GameProfile; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; +import dev.imabad.theatrical.dmx.*; +import dev.imabad.theatrical.net.artnet.NotifyNetworks; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.commands.arguments.GameProfileArgument; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.players.GameProfileCache; +import net.minecraft.server.players.PlayerList; +import net.minecraft.util.Tuple; + +import java.util.*; +import java.util.stream.Collectors; + +public class NetworkCommand { + + private static final SimpleCommandExceptionType ERROR_NETWORK_DOES_NOT_EXIST = new SimpleCommandExceptionType( + Component.translatable("commands.network.notfound") + ); + + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(Commands.literal("theatrical") + .then(Commands.literal("networks") + .executes(NetworkCommand::listNetworks) + ) + .then(Commands.literal("network") + .then(Commands.literal("new") + .then(Commands.argument("mode", DMXNetworkModeArgument.networkMode()) + .then(Commands.argument("name", StringArgumentType.greedyString()) + .executes(NetworkCommand::createNetwork)))) + .then(Commands.argument("id", StringArgumentType.string()) + .suggests((commandContext, suggestionsBuilder) -> SharedSuggestionProvider.suggest( + getNetworksForPlayer(commandContext) + .stream() + .map(serverPlayer -> serverPlayer.id().toString()), + suggestionsBuilder + )) + .executes(NetworkCommand::getNetwork) + .then(Commands.literal("members") + .executes(NetworkCommand::listNetworkMembers) + ).then(Commands.literal("rename") + .then(Commands.argument("name", StringArgumentType.greedyString()) + .executes(NetworkCommand::renameNetwork) + ) + ).then(Commands.literal("delete") + .executes(NetworkCommand::deleteNetwork) + ).then(Commands.literal("mode") + .then(Commands.argument("mode", DMXNetworkModeArgument.networkMode()) + .executes(NetworkCommand::changeNetworkMode)) + ).then(Commands.literal("setrole") + .then(Commands.argument("target", GameProfileArgument.gameProfile()) + .suggests( + (commandContext, suggestionsBuilder) -> { + Set members = + getDMXNetwork(commandContext).members(); + GameProfileCache profileCache = commandContext.getSource() + .getServer().getProfileCache(); + return SharedSuggestionProvider.suggest( + members.stream() + .map(serverPlayer -> profileCache + .get(serverPlayer.playerId()) + .orElse(new GameProfile( + serverPlayer.playerId(), + serverPlayer.playerId() + .toString() + )).getName()), + suggestionsBuilder + ); + } + ).then(Commands.argument("role", MemberRoleArgument.memberRole()) + .executes(NetworkCommand::changeMemberRole))) + ) + .then(Commands.literal("add") + .then(Commands.argument("targets", GameProfileArgument.gameProfile()) + .suggests( + (commandContext, suggestionsBuilder) -> { + PlayerList playerList = commandContext.getSource().getServer().getPlayerList(); + return SharedSuggestionProvider.suggest( + playerList.getPlayers() + .stream() + .map(serverPlayer -> serverPlayer.getGameProfile().getName()), + suggestionsBuilder + ); + } + ) + .executes(NetworkCommand::addPlayer))) + .then(Commands.literal("remove") + .then(Commands.argument("targets", GameProfileArgument.gameProfile()) + .suggests( + (commandContext, suggestionsBuilder) -> { + Set members = + getDMXNetwork(commandContext).members(); + GameProfileCache profileCache = commandContext.getSource() + .getServer().getProfileCache(); + return SharedSuggestionProvider.suggest( + members.stream() + .map(serverPlayer -> profileCache + .get(serverPlayer.playerId()) + .orElse(new GameProfile( + serverPlayer.playerId(), + serverPlayer.playerId() + .toString() + )).getName()), + suggestionsBuilder + ); + } + ) + .executes(NetworkCommand::removePlayer))) + ) + ) + ); + } + + private static int changeMemberRole(CommandContext context) throws CommandSyntaxException { + DMXNetwork dmxNetwork = getDMXNetwork(context); + if (!isSourceOperator(context)) { + if (context.getSource().isPlayer() && !dmxNetwork.isAdmin(context.getSource().getPlayer().getUUID())) { + throw ERROR_NETWORK_DOES_NOT_EXIST.create(); + } + } + Collection players = GameProfileArgument.getGameProfiles(context, "targets"); + DMXNetworkMemberRole role = MemberRoleArgument.getMode(context, "role"); + for (GameProfile player : players) { + dmxNetwork.setMemberRole(player.getId(), role); + } + context.getSource().sendSuccess(() -> Component.translatable("commands.network.updated"), false); + return 0; + } + + private static int changeNetworkMode(CommandContext context) throws CommandSyntaxException { + DMXNetwork dmxNetwork = getDMXNetwork(context); + if (!isSourceOperator(context)) { + if (context.getSource().isPlayer() && !dmxNetwork.isAdmin(context.getSource().getPlayer().getUUID())) { + throw ERROR_NETWORK_DOES_NOT_EXIST.create(); + } + } + DMXNetworkMode mode = DMXNetworkModeArgument.getMode(context, "mode"); + DMXNetworkMode oldMode = dmxNetwork.mode(); + dmxNetwork.setMode(mode); + List members = new ArrayList<>(); + for (DMXNetworkMember member : dmxNetwork.members()) { + ServerPlayer player = context.getSource().getServer().getPlayerList().getPlayer(member.playerId()); + if(player != null){ + DMXNetworkData.getInstance(context.getSource().getLevel()).notifyNetworks(player); + members.add(player.getUUID()); + } + } + if(dmxNetwork.mode() == DMXNetworkMode.PUBLIC || oldMode == DMXNetworkMode.PUBLIC){ + for (ServerPlayer player : context.getSource().getServer().getPlayerList().getPlayers()) { + if(!members.contains(player.getUUID())){ + DMXNetworkData.getInstance(context.getSource().getServer().overworld()).notifyNetworks(player); + } + } + } + context.getSource().sendSuccess(() -> Component.translatable("commands.network.updated"), false); + return 1; + } + + private static int createNetwork(CommandContext context) { + String newName = StringArgumentType.getString(context, "name"); + DMXNetworkMode mode = DMXNetworkModeArgument.getMode(context, "mode"); + DMXNetwork network = DMXNetworkData.getInstance(context.getSource().getServer().overworld()).createNetwork(newName, mode); + if(context.getSource().isPlayer()){ + network.addMember(context.getSource().getPlayer().getUUID(), DMXNetworkMemberRole.ADMIN); + } + if(network.mode() == DMXNetworkMode.PUBLIC){ + for (ServerPlayer player : context.getSource().getServer().getPlayerList().getPlayers()) { + DMXNetworkData.getInstance(context.getSource().getServer().overworld()).notifyNetworks(player); + } + } + context.getSource().sendSuccess(() -> Component.translatable("commands.network.created"), false); + + return 1; + } + + private static int listNetworkMembers(CommandContext context) throws CommandSyntaxException { + DMXNetwork dmxNetwork = getDMXNetwork(context); + GameProfileCache profileCache = context.getSource().getServer().getProfileCache(); + List list = dmxNetwork.members() + .stream().map(DMXNetworkMember::playerId) + .map((playerUUID) -> new Tuple<>(playerUUID, profileCache.get(playerUUID))) + .map(uuidOptionalTuple -> uuidOptionalTuple.getB().isPresent() ? uuidOptionalTuple.getB().get().getName() : uuidOptionalTuple.getA().toString()) + .toList(); + context.getSource().sendSuccess(() -> Component.translatable("commands.network.members", list.size(), String.join(", ", list)), false); + return 1; + } + private static int getNetwork(CommandContext context) throws CommandSyntaxException { + DMXNetwork dmxNetwork = getDMXNetwork(context); + if (!isSourceOperator(context)) { + if (context.getSource().isPlayer() && !dmxNetwork.isAdmin(context.getSource().getPlayer().getUUID())) { + throw ERROR_NETWORK_DOES_NOT_EXIST.create(); + } + } + int i = 0; + context.getSource().sendSuccess(() -> Component.translatable("commands.network", Component.literal(dmxNetwork.name()), dmxNetwork.id().toString(), dmxNetwork.members().size()), false); + return i; + } + private static int addPlayer(CommandContext context) throws CommandSyntaxException { + DMXNetwork dmxNetwork = getDMXNetwork(context); + if (!isSourceOperator(context)) { + if (context.getSource().isPlayer() && !dmxNetwork.isAdmin(context.getSource().getPlayer().getUUID())) { + throw ERROR_NETWORK_DOES_NOT_EXIST.create(); + } + } + int i = 0; + Collection players = GameProfileArgument.getGameProfiles(context, "targets"); + for (GameProfile player : players) { + if(!dmxNetwork.isMember(player.getId())) { + dmxNetwork.addMember(player.getId(), DMXNetworkMemberRole.NONE); + context.getSource().sendSuccess(() -> Component.translatable("commands.network.members.add.success", Component.literal(player.getName())), false); + i++; + } + } + return i; + } + + private static int renameNetwork(CommandContext context) throws CommandSyntaxException { + DMXNetwork dmxNetwork = getDMXNetwork(context); + if (!isSourceOperator(context)) { + if (context.getSource().isPlayer() && !dmxNetwork.isAdmin(context.getSource().getPlayer().getUUID())) { + throw ERROR_NETWORK_DOES_NOT_EXIST.create(); + } + } + String newName = StringArgumentType.getString(context, "name"); + dmxNetwork.setName(newName); + List members = new ArrayList<>(); + for (DMXNetworkMember member : dmxNetwork.members()) { + ServerPlayer player = context.getSource().getServer().getPlayerList().getPlayer(member.playerId()); + if(player != null){ + DMXNetworkData.getInstance(context.getSource().getLevel()).notifyNetworks(player); + members.add(player.getUUID()); + } + } + if(dmxNetwork.mode() == DMXNetworkMode.PUBLIC){ + for (ServerPlayer player : context.getSource().getServer().getPlayerList().getPlayers()) { + if(!members.contains(player.getUUID())){ + DMXNetworkData.getInstance(context.getSource().getServer().overworld()).notifyNetworks(player); + } + } + } + return 1; + } + + private static int deleteNetwork(CommandContext context) throws CommandSyntaxException { + DMXNetwork dmxNetwork = getDMXNetwork(context); + if (!isSourceOperator(context)) { + if (context.getSource().isPlayer() && !dmxNetwork.isAdmin(context.getSource().getPlayer().getUUID())) { + throw ERROR_NETWORK_DOES_NOT_EXIST.create(); + } + } + + DMXNetworkData.getInstance(context.getSource().getLevel()).deleteNetwork(dmxNetwork); + List members = new ArrayList<>(); + for (DMXNetworkMember member : dmxNetwork.members()) { + ServerPlayer player = context.getSource().getServer().getPlayerList().getPlayer(member.playerId()); + if(player != null){ + DMXNetworkData.getInstance(context.getSource().getLevel()).notifyNetworks(player); + members.add(player.getUUID()); + } + } + if(dmxNetwork.mode() == DMXNetworkMode.PUBLIC){ + for (ServerPlayer player : context.getSource().getServer().getPlayerList().getPlayers()) { + if(!members.contains(player.getUUID())){ + DMXNetworkData.getInstance(context.getSource().getServer().overworld()).notifyNetworks(player); + } + } + } + context.getSource().sendSuccess(() -> Component.translatable("commands.network.deleted"), false); + return 1; + } + + private static int removePlayer(CommandContext context) throws CommandSyntaxException { + DMXNetwork dmxNetwork = getDMXNetwork(context); + if (!isSourceOperator(context)) { + if (context.getSource().isPlayer() && !dmxNetwork.isAdmin(context.getSource().getPlayer().getUUID())) { + throw ERROR_NETWORK_DOES_NOT_EXIST.create(); + } + } + Collection players = GameProfileArgument.getGameProfiles(context, "targets"); + for (GameProfile player : players) { + if(dmxNetwork.isMember(player.getId())){ + dmxNetwork.removeMember(player.getId()); + context.getSource().sendSuccess(() -> Component.translatable("commands.network.members.remove.success", Component.literal(player.getName())), false); + } + } + return 0; + } + + private static Collection getNetworksForPlayer(CommandContext context) { + DMXNetworkData instance = DMXNetworkData. + getInstance(context.getSource().getServer().overworld()); + if (isSourceOperator(context)) { + return instance.getAllNetworks(); + } else { + return instance.getNetworksForPlayer(context.getSource().getPlayer().getUUID()); + } + } + + private static int listNetworks(CommandContext context) { + DMXNetworkData instance = DMXNetworkData. + getInstance(context.getSource().getServer().overworld()); + List networks; + if (isSourceOperator(context)) { + networks = instance.getAllNetworks().stream() + .map(DMXNetwork::name).collect(Collectors.toList()); + } else { + networks = instance.getNetworksForPlayer(context.getSource().getPlayer().getUUID()).stream() + .map(DMXNetwork::name).collect(Collectors.toList()); + } + context.getSource().sendSuccess(() -> Component.translatable("commands.networks", + networks.size(), String.join(", ", networks)), false); + return 1; + } + + private static boolean isSourceOperator(CommandContext context) { + return context.getSource().hasPermission(context.getSource().getServer().getOperatorUserPermissionLevel()); + } + + private static DMXNetwork getDMXNetwork(CommandContext context) throws CommandSyntaxException { + DMXNetworkData instance = DMXNetworkData. + getInstance(context.getSource().getServer().overworld()); + try { + String id = context.getArgument("id", String.class); + UUID uuid = UUID.fromString(id); + DMXNetwork network = instance.getNetwork(uuid); + if (network != null) { + return network; + } + } catch (Exception ignored) { + } + throw ERROR_NETWORK_DOES_NOT_EXIST.create(); + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java index 32a8d6e..a54a830 100644 --- a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java +++ b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java @@ -5,19 +5,21 @@ import dev.imabad.theatrical.net.artnet.NotifyConsumerChange; import io.netty.util.collection.IntObjectHashMap; import io.netty.util.collection.IntObjectMap; +import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerPlayer; +import org.jetbrains.annotations.Nullable; import java.util.*; public class DMXNetwork { private final UUID id; - private final String name; - private final DMXNetworkMode mode; + private String name; + private DMXNetworkMode mode; private final Set members; private final IntObjectMap> universeToNodeMap = new IntObjectHashMap<>(); private final Set knownSenders = new HashSet<>(); @@ -51,6 +53,7 @@ public CompoundTag save(){ CompoundTag tag = new CompoundTag(); tag.putUUID("id", id); tag.putString("mode", mode.toString()); + tag.putString("name", name); ListTag membersList = new ListTag(); for (DMXNetworkMember member : members) { CompoundTag memberTag = new CompoundTag(); @@ -163,6 +166,12 @@ public Set getUniverses(){ public void addMember(UUID playerUUID, DMXNetworkMemberRole role){ members.add(new DMXNetworkMember(playerUUID, role)); + DMXNetworkData.getInstance().setDirty(); + } + public void removeMember(UUID playerUUID){ + DMXNetworkMember dmxNetworkMember = getDmxNetworkMember(playerUUID); + members.remove(dmxNetworkMember); + DMXNetworkData.getInstance().setDirty(); } public boolean isMember(UUID playerUUID){ @@ -170,12 +179,39 @@ public boolean isMember(UUID playerUUID){ } public boolean canSendDMX(UUID uuid) { + DMXNetworkMember dmxNetworkMember = getDmxNetworkMember(uuid); + if (dmxNetworkMember == null) return false; + return dmxNetworkMember.role() == DMXNetworkMemberRole.SEND || dmxNetworkMember.role() == DMXNetworkMemberRole.ADMIN; + } + + public boolean isAdmin(UUID uuid){ + DMXNetworkMember dmxNetworkMember = getDmxNetworkMember(uuid); + if (dmxNetworkMember == null) return false; + return dmxNetworkMember.role() == DMXNetworkMemberRole.ADMIN; + } + + public void setMemberRole(UUID playerId, DMXNetworkMemberRole role){ + DMXNetworkMember dmxNetworkMember = getDmxNetworkMember(playerId); + if(dmxNetworkMember != null) { + dmxNetworkMember.setRole(role); + DMXNetworkData.getInstance().setDirty(); + } + } + + @Nullable + private DMXNetworkMember getDmxNetworkMember(UUID uuid) { Optional first = members.stream() .filter(dmxNetworkMember -> dmxNetworkMember.playerId() == uuid).findFirst(); - if(first.isEmpty()){ - return false; - } - DMXNetworkMember dmxNetworkMember = first.get(); - return dmxNetworkMember.role() == DMXNetworkMemberRole.SEND || dmxNetworkMember.role() == DMXNetworkMemberRole.ADMIN; + return first.orElse(null); + } + + public void setName(String name) { + this.name = name; + DMXNetworkData.getInstance().setDirty(); + } + + public void setMode(DMXNetworkMode mode) { + this.mode = mode; + DMXNetworkData.getInstance().setDirty(); } } diff --git a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkData.java b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkData.java index ead3a63..e29eb81 100644 --- a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkData.java +++ b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkData.java @@ -1,17 +1,10 @@ package dev.imabad.theatrical.dmx; -import ch.bildspur.artnet.rdm.RDMDeviceId; -import dev.imabad.theatrical.api.dmx.DMXConsumer; -import dev.imabad.theatrical.net.artnet.NotifyConsumerChange; +import dev.architectury.utils.GameInstance; import dev.imabad.theatrical.net.artnet.NotifyNetworks; -import io.netty.util.collection.IntObjectHashMap; -import io.netty.util.collection.IntObjectMap; -import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; @@ -32,6 +25,11 @@ public class DMXNetworkData extends SavedData { DMXNetworkData::read, null ); + + public static void unloadLevel(){ + INSTANCE = null; + } + public static DMXNetworkData getInstance(Level level){ if(INSTANCE == null){ INSTANCE = level.getServer() @@ -40,6 +38,14 @@ public static DMXNetworkData getInstance(Level level){ return INSTANCE; } + public static DMXNetworkData getInstance(){ + if(INSTANCE == null){ + INSTANCE = GameInstance.getServer().overworld().getDataStorage().computeIfAbsent(factory, KEY); + } + return INSTANCE; + } + + @Nullable public DMXNetwork getNetwork(UUID networkId){ return networks.get(networkId); @@ -50,8 +56,21 @@ public DMXNetwork createNetwork(Player player){ network.addMember(player.getUUID(), DMXNetworkMemberRole.ADMIN); networks.put(network.id(), network); notifyNetworks(player); + setDirty(); return network; } + public DMXNetwork createNetwork(String name, DMXNetworkMode mode){ + DMXNetwork network = new DMXNetwork(name); + network.setMode(mode); + networks.put(network.id(), network); + setDirty(); + return network; + } + + public void deleteNetwork(DMXNetwork dmxNetwork){ + networks.remove(dmxNetwork.id()); + setDirty(); + } public void notifyNetworks(Player player){ Map collect = getNetworksForPlayer(player.getUUID()).stream().collect(Collectors.toMap(DMXNetwork::id, DMXNetwork::name)); diff --git a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMember.java b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMember.java index 0ab0a91..a23efb8 100644 --- a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMember.java +++ b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMember.java @@ -1,6 +1,48 @@ package dev.imabad.theatrical.dmx; +import java.util.Objects; import java.util.UUID; -public record DMXNetworkMember(UUID playerId, DMXNetworkMemberRole role) { +public final class DMXNetworkMember { + private final UUID playerId; + private DMXNetworkMemberRole role; + + public DMXNetworkMember(UUID playerId, DMXNetworkMemberRole role) { + this.playerId = playerId; + this.role = role; + } + + public UUID playerId() { + return playerId; + } + + public DMXNetworkMemberRole role() { + return role; + } + + public void setRole(DMXNetworkMemberRole role) { + this.role = role; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj == null || obj.getClass() != this.getClass()) return false; + var that = (DMXNetworkMember) obj; + return Objects.equals(this.playerId, that.playerId) && + Objects.equals(this.role, that.role); + } + + @Override + public int hashCode() { + return Objects.hash(playerId, role); + } + + @Override + public String toString() { + return "DMXNetworkMember[" + + "playerId=" + playerId + ", " + + "role=" + role + ']'; + } + } diff --git a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMemberRole.java b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMemberRole.java index a117b88..5cd52b6 100644 --- a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMemberRole.java +++ b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMemberRole.java @@ -1,7 +1,34 @@ package dev.imabad.theatrical.dmx; -public enum DMXNetworkMemberRole { - NONE, - SEND, - ADMIN; +import net.minecraft.util.StringRepresentable; +import org.jetbrains.annotations.NotNull; + +public enum DMXNetworkMemberRole implements StringRepresentable { + NONE("NONE"), + SEND("SEND"), + ADMIN("ADMIN"); + + private final String name; + + DMXNetworkMemberRole(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public @NotNull String getSerializedName() { + return name; + } + + public static DMXNetworkMemberRole byName(String name){ + for (DMXNetworkMemberRole value : values()) { + if(value.getName().equals(name)){ + return value; + } + } + return null; + } } diff --git a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMode.java b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMode.java index df97066..0e23b0b 100644 --- a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMode.java +++ b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetworkMode.java @@ -1,9 +1,35 @@ package dev.imabad.theatrical.dmx; -public enum DMXNetworkMode { +import net.minecraft.util.StringRepresentable; +import org.jetbrains.annotations.NotNull; - PUBLIC, - INVITE, - PRIVATE; +public enum DMXNetworkMode implements StringRepresentable { + PUBLIC("PUBLIC"), + INVITE("INVITE"), + PRIVATE("PRIVATE"); + + private final String name; + + DMXNetworkMode(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + @Override + public @NotNull String getSerializedName() { + return name; + } + + public static DMXNetworkMode byName(String name){ + for (DMXNetworkMode value : values()) { + if(value.getName().equals(name)){ + return value; + } + } + return null; + } } diff --git a/common/src/main/java/dev/imabad/theatrical/mixin/ArgumentTypeInfosAccessor.java b/common/src/main/java/dev/imabad/theatrical/mixin/ArgumentTypeInfosAccessor.java new file mode 100644 index 0000000..a7b394d --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/mixin/ArgumentTypeInfosAccessor.java @@ -0,0 +1,18 @@ +package dev.imabad.theatrical.mixin; + +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.commands.synchronization.ArgumentTypeInfos; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(ArgumentTypeInfos.class) +public interface ArgumentTypeInfosAccessor { + + @Accessor("BY_CLASS") + static Map, ArgumentTypeInfo> classMap(){ + throw new UnsupportedOperationException(); + } + +} diff --git a/common/src/main/java/dev/imabad/theatrical/net/artnet/RDMUpdateConsumer.java b/common/src/main/java/dev/imabad/theatrical/net/artnet/RDMUpdateConsumer.java index 8ea7882..bed96c4 100644 --- a/common/src/main/java/dev/imabad/theatrical/net/artnet/RDMUpdateConsumer.java +++ b/common/src/main/java/dev/imabad/theatrical/net/artnet/RDMUpdateConsumer.java @@ -56,7 +56,7 @@ public void handle(NetworkManager.PacketContext context) { Level level = context.getPlayer().level(); if(level.getServer() != null ) { if (context.getPlayer().hasPermissions(level.getServer().getOperatorUserPermissionLevel())) { - DMXNetwork network = DMXNetworkData.getInstance(level).getNetwork(networkId); + DMXNetwork network = DMXNetworkData.getInstance(level.getServer().overworld()).getNetwork(networkId); if(network == null){ return; } diff --git a/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestConsumers.java b/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestConsumers.java index ab34f41..2a60d72 100644 --- a/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestConsumers.java +++ b/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestConsumers.java @@ -49,7 +49,7 @@ public void handle(NetworkManager.PacketContext context) { Level level = context.getPlayer().level(); if(level.getServer() != null ) { if (context.getPlayer().hasPermissions(level.getServer().getOperatorUserPermissionLevel())) { - DMXNetwork network = DMXNetworkData.getInstance(level).getNetwork(networkId); + DMXNetwork network = DMXNetworkData.getInstance(level.getServer().overworld()).getNetwork(networkId); if(network != null && network.isMember(context.getPlayer().getUUID())){ List devices = new ArrayList<>(); Collection consumers = network.getConsumers(universe); diff --git a/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestNetworks.java b/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestNetworks.java index f6738da..ee4bc85 100644 --- a/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestNetworks.java +++ b/common/src/main/java/dev/imabad/theatrical/net/artnet/RequestNetworks.java @@ -37,7 +37,7 @@ public void write(FriendlyByteBuf buf) { public void handle(NetworkManager.PacketContext context) { Level level = context.getPlayer().level(); if(level.getServer() != null ) { - List networksForPlayer = DMXNetworkData.getInstance(level) + List networksForPlayer = DMXNetworkData.getInstance(level.getServer().overworld()) .getNetworksForPlayer(context.getPlayer().getUUID()); Map collect = networksForPlayer.stream().collect(Collectors.toMap(DMXNetwork::id, DMXNetwork::name)); new NotifyNetworks(collect).sendTo((ServerPlayer) context.getPlayer()); diff --git a/common/src/main/java/dev/imabad/theatrical/net/artnet/SendArtNetData.java b/common/src/main/java/dev/imabad/theatrical/net/artnet/SendArtNetData.java index 1867779..b91cb69 100644 --- a/common/src/main/java/dev/imabad/theatrical/net/artnet/SendArtNetData.java +++ b/common/src/main/java/dev/imabad/theatrical/net/artnet/SendArtNetData.java @@ -46,7 +46,7 @@ public void write(FriendlyByteBuf buf) { public void handle(NetworkManager.PacketContext context) { Level level = context.getPlayer().level(); if(level.getServer() != null) { - DMXNetwork network = DMXNetworkData.getInstance(level).getNetwork(networkId); + DMXNetwork network = DMXNetworkData.getInstance(level.getServer().overworld()).getNetwork(networkId); UUID uuid = context.getPlayer().getUUID(); if(network != null) { if (network.isMember(uuid) && network.canSendDMX(uuid)) { diff --git a/common/src/main/resources/theatrical-common.mixins.json b/common/src/main/resources/theatrical-common.mixins.json index 24ede0b..6987d5f 100644 --- a/common/src/main/resources/theatrical-common.mixins.json +++ b/common/src/main/resources/theatrical-common.mixins.json @@ -8,6 +8,7 @@ "maxShiftBy": 5 }, "mixins": [ + "ArgumentTypeInfosAccessor", "ClipContextAccessor" ], "client": [ diff --git a/neoforge/src/main/java/dev/imabad/theatrical/neoforge/DataEvent.java b/neoforge/src/main/java/dev/imabad/theatrical/neoforge/DataEvent.java index bc93ba5..af91081 100644 --- a/neoforge/src/main/java/dev/imabad/theatrical/neoforge/DataEvent.java +++ b/neoforge/src/main/java/dev/imabad/theatrical/neoforge/DataEvent.java @@ -108,6 +108,18 @@ protected void addTranslations() { add("ui.control.cue", "Cue - %s"); add("ui.control.fadeIn", "Fade in"); add("ui.control.fadeOut", "Fade out"); + add("commands.network.notfound", "Network not found."); + add("commands.networks", "There are %s network(s): %s."); + add("commands.network.members", "There are %s network member(s): %s."); + add("commands.network.members.add.success", "Added %s to the network."); + add("commands.network.members.add.failed", "Player already member of network."); + add("commands.network.members.remove.success", "Removed %s from the network."); + add("commands.network", "%s (%s) has %s member(s)"); + add("commands.network.invalid", "Unknown network mode: %s"); + add("commands.network.role.invalid", "Unknown member role: %s"); + add("commands.network.created", "Network created"); + add("commands.network.deleted", "Network deleted"); + add("commands.network.updated", "Network updated"); } } From edd36721cc982209bf403441d19e6aa1a1814092 Mon Sep 17 00:00:00 2001 From: Stuart Pomeroy Date: Tue, 30 Jul 2024 18:42:32 +0100 Subject: [PATCH 4/5] few small fixes --- .../theatrical/blockentities/light/FresnelBlockEntity.java | 1 + .../theatrical/blockentities/light/MovingLightBlockEntity.java | 1 + .../client/gui/screen/GenericDMXConfigurationScreen.java | 2 +- common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/dev/imabad/theatrical/blockentities/light/FresnelBlockEntity.java b/common/src/main/java/dev/imabad/theatrical/blockentities/light/FresnelBlockEntity.java index d3ef39f..4a56682 100644 --- a/common/src/main/java/dev/imabad/theatrical/blockentities/light/FresnelBlockEntity.java +++ b/common/src/main/java/dev/imabad/theatrical/blockentities/light/FresnelBlockEntity.java @@ -43,6 +43,7 @@ public void consume(byte[] dmxValues) { green = convertByteToInt(ourValues[2]); blue = convertByteToInt(ourValues[3]); level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); + setChanged(); } @Override diff --git a/common/src/main/java/dev/imabad/theatrical/blockentities/light/MovingLightBlockEntity.java b/common/src/main/java/dev/imabad/theatrical/blockentities/light/MovingLightBlockEntity.java index 3c44330..f76d6a5 100644 --- a/common/src/main/java/dev/imabad/theatrical/blockentities/light/MovingLightBlockEntity.java +++ b/common/src/main/java/dev/imabad/theatrical/blockentities/light/MovingLightBlockEntity.java @@ -46,6 +46,7 @@ public void consume(byte[] dmxValues) { pan = (int) ((convertByteToInt(ourValues[5]) * 360) / 255f) - 180; tilt = (int) ((convertByteToInt(ourValues[6]) * 180) / 255F) - 180; level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), Block.UPDATE_CLIENTS); + setChanged(); } @Override diff --git a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/GenericDMXConfigurationScreen.java b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/GenericDMXConfigurationScreen.java index f1f0bb9..2d51a2e 100644 --- a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/GenericDMXConfigurationScreen.java +++ b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/GenericDMXConfigurationScreen.java @@ -62,7 +62,7 @@ protected void init() { this.dmxAddress.setValue(Integer.toString(this.be.getChannelStart())); layout.addChild(dmxAddress); this.dmxUniverse = new LabeledEditBox(this.font, xCenter, yCenter, 50, 10, Component.translatable("artneti.dmxUniverse")); - this.dmxUniverse.setValue(Integer.toString(this.be.getChannelStart())); + this.dmxUniverse.setValue(Integer.toString(this.be.getUniverse())); layout.addChild(dmxUniverse); addExtraWidgetsToUI(); layout.addChild(new CycleButton.Builder((networkId) -> diff --git a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java index a54a830..d6dd2b9 100644 --- a/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java +++ b/common/src/main/java/dev/imabad/theatrical/dmx/DMXNetwork.java @@ -201,7 +201,7 @@ public void setMemberRole(UUID playerId, DMXNetworkMemberRole role){ @Nullable private DMXNetworkMember getDmxNetworkMember(UUID uuid) { Optional first = members.stream() - .filter(dmxNetworkMember -> dmxNetworkMember.playerId() == uuid).findFirst(); + .filter(dmxNetworkMember -> dmxNetworkMember.playerId().equals(uuid)).findFirst(); return first.orElse(null); } From 00085faac7fe7a9bbb5d942fdc1bbb91c0095580 Mon Sep 17 00:00:00 2001 From: Stuart Pomeroy Date: Tue, 30 Jul 2024 22:09:31 +0100 Subject: [PATCH 5/5] configuration card & renderering fixes --- .../ac32a6491e9ad7e80dfd5d9683e4c90fbf53e1e6 | 3 +- .../c622617f6fabf890a00b9275cd5f643584a8a2c8 | 4 +- .../assets/theatrical/lang/en_us.json | 5 + .../models/item/configuration_card.json | 6 + .../imabad/theatrical/TheatricalClient.java | 2 + .../blocks/light/BaseLightBlock.java | 31 ++++ .../theatrical/blocks/light/FresnelBlock.java | 20 +-- .../blocks/light/LEDPanelBlock.java | 20 +-- .../blocks/light/MovingLightBlock.java | 20 +-- .../theatrical/client/LazyRenderers.java | 50 +++++++ .../client/TheatricalRenderTypes.java | 10 ++ .../client/blockentities/FixtureRenderer.java | 32 +++- .../client/blockentities/FresnelRenderer.java | 61 ++++++++ .../blockentities/LEDPanelRenderer.java | 38 +++++ .../blockentities/MovingLightRenderer.java | 67 +++++++++ .../gui/screen/ConfigurationCardScreen.java | 137 ++++++++++++++++++ .../gui/widgets/BetterStringWidget.java | 40 +++++ .../client/gui/widgets/LabeledEditBox.java | 4 +- .../theatrical/items/ConfigurationCard.java | 7 +- .../dev/imabad/theatrical/items/Items.java | 4 + .../net/ConfigureConfigurationCard.java | 68 +++++++++ .../imabad/theatrical/net/TheatricalNet.java | 1 + .../textures/item/configuration_card.png | Bin 0 -> 2046 bytes .../main/resources/theatrical.accesswidener | 3 +- .../imabad/theatrical/neoforge/DataEvent.java | 8 + 25 files changed, 601 insertions(+), 40 deletions(-) create mode 100644 common/src/generated/resources/assets/theatrical/models/item/configuration_card.json create mode 100644 common/src/main/java/dev/imabad/theatrical/client/LazyRenderers.java create mode 100644 common/src/main/java/dev/imabad/theatrical/client/gui/screen/ConfigurationCardScreen.java create mode 100644 common/src/main/java/dev/imabad/theatrical/client/gui/widgets/BetterStringWidget.java create mode 100644 common/src/main/java/dev/imabad/theatrical/net/ConfigureConfigurationCard.java create mode 100644 common/src/main/resources/assets/theatrical/textures/item/configuration_card.png diff --git a/common/src/generated/resources/.cache/ac32a6491e9ad7e80dfd5d9683e4c90fbf53e1e6 b/common/src/generated/resources/.cache/ac32a6491e9ad7e80dfd5d9683e4c90fbf53e1e6 index ddf5dd8..a6cf055 100644 --- a/common/src/generated/resources/.cache/ac32a6491e9ad7e80dfd5d9683e4c90fbf53e1e6 +++ b/common/src/generated/resources/.cache/ac32a6491e9ad7e80dfd5d9683e4c90fbf53e1e6 @@ -1,6 +1,7 @@ -// 1.20.2 2024-07-20T12:53:36.9724263 Item Models: theatrical +// 1.20.2 2024-07-30T19:12:09.649396 Item Models: theatrical b61dea162dac1064778fccd83e00b34aeea3d2b7 assets/theatrical/models/item/artnet_interface.json b8f0135bf11be0f31f5d16d76a8c50f28900ee04 assets/theatrical/models/item/basic_lighting_desk.json +545f9e738bfe2c1e7b2236f46042b2504b81373b assets/theatrical/models/item/configuration_card.json 0dc3e30a7627a40ada8a4b8e20249c809067a337 assets/theatrical/models/item/led_fresnel.json 81307d2abd44e288e5e8c9b7824de5a0e895e0be assets/theatrical/models/item/led_panel.json e6b312509e9a1cfcd5730624d5cbd9f04781d7f7 assets/theatrical/models/item/moving_light.json diff --git a/common/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 b/common/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 index 6cba800..bdbc5fd 100644 --- a/common/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 +++ b/common/src/generated/resources/.cache/c622617f6fabf890a00b9275cd5f643584a8a2c8 @@ -1,2 +1,2 @@ -// 1.20.2 2024-07-29T23:11:39.1659592 Languages: en_us -51f24e3b8b2d0667dec3cce6b38b13b241264dc8 assets/theatrical/lang/en_us.json +// 1.20.2 2024-07-30T20:12:14.177896 Languages: en_us +dd27ac82d3d3f2c79ab7c9dcfc8cbd0ad314670e assets/theatrical/lang/en_us.json diff --git a/common/src/generated/resources/assets/theatrical/lang/en_us.json b/common/src/generated/resources/assets/theatrical/lang/en_us.json index f6bec6a..5d8a813 100644 --- a/common/src/generated/resources/assets/theatrical/lang/en_us.json +++ b/common/src/generated/resources/assets/theatrical/lang/en_us.json @@ -30,8 +30,13 @@ "fixture.dmxStart": "DMX Address", "fixture.pan": "Pan", "fixture.tilt": "Tilt", + "item.configurationcard.success": "Configured device to %s network, %s universe, %s address - next address is %s.", + "item.theatrical.configuration_card": "Configuration Card", "itemGroup.theatrical": "Theatrical", "screen.artnetconfig.enabled": "ArtNet Enabled: %s", + "screen.artnetconfig.network": "Network", + "screen.configurationcard": "Configuration Card", + "screen.configurationcard.autoincrement": "Address Auto Increment", "screen.movinglight": "Moving Light", "ui.control.cue": "Cue - %s", "ui.control.cues": "Cues", diff --git a/common/src/generated/resources/assets/theatrical/models/item/configuration_card.json b/common/src/generated/resources/assets/theatrical/models/item/configuration_card.json new file mode 100644 index 0000000..86beef4 --- /dev/null +++ b/common/src/generated/resources/assets/theatrical/models/item/configuration_card.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "theatrical:item/configuration_card" + } +} \ No newline at end of file diff --git a/common/src/main/java/dev/imabad/theatrical/TheatricalClient.java b/common/src/main/java/dev/imabad/theatrical/TheatricalClient.java index 7b35291..97fae46 100644 --- a/common/src/main/java/dev/imabad/theatrical/TheatricalClient.java +++ b/common/src/main/java/dev/imabad/theatrical/TheatricalClient.java @@ -8,6 +8,7 @@ import dev.imabad.theatrical.blockentities.BlockEntities; import dev.imabad.theatrical.blockentities.light.BaseLightBlockEntity; import dev.imabad.theatrical.blocks.light.MovingLightBlock; +import dev.imabad.theatrical.client.LazyRenderers; import dev.imabad.theatrical.client.blockentities.BasicLightingConsoleRenderer; import dev.imabad.theatrical.client.blockentities.FresnelRenderer; import dev.imabad.theatrical.client.blockentities.LEDPanelRenderer; @@ -88,6 +89,7 @@ public static void renderWorldLastAfterTripwire(LevelRenderer levelRenderer){ public static void renderWorldLast(PoseStack poseStack, Matrix4f projectionMatrix, Camera camera, float tickDelta){ Minecraft mc = Minecraft.getInstance(); + LazyRenderers.doRender(camera,poseStack, mc.renderBuffers().bufferSource(), tickDelta); if(mc.getDebugOverlay().showDebugScreen()){ Vec3 cameraPos = camera.getPosition(); //#region translateToCamera diff --git a/common/src/main/java/dev/imabad/theatrical/blocks/light/BaseLightBlock.java b/common/src/main/java/dev/imabad/theatrical/blocks/light/BaseLightBlock.java index 4f624d7..44b1f5a 100644 --- a/common/src/main/java/dev/imabad/theatrical/blocks/light/BaseLightBlock.java +++ b/common/src/main/java/dev/imabad/theatrical/blocks/light/BaseLightBlock.java @@ -5,8 +5,13 @@ import dev.imabad.theatrical.blockentities.light.LightCollisionContext; import dev.imabad.theatrical.blocks.HangableBlock; import dev.imabad.theatrical.dmx.DMXNetworkData; +import dev.imabad.theatrical.items.Items; import dev.imabad.theatrical.util.UUIDUtil; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; @@ -66,4 +71,30 @@ public void setPlacedBy(Level level, BlockPos pos, BlockState state, @Nullable L } } } + @Override + @Environment(EnvType.CLIENT) + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + if(player.getItemInHand(hand).getItem() == Items.CONFIGURATION_CARD.get()){ + if(!level.isClientSide()) { + ItemStack itemInHand = player.getItemInHand(hand); + CompoundTag tagData = itemInHand.getOrCreateTag(); + BlockEntity be = level.getBlockEntity(pos); + if (be instanceof BaseDMXConsumerLightBlockEntity consumerLightBlockEntity) { + consumerLightBlockEntity.setNetworkId(tagData.getUUID("network")); + consumerLightBlockEntity.setUniverse(tagData.getInt("dmxUniverse")); + consumerLightBlockEntity.setChannelStartPoint(tagData.getInt("dmxAddress")); + if (tagData.getBoolean("autoIncrement")) { + tagData.putInt("dmxAddress", tagData.getInt("dmxAddress") + consumerLightBlockEntity.getChannelCount()); + } + itemInHand.save(tagData); + DMXNetworkData instance = DMXNetworkData.getInstance(level.getServer().overworld()); + player.sendSystemMessage(Component.translatable("item.configurationcard.success", instance.getNetwork(consumerLightBlockEntity.getNetworkId()).name(), Integer.toString(consumerLightBlockEntity.getUniverse()), Integer.toString(consumerLightBlockEntity.getChannelStart()), Integer.toString(tagData.getInt("dmxAddress")))); + return InteractionResult.SUCCESS; + } + } else { + return InteractionResult.SUCCESS; + } + } + return super.use(state, level, pos, player, hand, hit); + } } diff --git a/common/src/main/java/dev/imabad/theatrical/blocks/light/FresnelBlock.java b/common/src/main/java/dev/imabad/theatrical/blocks/light/FresnelBlock.java index 0af85d1..04d774c 100644 --- a/common/src/main/java/dev/imabad/theatrical/blocks/light/FresnelBlock.java +++ b/common/src/main/java/dev/imabad/theatrical/blocks/light/FresnelBlock.java @@ -112,17 +112,19 @@ public VoxelShape getVisualShape(BlockState state, BlockGetter level, BlockPos p @Override @Environment(EnvType.CLIENT) public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { - if(level.isClientSide){ - if(player.isCrouching()){ - if(TheatricalClient.DEBUG_BLOCKS.contains(pos)){ - TheatricalClient.DEBUG_BLOCKS.remove(pos); - } else { - TheatricalClient.DEBUG_BLOCKS.add(pos); + if(super.use(state, level, pos, player, hand, hit) != InteractionResult.SUCCESS) { + if (level.isClientSide) { + if (player.isCrouching()) { + if (TheatricalClient.DEBUG_BLOCKS.contains(pos)) { + TheatricalClient.DEBUG_BLOCKS.remove(pos); + } else { + TheatricalClient.DEBUG_BLOCKS.add(pos); + } + return InteractionResult.SUCCESS; } - return InteractionResult.SUCCESS; + FresnelBlockEntity be = (FresnelBlockEntity) level.getBlockEntity(pos); + Minecraft.getInstance().setScreen(new FresnelScreen(be)); } - FresnelBlockEntity be = (FresnelBlockEntity)level.getBlockEntity(pos); - Minecraft.getInstance().setScreen(new FresnelScreen(be)); } return InteractionResult.SUCCESS; } diff --git a/common/src/main/java/dev/imabad/theatrical/blocks/light/LEDPanelBlock.java b/common/src/main/java/dev/imabad/theatrical/blocks/light/LEDPanelBlock.java index 7a5f1cc..55fd1dd 100644 --- a/common/src/main/java/dev/imabad/theatrical/blocks/light/LEDPanelBlock.java +++ b/common/src/main/java/dev/imabad/theatrical/blocks/light/LEDPanelBlock.java @@ -105,17 +105,19 @@ public VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPo @Override @Environment(EnvType.CLIENT) public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { - if(level.isClientSide){ - if(player.isCrouching()){ - if(TheatricalClient.DEBUG_BLOCKS.contains(pos)){ - TheatricalClient.DEBUG_BLOCKS.remove(pos); - } else { - TheatricalClient.DEBUG_BLOCKS.add(pos); + if(super.use(state, level, pos, player, hand, hit) != InteractionResult.SUCCESS) { + if (level.isClientSide) { + if (player.isCrouching()) { + if (TheatricalClient.DEBUG_BLOCKS.contains(pos)) { + TheatricalClient.DEBUG_BLOCKS.remove(pos); + } else { + TheatricalClient.DEBUG_BLOCKS.add(pos); + } + return InteractionResult.SUCCESS; } - return InteractionResult.SUCCESS; + LEDPanelBlockEntity be = (LEDPanelBlockEntity) level.getBlockEntity(pos); + Minecraft.getInstance().setScreen(new GenericDMXConfigurationScreen<>(be, pos, "block.theatrical.led_panel")); } - LEDPanelBlockEntity be = (LEDPanelBlockEntity)level.getBlockEntity(pos); - Minecraft.getInstance().setScreen(new GenericDMXConfigurationScreen<>(be, pos, "block.theatrical.led_panel")); } return InteractionResult.SUCCESS; } diff --git a/common/src/main/java/dev/imabad/theatrical/blocks/light/MovingLightBlock.java b/common/src/main/java/dev/imabad/theatrical/blocks/light/MovingLightBlock.java index e5b3d42..f5fdf21 100644 --- a/common/src/main/java/dev/imabad/theatrical/blocks/light/MovingLightBlock.java +++ b/common/src/main/java/dev/imabad/theatrical/blocks/light/MovingLightBlock.java @@ -101,17 +101,19 @@ public VoxelShape getVisualShape(BlockState state, BlockGetter level, BlockPos p @Override @Environment(EnvType.CLIENT) public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { - if(level.isClientSide){ - if(player.isCrouching()){ - if(TheatricalClient.DEBUG_BLOCKS.contains(pos)){ - TheatricalClient.DEBUG_BLOCKS.remove(pos); - } else { - TheatricalClient.DEBUG_BLOCKS.add(pos); + if(super.use(state, level, pos, player, hand, hit) != InteractionResult.SUCCESS) { + if (level.isClientSide) { + if (player.isCrouching()) { + if (TheatricalClient.DEBUG_BLOCKS.contains(pos)) { + TheatricalClient.DEBUG_BLOCKS.remove(pos); + } else { + TheatricalClient.DEBUG_BLOCKS.add(pos); + } + return InteractionResult.SUCCESS; } - return InteractionResult.SUCCESS; + MovingLightBlockEntity be = (MovingLightBlockEntity) level.getBlockEntity(pos); + Minecraft.getInstance().setScreen(new GenericDMXConfigurationScreen<>(be, pos, "block.theatrical.moving_light")); } - MovingLightBlockEntity be = (MovingLightBlockEntity)level.getBlockEntity(pos); - Minecraft.getInstance().setScreen(new GenericDMXConfigurationScreen<>(be, pos, "block.theatrical.moving_light")); } return InteractionResult.SUCCESS; } diff --git a/common/src/main/java/dev/imabad/theatrical/client/LazyRenderers.java b/common/src/main/java/dev/imabad/theatrical/client/LazyRenderers.java new file mode 100644 index 0000000..3aa0edb --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/client/LazyRenderers.java @@ -0,0 +1,50 @@ +package dev.imabad.theatrical.client; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.util.Tuple; +import net.minecraft.world.phys.Vec3; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; + +public class LazyRenderers { + + public static abstract class LazyRenderer { + public abstract void render(MultiBufferSource.BufferSource bufferSource, PoseStack poseStack, Camera camera, float partialTick); + public abstract Vec3 getPos(float partialTick); + } + + private static final List renderers = new ArrayList<>(); + + public static void addLazyRender(LazyRenderer renderer){ + renderers.add(renderer); + } + + public static void doRender(Camera camera, PoseStack poseStack, MultiBufferSource.BufferSource renderer,float partialTick){ + if(!renderers.isEmpty()){ + if(renderers.size() == 1){ + LazyRenderer first = renderers.get(0); + first.render(renderer, poseStack, camera, partialTick); + } else { + List> distanced = new ArrayList<>(); + for (LazyRenderer lazyRenderer : renderers) { + distanced.add(new Tuple<>(lazyRenderer, camera.getPosition().distanceToSqr(lazyRenderer.getPos(partialTick)))); + } + distanced.sort(Comparator.comparingDouble(t -> -t.getB())); + for (Tuple lazyRendererDoubleTuple : distanced) { + LazyRenderer a = lazyRendererDoubleTuple.getA(); + a.render(renderer, poseStack, camera, partialTick); + } + } + renderer.endBatch(); + renderers.clear(); + } + } + +} diff --git a/common/src/main/java/dev/imabad/theatrical/client/TheatricalRenderTypes.java b/common/src/main/java/dev/imabad/theatrical/client/TheatricalRenderTypes.java index 0ffdf9a..5f1b3a3 100644 --- a/common/src/main/java/dev/imabad/theatrical/client/TheatricalRenderTypes.java +++ b/common/src/main/java/dev/imabad/theatrical/client/TheatricalRenderTypes.java @@ -16,4 +16,14 @@ public class TheatricalRenderTypes { RenderType.CompositeState.builder() .setShaderState(new RenderStateShard.ShaderStateShard(GameRenderer::getPositionColorShader)) .createCompositeState(false)); + + public static final RenderType BEAM = RenderType.create( + "TheatricalBeam", + DefaultVertexFormat.POSITION_COLOR, + VertexFormat.Mode.QUADS, + 256, + false, + true, + RenderType.translucentState(new RenderStateShard.ShaderStateShard(GameRenderer::getPositionColorShader)) + ); } diff --git a/common/src/main/java/dev/imabad/theatrical/client/blockentities/FixtureRenderer.java b/common/src/main/java/dev/imabad/theatrical/client/blockentities/FixtureRenderer.java index b8675d9..1b68180 100644 --- a/common/src/main/java/dev/imabad/theatrical/client/blockentities/FixtureRenderer.java +++ b/common/src/main/java/dev/imabad/theatrical/client/blockentities/FixtureRenderer.java @@ -5,7 +5,10 @@ import dev.imabad.theatrical.blockentities.light.BaseLightBlockEntity; import dev.imabad.theatrical.blocks.HangableBlock; import dev.imabad.theatrical.blocks.light.MovingLightBlock; +import dev.imabad.theatrical.client.LazyRenderers; +import dev.imabad.theatrical.client.TheatricalRenderTypes; import dev.imabad.theatrical.config.TheatricalConfig; +import net.minecraft.client.Camera; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; @@ -35,17 +38,34 @@ public void render(T blockEntity, float partialTick, PoseStack poseStack, MultiB renderModel(blockEntity, poseStack, vertexConsumer, facing, partialTick, isFlipped, blockState, isHanging, packedLight, packedOverlay); beforeRenderBeam(blockEntity, poseStack, vertexConsumer, multiBufferSource, facing, partialTick, isFlipped, blockState, isHanging, packedLight, packedOverlay); if(shouldRenderBeam(blockEntity)){ - VertexConsumer beamConsumer = multiBufferSource.getBuffer(RenderType.lightning()); - poseStack.translate(blockEntity.getFixture().getBeamStartPosition()[0], blockEntity.getFixture().getBeamStartPosition()[1], blockEntity.getFixture().getBeamStartPosition()[2]); - float intensity = (blockEntity.getPrevIntensity() + ((blockEntity.getIntensity()) - blockEntity.getPrevIntensity()) * partialTick); - int color = blockEntity.calculatePartialColour(partialTick); - renderLightBeam(beamConsumer, poseStack, blockEntity, partialTick, (float) ((intensity * beamOpacity) / 255f), blockEntity.getFixture().getBeamWidth(), (float) blockEntity.getDistance(), color); + LazyRenderers.addLazyRender(new LazyRenderers.LazyRenderer() { + @Override + public void render(MultiBufferSource.BufferSource bufferSource, PoseStack poseStack, Camera camera, float partialTick) { + poseStack.pushPose(); + Vec3 offset = Vec3.atLowerCornerOf(blockEntity.getBlockPos()).subtract(camera.getPosition()); + poseStack.translate(offset.x, offset.y, offset.z); + preparePoseStack(blockEntity, poseStack, facing, partialTick, isFlipped, blockState, isHanging); + VertexConsumer beamConsumer = bufferSource.getBuffer(TheatricalRenderTypes.BEAM); + poseStack.translate(blockEntity.getFixture().getBeamStartPosition()[0], blockEntity.getFixture().getBeamStartPosition()[1], blockEntity.getFixture().getBeamStartPosition()[2]); + float intensity = (blockEntity.getPrevIntensity() + ((blockEntity.getIntensity()) - blockEntity.getPrevIntensity()) * partialTick); + int color = blockEntity.calculatePartialColour(partialTick); + renderLightBeam(beamConsumer, poseStack, blockEntity, partialTick, (float) ((intensity * beamOpacity) / 255f), blockEntity.getFixture().getBeamWidth(), (float) blockEntity.getDistance(), color); + poseStack.popPose(); + } + + @Override + public Vec3 getPos(float partialTick) { + return blockEntity.getBlockPos().getCenter(); + } + }); } poseStack.popPose(); } public abstract void renderModel(T blockEntity, PoseStack poseStack, VertexConsumer vertexConsumer, Direction facing, float partialTicks, boolean isFlipped, BlockState blockState, boolean isHanging, int packedLight, int packedOverlay); + public abstract void preparePoseStack(T blockEntity, PoseStack poseStack, Direction facing, float partialTicks, boolean isFlipped, BlockState blockState, boolean isHanging); + public void beforeRenderBeam(T blockEntity, PoseStack poseStack, VertexConsumer vertexConsumer, MultiBufferSource multiBufferSource, Direction facing, float partialTicks, boolean isFlipped, BlockState blockstate, boolean isHanging, int packedLight, @@ -89,7 +109,7 @@ protected void renderLightBeam(VertexConsumer builder, PoseStack stack, T tileEn } protected void addVertex(VertexConsumer builder, Matrix4f matrix4f, Matrix3f matrix3f, int r, int g, int b, int a, float x, float y, float z) { - builder.vertex(matrix4f, x, y, z).color(r, g, b, a).overlayCoords(OverlayTexture.NO_OVERLAY).normal(matrix3f, 0.0F, 1.0F, 0.0F).endVertex(); + builder.vertex(matrix4f, x, y, z).color(r, g, b, a).endVertex(); } @Override diff --git a/common/src/main/java/dev/imabad/theatrical/client/blockentities/FresnelRenderer.java b/common/src/main/java/dev/imabad/theatrical/client/blockentities/FresnelRenderer.java index beff911..251733a 100644 --- a/common/src/main/java/dev/imabad/theatrical/client/blockentities/FresnelRenderer.java +++ b/common/src/main/java/dev/imabad/theatrical/client/blockentities/FresnelRenderer.java @@ -95,4 +95,65 @@ public void renderModel(FresnelBlockEntity blockEntity, PoseStack poseStack, Ver minecraftRenderModel(poseStack, vertexConsumer, blockState, cachedTiltModel, packedLight, packedOverlay); //#endregion } + + @Override + public void preparePoseStack(FresnelBlockEntity blockEntity, PoseStack poseStack, Direction facing, float partialTicks, boolean isFlipped, BlockState blockState, boolean isHanging) { + //#region Fixture Hanging + poseStack.translate(0.5F, 0, .5F); + if(isHanging){ + Direction hangDirection = blockState.getValue(HangableBlock.HANG_DIRECTION); + poseStack.translate(0, 0.5, 0F); + if(hangDirection.getAxis() != Direction.Axis.Y){ + if(hangDirection.getAxis() == Direction.Axis.Z){ + if(hangDirection == Direction.SOUTH) { + poseStack.mulPose(Axis.XP.rotationDegrees(90)); + } else { + poseStack.mulPose(Axis.XN.rotationDegrees(90)); + } + } else { + if(hangDirection == Direction.EAST) { + poseStack.mulPose(Axis.ZN.rotationDegrees(90)); + } else { + poseStack.mulPose(Axis.ZN.rotationDegrees(-90)); + } + } + } else { + //TODO: Handle hanging up + } + poseStack.translate(0, -0.5, 0F); + } + //#endregion + if(facing.getAxis() == Direction.Axis.X){ + poseStack.mulPose(Axis.YP.rotationDegrees(facing.toYRot())); + } else { + poseStack.mulPose(Axis.YP.rotationDegrees(facing.getOpposite().toYRot())); + } + poseStack.translate(-0.5F, 0, -.5F); + if (isHanging) { + Optional optionalSupport = blockEntity.getSupportingStructure(); + if (optionalSupport.isPresent()) { + float[] transforms = blockEntity.getFixture().getTransforms(blockState, optionalSupport.get()); + poseStack.translate(transforms[0], transforms[1], transforms[2]); + } else { + poseStack.translate(0, 0.19, 0); + } + } + //#region Model Pan + float[] pans = blockEntity.getFixture().getPanRotationPosition(); + poseStack.translate(pans[0], pans[1], pans[2]); + int prevPan = blockEntity.getPrevPan(); + int pan = blockEntity.getPan(); + poseStack.mulPose(Axis.YN.rotationDegrees((prevPan + (pan - prevPan) * partialTicks))); + poseStack.translate(-pans[0], -pans[1], -pans[2]); + //#endregion + //#region Model Tilt + float[] tilts = blockEntity.getFixture().getTiltRotationPosition(); + poseStack.translate(tilts[0], tilts[1], tilts[2]); + int prevTilt = blockEntity.getPrevTilt(); + int tilt = blockEntity.getTilt(); +// poseStack.mulPose(Axis.XP.rotationDegrees(180)); + poseStack.mulPose(Axis.XP.rotationDegrees((prevTilt + (tilt - prevTilt) * partialTicks))); + poseStack.translate(-tilts[0], -tilts[1], -tilts[2]); + //#endregion + } } diff --git a/common/src/main/java/dev/imabad/theatrical/client/blockentities/LEDPanelRenderer.java b/common/src/main/java/dev/imabad/theatrical/client/blockentities/LEDPanelRenderer.java index b383541..b6cfecd 100644 --- a/common/src/main/java/dev/imabad/theatrical/client/blockentities/LEDPanelRenderer.java +++ b/common/src/main/java/dev/imabad/theatrical/client/blockentities/LEDPanelRenderer.java @@ -87,4 +87,42 @@ public void beforeRenderBeam(LEDPanelBlockEntity blockEntity, PoseStack poseStac addVertex(beamConsumer, m, normal, r, g, b, a,0, 0, 0); } } + + @Override + public void preparePoseStack(LEDPanelBlockEntity blockEntity, PoseStack poseStack, Direction facing, float partialTicks, boolean isFlipped, BlockState blockState, boolean isHanging) { + //#region Fixture Hanging + poseStack.translate(0.5F, 0, .5F); + if(isHanging){ + Direction hangDirection = blockState.getValue(HangableBlock.HANG_DIRECTION); + poseStack.translate(0, 0.5, 0F); + if(hangDirection.getAxis() != Direction.Axis.Y){ + if(hangDirection.getAxis() == Direction.Axis.Z){ + if(hangDirection == Direction.SOUTH) { +// poseStack.mulPose(Axis.ZP.rotationDegrees(90)); + poseStack.mulPose(Axis.XN.rotationDegrees(180)); + } else { + poseStack.mulPose(Axis.XN.rotationDegrees(180)); + } + } + } else { + if(hangDirection == Direction.UP){ + poseStack.mulPose(Axis.ZN.rotationDegrees(90)); + poseStack.mulPose(Axis.XP.rotationDegrees(90)); + } + } + poseStack.translate(0, -0.5, 0F); + } + //#endregion + poseStack.mulPose(Axis.YP.rotationDegrees(facing.toYRot())); + poseStack.translate(-0.5F, 0, -.5F); + if (isHanging) { + Optional optionalSupport = blockEntity.getSupportingStructure(); + if (optionalSupport.isPresent()) { + float[] transforms = blockEntity.getFixture().getTransforms(blockState, optionalSupport.get()); + poseStack.translate(transforms[0], transforms[1], transforms[2]); + } else { + poseStack.translate(0, 0.19, 0); + } + } + } } diff --git a/common/src/main/java/dev/imabad/theatrical/client/blockentities/MovingLightRenderer.java b/common/src/main/java/dev/imabad/theatrical/client/blockentities/MovingLightRenderer.java index 0efe57b..62feb11 100644 --- a/common/src/main/java/dev/imabad/theatrical/client/blockentities/MovingLightRenderer.java +++ b/common/src/main/java/dev/imabad/theatrical/client/blockentities/MovingLightRenderer.java @@ -105,4 +105,71 @@ public void renderModel(MovingLightBlockEntity blockEntity, PoseStack poseStack, minecraftRenderModel(poseStack, vertexConsumer, blockState, cachedTiltModel, packedLight, packedOverlay); //#endregion } + + @Override + public void preparePoseStack(MovingLightBlockEntity blockEntity, PoseStack poseStack, Direction facing, float partialTicks, boolean isFlipped, BlockState blockState, boolean isHanging) { + poseStack.translate(0.5F, 0, .5F); + if(isHanging){ + Direction hangDirection = blockState.getValue(HangableBlock.HANG_DIRECTION); + poseStack.translate(0, 0.5, 0F); + if(hangDirection.getAxis() != Direction.Axis.Y){ + if(hangDirection.getAxis() == Direction.Axis.Z){ + if(hangDirection == Direction.SOUTH) { + poseStack.mulPose(Axis.ZP.rotationDegrees(90)); + poseStack.mulPose(Axis.XP.rotationDegrees(-90)); + } else { + poseStack.mulPose(Axis.ZP.rotationDegrees(90)); + poseStack.mulPose(Axis.XP.rotationDegrees(90)); + } + } else { + if(hangDirection == Direction.EAST) { + poseStack.mulPose(Axis.ZN.rotationDegrees(-90)); + } else { + poseStack.mulPose(Axis.ZN.rotationDegrees(90)); + } + } + } else { + //TODO: Handle hanging up + } + poseStack.translate(0, -0.5, 0F); + } + //#endregion + poseStack.mulPose(Axis.YP.rotationDegrees(facing.toYRot())); + poseStack.translate(-0.5F, 0, -.5F); + if (isHanging) { + Optional optionalSupport = blockEntity.getSupportingStructure(); + if (optionalSupport.isPresent()) { + float[] transforms = blockEntity.getFixture().getTransforms(blockState, optionalSupport.get()); + poseStack.translate(transforms[0], transforms[1], transforms[2]); + } else { + poseStack.translate(0, 0.19, 0); + } + poseStack.translate(0, -0.08, 0); + } + if (isFlipped) { + poseStack.translate(0.5F, 0.5, .5F); + poseStack.mulPose(Axis.ZP.rotationDegrees(180)); + poseStack.translate(-0.5F, -0.5, -.5F); + } + float[] pans = blockEntity.getFixture().getPanRotationPosition(); + poseStack.translate(pans[0], pans[1], pans[2]); + int prevPan = blockEntity.getPrevPan(); + int pan = blockEntity.getPan(); + poseStack.mulPose(Axis.YP.rotationDegrees((prevPan + (pan - prevPan) * partialTicks))); + poseStack.translate(-pans[0], -pans[1], -pans[2]); + //#endregion + //#region Model Tilt + float[] tilts = blockEntity.getFixture().getTiltRotationPosition(); + poseStack.translate(tilts[0], tilts[1], tilts[2]); + int prevTilt = blockEntity.getPrevTilt(); + int tilt = blockEntity.getTilt(); + if (isFlipped) { + poseStack.mulPose(Axis.XP.rotationDegrees(-180)); + } else { + poseStack.mulPose(Axis.XP.rotationDegrees(180)); + } + poseStack.mulPose(Axis.XP.rotationDegrees((prevTilt + (tilt - prevTilt) * partialTicks))); + poseStack.translate(-tilts[0], -tilts[1], -tilts[2]); + //#endregion + } } diff --git a/common/src/main/java/dev/imabad/theatrical/client/gui/screen/ConfigurationCardScreen.java b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/ConfigurationCardScreen.java new file mode 100644 index 0000000..b08e3af --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/client/gui/screen/ConfigurationCardScreen.java @@ -0,0 +1,137 @@ +package dev.imabad.theatrical.client.gui.screen; + +import dev.imabad.theatrical.Theatrical; +import dev.imabad.theatrical.TheatricalClient; +import dev.imabad.theatrical.client.gui.widgets.BetterStringWidget; +import dev.imabad.theatrical.client.gui.widgets.LabeledEditBox; +import dev.imabad.theatrical.net.ConfigureConfigurationCard; +import dev.imabad.theatrical.net.UpdateDMXFixture; +import dev.imabad.theatrical.net.UpdateNetworkId; +import dev.imabad.theatrical.util.UUIDUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.Checkbox; +import net.minecraft.client.gui.components.CycleButton; +import net.minecraft.client.gui.components.StringWidget; +import net.minecraft.client.gui.layouts.FrameLayout; +import net.minecraft.client.gui.layouts.LinearLayout; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; + +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ConfigurationCardScreen extends Screen { + private final ResourceLocation GUI = new ResourceLocation(Theatrical.MOD_ID, "textures/gui/blank.png"); + protected final int imageWidth; + protected final int imageHeight; + protected int xCenter; + protected int yCenter; + protected LinearLayout layout; + private LabeledEditBox dmxAddress, dmxUniverse; + private Checkbox autoIncrement; + private UUID networkId = UUIDUtil.NULL; + private CompoundTag itemData; + public ConfigurationCardScreen(CompoundTag itemData) { + super(Component.translatable("screen.configurationcard")); + this.imageWidth = 176; + this.imageHeight = 126; + this.itemData = itemData; + if(itemData.hasUUID("network")) { + this.networkId = itemData.getUUID("network"); + } + } + @Override + protected void init() { + super.init(); + layout = new LinearLayout(imageWidth, imageHeight, LinearLayout.Orientation.VERTICAL); + layout.defaultCellSetting().alignHorizontallyCenter().padding(10); + layout.addChild(new BetterStringWidget(Component.translatable("screen.configurationcard"), this.font).setColor(4210752).setShadow(false)); + this.dmxUniverse = new LabeledEditBox(this.font, xCenter, yCenter, 50, 10, Component.translatable("artneti.dmxUniverse")); + if(itemData.contains("dmxUniverse")){ + this.dmxUniverse.setValue(Integer.toString(itemData.getInt("dmxUniverse"))); + } else { + this.dmxUniverse.setValue("0"); + } + layout.addChild(dmxUniverse); + layout.addChild(new CycleButton.Builder((networkId) -> + { + if (TheatricalClient.getArtNetManager().getKnownNetworks().containsKey(networkId)) { + return Component.literal(TheatricalClient.getArtNetManager().getKnownNetworks().get(networkId)); + } + return Component.literal("Unknown"); + } + ).withValues(CycleButton.ValueListSupplier.create(Stream.concat(Stream.of(UUIDUtil.NULL), + TheatricalClient.getArtNetManager().getKnownNetworks().keySet().stream()).collect(Collectors.toList()))) + .displayOnlyValue().withInitialValue(networkId) + .create(xCenter, yCenter, 150, 20, + Component.translatable("screen.artnetconfig.network"), (obj, val) -> { + this.networkId = val; + })); + + this.dmxAddress = new LabeledEditBox(this.font, xCenter, yCenter, 50, 10, Component.translatable("fixture.dmxStart")); + if(itemData.contains("dmxAddress")){ + this.dmxAddress.setValue(Integer.toString(itemData.getInt("dmxAddress"))); + }else { + this.dmxAddress.setValue("0"); + } + layout.addChild(dmxAddress); + this.autoIncrement = new Checkbox(xCenter, yCenter, 150, 20, Component.translatable("screen.configurationcard.autoincrement"), itemData.getBoolean("autoIncrement")); + + layout.addChild(autoIncrement); + layout.addChild( + new Button.Builder(Component.translatable("artneti.save"), button -> this.update()) + .pos(xCenter, yCenter) + .size(100, 20) + .build() + ); + refreshLayout(); + this.repositionElements(); + + } + protected void refreshLayout(){ + if(layout == null) + return; + layout.arrangeElements(); + layout.visitWidgets(this::addRenderableWidget); + } + + protected void repositionElements() { + FrameLayout.centerInRectangle(this.layout, this.getRectangle()); + } + + protected void update(){ + try { + int dmx = Integer.parseInt(this.dmxAddress.getValue()); + if (dmx > 512 || dmx < 0) { + return; + } + int universe = Integer.parseInt(this.dmxUniverse.getValue()); + if (universe > 16 || universe < 0) { + return; + } + new ConfigureConfigurationCard(networkId, dmx, universe, autoIncrement.selected()).sendToServer(); + Minecraft.getInstance().setScreen(null); + } catch(NumberFormatException ignored) { + //We need a nicer way to show that this is invalid? + } + } + @Override + public void renderBackground(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + super.renderBackground(guiGraphics, mouseX, mouseY, partialTick); + this.renderWindow(guiGraphics); + } + private void renderWindow(GuiGraphics guiGraphics){ + int layoutHeight = 0; + if(layout != null) { + layoutHeight = layout.getHeight(); + } + int relX = (this.width - this.imageWidth) / 2; + int relY = (this.height - layoutHeight) / 2; + guiGraphics.blit(GUI, relX, relY, imageWidth, layoutHeight, 0, 0, this.imageWidth, this.imageHeight, 256,256); + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/client/gui/widgets/BetterStringWidget.java b/common/src/main/java/dev/imabad/theatrical/client/gui/widgets/BetterStringWidget.java new file mode 100644 index 0000000..8c0c3d6 --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/client/gui/widgets/BetterStringWidget.java @@ -0,0 +1,40 @@ +package dev.imabad.theatrical.client.gui.widgets; + +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.StringWidget; +import net.minecraft.network.chat.Component; +import net.minecraft.util.FormattedCharSequence; + +public class BetterStringWidget extends StringWidget { + private float alignX = 0.5F; + private boolean shadow = true; + + public BetterStringWidget(Component message, Font font) { + super(message, font); + } + + public BetterStringWidget setShadow(boolean shadow) { + this.shadow = shadow; + return this; + } + + public BetterStringWidget setColor(int color) { + super.setColor(color); + return this; + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + Component component = this.getMessage(); + Font font = this.getFont(); + int i = this.getWidth(); + int j = font.width(component); + int k = this.getX() + Math.round(this.alignX * (float)(i - j)); + int l = this.getY() + (this.getHeight() - 9) / 2; + FormattedCharSequence formattedCharSequence = component.getVisualOrderText(); + guiGraphics.drawString(font, formattedCharSequence, k, l, this.getColor(), shadow); + } + + +} diff --git a/common/src/main/java/dev/imabad/theatrical/client/gui/widgets/LabeledEditBox.java b/common/src/main/java/dev/imabad/theatrical/client/gui/widgets/LabeledEditBox.java index 066ee46..be55cc4 100644 --- a/common/src/main/java/dev/imabad/theatrical/client/gui/widgets/LabeledEditBox.java +++ b/common/src/main/java/dev/imabad/theatrical/client/gui/widgets/LabeledEditBox.java @@ -15,7 +15,7 @@ public class LabeledEditBox extends EditBox { private float alignX = 0.5F; private Font font; - private int color = 0xffffff; + private int color = 4210752; public LabeledEditBox(Font font, int width, int height, Component message) { super(font, width, height, message); @@ -69,7 +69,7 @@ public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float int l = this.getY() + (this.getHeight() - 9) / 2; // j > i ? this.clipText(component, i) : FormattedCharSequence formattedCharSequence = component.getVisualOrderText(); - guiGraphics.drawString(font, formattedCharSequence, k, l - (font.lineHeight), color); + guiGraphics.drawString(font, formattedCharSequence, k, l - (font.lineHeight), color, false); } private FormattedCharSequence clipText(Component message, int width) { diff --git a/common/src/main/java/dev/imabad/theatrical/items/ConfigurationCard.java b/common/src/main/java/dev/imabad/theatrical/items/ConfigurationCard.java index 1fceb7d..0a947c1 100644 --- a/common/src/main/java/dev/imabad/theatrical/items/ConfigurationCard.java +++ b/common/src/main/java/dev/imabad/theatrical/items/ConfigurationCard.java @@ -1,6 +1,9 @@ package dev.imabad.theatrical.items; import dev.imabad.theatrical.Theatrical; +import dev.imabad.theatrical.client.gui.screen.ConfigurationCardScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.nbt.CompoundTag; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.player.Player; @@ -15,7 +18,9 @@ public ConfigurationCard() { @Override public InteractionResultHolder use(Level level, Player player, InteractionHand usedHand) { - if(player.isCrouching()){ + if(player.isCrouching() && level.isClientSide()){ + CompoundTag cardData = player.getItemInHand(usedHand).getOrCreateTag(); + Minecraft.getInstance().setScreen(new ConfigurationCardScreen(cardData)); //TODO: Open UI return InteractionResultHolder.pass(player.getItemInHand(usedHand)); } diff --git a/common/src/main/java/dev/imabad/theatrical/items/Items.java b/common/src/main/java/dev/imabad/theatrical/items/Items.java index 5a22522..62efd32 100644 --- a/common/src/main/java/dev/imabad/theatrical/items/Items.java +++ b/common/src/main/java/dev/imabad/theatrical/items/Items.java @@ -47,4 +47,8 @@ public class Items { "basic_lighting_desk", () -> new BlockItem(Blocks.BASIC_LIGHTING_DESK.get(), new Item.Properties().arch$tab(Theatrical.TAB)) ); + public static final RegistrySupplier CONFIGURATION_CARD = ITEMS.register( + "configuration_card", + ConfigurationCard::new + ); } diff --git a/common/src/main/java/dev/imabad/theatrical/net/ConfigureConfigurationCard.java b/common/src/main/java/dev/imabad/theatrical/net/ConfigureConfigurationCard.java new file mode 100644 index 0000000..3cfb1c0 --- /dev/null +++ b/common/src/main/java/dev/imabad/theatrical/net/ConfigureConfigurationCard.java @@ -0,0 +1,68 @@ +package dev.imabad.theatrical.net; + +import dev.architectury.networking.NetworkManager; +import dev.architectury.networking.simple.BaseC2SMessage; +import dev.architectury.networking.simple.MessageType; +import dev.imabad.theatrical.items.Items; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; + +import java.util.UUID; + +public class ConfigureConfigurationCard extends BaseC2SMessage { + + private UUID network; + private int dmxAddress, dmxUniverse; + private boolean autoIncrement; + + public ConfigureConfigurationCard(UUID network, int dmxAddress, int dmxUniverse, boolean autoIncrement) { + this.network = network; + this.dmxAddress = dmxAddress; + this.dmxUniverse = dmxUniverse; + this.autoIncrement = autoIncrement; + } + + public ConfigureConfigurationCard(FriendlyByteBuf buf){ + this.network = buf.readUUID(); + this.dmxAddress = buf.readInt(); + this.dmxUniverse = buf.readInt(); + this.autoIncrement = buf.readBoolean(); + } + + @Override + public MessageType getType() { + return TheatricalNet.CONFIGURE_CONFIGURATION_CARD; + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeUUID(network); + buf.writeInt(dmxAddress); + buf.writeInt(dmxUniverse); + buf.writeBoolean(autoIncrement); + } + + @Override + public void handle(NetworkManager.PacketContext context) { + context.queue(() -> { + Player player = context.getPlayer(); + ItemStack itemStack = null; + if(player.getItemInHand(InteractionHand.MAIN_HAND).getItem() == Items.CONFIGURATION_CARD.get()){ + itemStack = player.getItemInHand(InteractionHand.MAIN_HAND); + } else if(player.getItemInHand(InteractionHand.OFF_HAND).getItem() == Items.CONFIGURATION_CARD.get()){ + itemStack = player.getItemInHand(InteractionHand.OFF_HAND); + } + if(itemStack != null){ + CompoundTag dataTag = itemStack.getOrCreateTag(); + dataTag.putUUID("network", network); + dataTag.putInt("dmxUniverse", dmxUniverse); + dataTag.putInt("dmxAddress", dmxAddress); + dataTag.putBoolean("autoIncrement", autoIncrement); + itemStack.save(dataTag); + } + }); + } +} diff --git a/common/src/main/java/dev/imabad/theatrical/net/TheatricalNet.java b/common/src/main/java/dev/imabad/theatrical/net/TheatricalNet.java index fb324d6..250577b 100644 --- a/common/src/main/java/dev/imabad/theatrical/net/TheatricalNet.java +++ b/common/src/main/java/dev/imabad/theatrical/net/TheatricalNet.java @@ -20,6 +20,7 @@ public interface TheatricalNet { MessageType CONTROL_GO = MAIN.registerC2S("control_go", ControlGo::new); MessageType REQUEST_NETWORKS = MAIN.registerC2S("request_networks", RequestNetworks::new); MessageType UPDATE_NETWORK_ID = MAIN.registerC2S("update_network_id", UpdateNetworkId::new); + MessageType CONFIGURE_CONFIGURATION_CARD = MAIN.registerC2S("configure_configuration_card", ConfigureConfigurationCard::new); // S2C MessageType NOTIFY_CONSUMER_CHANGE = MAIN.registerS2C("notify_consumer_change", NotifyConsumerChange::new); diff --git a/common/src/main/resources/assets/theatrical/textures/item/configuration_card.png b/common/src/main/resources/assets/theatrical/textures/item/configuration_card.png new file mode 100644 index 0000000000000000000000000000000000000000..e67a26fd347b249c5b854cc0c10ebdc8448f1900 GIT binary patch literal 2046 zcmVCML#28Tkhs zIFvNBKm*+n{t3}Y1N}kU5l4>v115y1k%=LuBZ9^^x-s!h?vw6w>eM+^Zy>d$<=z_g z$2q%duf5jVyO^~WZl!4o-}jMa8Kjf|fIQD3ga80oYcW1PZo@D{nx^2K^P{693Sg}T zV+?<`TufsO@;ryn7Xk|Y7=9E>qDK0a=X#bV(8 zcd^{2S(f4ae`oLgi0Ke8#=u&OgM$MkNdn*ZVT^&+8ihguoO9f}ch3qTu(`Pj&-1Xb zut4t_W57B8XSdt^ueBCQk^lgtl;E6GLO~GV+O=yCLVz*$0|CYugb=XS!t*>xDG>w# z9Ned;r<6eyMbKKK)9GM)dz%hmjQP5-uwZ9qX2zo^A~alFAq3JirBVzb;A-^d%^T!- z4k;!2{XW%pX=%x3S%!AI4Jjq8we*gZ5=oLE2m(w`PlIy~&+}ldMZI2Uj4`Ua5CS)E z-lP&p`XK2e7-Kj+JtY*9B%v%AW3*uyhKS=B08l6tV6DaO?k zg75oaj6o@da=DB`p#WnH(lmt-;vcC>lZwOYus3{e!p^SnQP`|US7IXU_31q1+K ze}A8d;&~p*<#Lqg`M?;1Znuj(&mG~w7{m7VHc4xBbrqa*I*3z96h(;Rm=sYim%%wl zuh(OQfVCD{YuY%^b69J^IUht(gx%d;c%BEw7{V|_p-_Mj0;{X5B**pjb*!(ildK)v z(=?@cNs^ExhY-+O!}C16di9E&uT&}tV@zg@!OqSO8jS|5wV0cmLl}niUJwLShGw%# z22`z9Nij}#)oK-4mcba~9UUEIgn)BAcc3#EGvD{oY&PL}9u^lD0RWv&2M-@Ugw`6? zTBK=8@0QDDtgNhHbaWJ(o1190T40P(f=VeT;S4xu#d)41%Q9%K5yvq(VI0Re&y#Ak ziuw6@c%FxijSXyVZNc+A(zt`STrOj6Z4HCL0QGtuj4{m4&cgS7SZn`QC=`ZEaAu`= z{rWWqg8|mo)~qpxG8ha72*Z$M=6N0lg8@374zesmp694mtHh-+42gtc7$VCuOixcE z2m)}tM0 zq-ly)s|6thlv1eGYDm)*K@gA$`M!_AU;rs4=I7^OtwpQVVgN8THAVXkS@D@Xes?W- zWMl+NDF`9JIj0gxDKR%UhjO_L-}kY-y^VIeO~^SUg%I#O4{4f0YmF?+sAssuhg2{* zIXTKX|JH7|5yvs2D54S=WAOa>b4*N3U~Fs*K@cFzGH}kJwMMhqB>Sz^Y9z_IxjE!{ zj>nH5vpmnCl)~-Xw=W`a7U-MfLKH<%N?pM{h?XF8PnUhZ|T(EzJ0@s7cbE3^>Fv@ zU6QOZ1}iHoNRk9vYt(8roDCyVN=c6Cdd?66QcCT49-7T2q9{TbhBSQkdOezs&aX?C zE`f87AP6Wc*MvCd)V`a|X0DW?9^u;kg%Y@-(LLy<x!;5pI=16VzKzE5aK^dDUx2jUPqx&Kpe+-|NcD=4-aWLotm1$<;#}=08tcC zX0D%9Dis7lfJURioHCq*&&!YwaOKJscQ^REwf2uZ&k;ot(lmwh1kO2*kB{;3<44@N za|c2Q31ar6B zMZe!ip-><~IhneELI}*x&brN*@B4W0-~r7AK@i}^jT>|eyD*gQ@9)#YF6h$Il67)) zJ;IId?(*Vn+xLAMxd5;~=)M_=G=Q-JI z7=~yx8Z<*%Yf&nd;QKx{Ha1ug1mt|~87U>MU%yVhV5k`Z-!-bW#$YfQI<*Vh?RJ?` z>KDcs(lkY>R6?~{rD4=vxAOHXW literal 0 HcmV?d00001 diff --git a/common/src/main/resources/theatrical.accesswidener b/common/src/main/resources/theatrical.accesswidener index c5ffbcd..e909a28 100644 --- a/common/src/main/resources/theatrical.accesswidener +++ b/common/src/main/resources/theatrical.accesswidener @@ -1,4 +1,5 @@ accessWidener v2 named accessible field net/minecraft/client/renderer/block/model/BlockModel textureMap Ljava/util/Map; accessible field net/minecraft/server/network/ServerGamePacketListenerImpl ackBlockChangesUpTo I -mutable field net/minecraft/world/level/ClipContext collisionContext Lnet/minecraft/world/phys/shapes/CollisionContext; \ No newline at end of file +mutable field net/minecraft/world/level/ClipContext collisionContext Lnet/minecraft/world/phys/shapes/CollisionContext; +accessible method net/minecraft/client/renderer/RenderType translucentState (Lnet/minecraft/client/renderer/RenderStateShard$ShaderStateShard;)Lnet/minecraft/client/renderer/RenderType$CompositeState; \ No newline at end of file diff --git a/neoforge/src/main/java/dev/imabad/theatrical/neoforge/DataEvent.java b/neoforge/src/main/java/dev/imabad/theatrical/neoforge/DataEvent.java index af91081..dd7bb7b 100644 --- a/neoforge/src/main/java/dev/imabad/theatrical/neoforge/DataEvent.java +++ b/neoforge/src/main/java/dev/imabad/theatrical/neoforge/DataEvent.java @@ -3,6 +3,7 @@ import dev.imabad.theatrical.Theatrical; import dev.imabad.theatrical.blocks.Blocks; import dev.imabad.theatrical.blocks.rigging.TankTrapBlock; +import dev.imabad.theatrical.items.Items; import net.minecraft.data.DataGenerator; import net.minecraft.data.PackOutput; import net.minecraft.resources.ResourceLocation; @@ -68,6 +69,8 @@ protected void registerModels() { withExistingParent(Blocks.TANK_TRAP.getId().getPath(), new ResourceLocation(Theatrical.MOD_ID, "block/tank_trap")); withExistingParent(Blocks.LED_PANEL.getId().getPath(), new ResourceLocation(Theatrical.MOD_ID, "block/led_panel")); withExistingParent(Blocks.BASIC_LIGHTING_DESK.getId().getPath(), new ResourceLocation(Theatrical.MOD_ID, "block/lighting_console")); + withExistingParent(Items.CONFIGURATION_CARD.getId().getPath(), mcLoc("item/generated")) + .texture("layer0", new ResourceLocation(Theatrical.MOD_ID, "item/configuration_card")); } } @@ -88,6 +91,7 @@ protected void addTranslations() { addBlock(Blocks.TANK_TRAP, "Tank Trap"); addBlock(Blocks.LED_PANEL, "LED Panel"); addBlock(Blocks.BASIC_LIGHTING_DESK, "Basic Lighting Desk"); + addItem(Items.CONFIGURATION_CARD, "Configuration Card"); add("itemGroup.theatrical", "Theatrical"); add("artneti.dmxUniverse", "DMX Universe"); add("artneti.ipAddress", "IP Address"); @@ -120,6 +124,10 @@ protected void addTranslations() { add("commands.network.created", "Network created"); add("commands.network.deleted", "Network deleted"); add("commands.network.updated", "Network updated"); + add("screen.configurationcard.autoincrement", "Address Auto Increment"); + add("screen.configurationcard", "Configuration Card"); + add("screen.artnetconfig.network", "Network"); + add("item.configurationcard.success", "Configured device to %s network, universe %s and address %s - next address is %s."); } }