diff --git a/src/main/java/appeng/client/gui/implementations/GuiCraftConfirm.java b/src/main/java/appeng/client/gui/implementations/GuiCraftConfirm.java index b46eab55b..fac0e3fc9 100644 --- a/src/main/java/appeng/client/gui/implementations/GuiCraftConfirm.java +++ b/src/main/java/appeng/client/gui/implementations/GuiCraftConfirm.java @@ -137,9 +137,8 @@ public class GuiCraftConfirm extends AEBaseGui { String btnTextText = GuiText.CraftingCPU.getLocal() + ": " + GuiText.Automatic.getLocal(); if (this.container.getSelectedCpu() >= 0)// && status.selectedCpu < status.cpus.size() ) { - if (this.container.getName().length() > 0) { - final String name = this.container.getName().substring(0, - Math.min(20, this.container.getName().length())); + if (this.container.getName() != null) { + final String name = this.container.getName().getStringTruncated(20); btnTextText = GuiText.CraftingCPU.getLocal() + ": " + name; } else { btnTextText = GuiText.CraftingCPU.getLocal() + ": #" + this.container.getSelectedCpu(); diff --git a/src/main/java/appeng/client/gui/implementations/GuiCraftingStatus.java b/src/main/java/appeng/client/gui/implementations/GuiCraftingStatus.java index 2a2bd0dae..3175c9289 100644 --- a/src/main/java/appeng/client/gui/implementations/GuiCraftingStatus.java +++ b/src/main/java/appeng/client/gui/implementations/GuiCraftingStatus.java @@ -70,8 +70,8 @@ public class GuiCraftingStatus extends GuiCraftingCPU { if (this.container.selectedCpu >= 0)// && status.selectedCpu < status.cpus.size() ) { - if (this.container.myName.length() > 0) { - final String name = this.container.myName.substring(0, Math.min(20, this.container.myName.length())); + if (this.container.myName != null) { + final String name = this.container.myName.getStringTruncated(20); btnTextText = GuiText.CPUs.getLocal() + ": " + name; } else { btnTextText = GuiText.CPUs.getLocal() + ": #" + this.container.selectedCpu; diff --git a/src/main/java/appeng/container/guisync/SyncData.java b/src/main/java/appeng/container/guisync/SyncData.java index e00cc4413..d90e2b0d0 100644 --- a/src/main/java/appeng/container/guisync/SyncData.java +++ b/src/main/java/appeng/container/guisync/SyncData.java @@ -18,12 +18,14 @@ package appeng.container.guisync; -import java.io.IOException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import java.lang.reflect.Field; -import java.util.EnumSet; +import java.util.Objects; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.container.IContainerListener; +import net.minecraft.util.text.ITextComponent; import appeng.container.AEBaseContainer; import appeng.core.AELog; @@ -31,18 +33,33 @@ import appeng.core.sync.network.NetworkHandler; import appeng.core.sync.packets.PacketProgressBar; import appeng.core.sync.packets.PacketValueConfig; +/** + * This class is responsible for synchronizing Container-fields from server to + * client. + */ public class SyncData { private final AEBaseContainer source; private final Field field; + private final Class fieldType; private final int channel; + private final MethodHandle getter; + private final MethodHandle setter; private Object clientVersion; public SyncData(final AEBaseContainer container, final Field field, final GuiSync annotation) { this.clientVersion = null; this.source = container; - this.field = field; this.channel = annotation.value(); + this.field = field; + this.fieldType = field.getType(); + try { + this.getter = MethodHandles.publicLookup().unreflectGetter(field); + this.setter = MethodHandles.publicLookup().unreflectSetter(field); + } catch (IllegalAccessException e) { + throw new RuntimeException( + "Failed to get accessor for field " + field + ". Did you forget to make it public?"); + } } public int getChannel() { @@ -50,96 +67,119 @@ public class SyncData { } public void tick(final IContainerListener c) { + try { - final Object val = this.field.get(this.source); - if (val != null && this.clientVersion == null) { - this.send(c, val); - } else if (!val.equals(this.clientVersion)) { + final Object val = this.getter.invoke(source); + if (!Objects.equals(val, this.clientVersion)) { this.send(c, val); } - } catch (final IllegalArgumentException | IllegalAccessException e) { + } catch (Throwable e) { AELog.debug(e); } } - private void send(final IContainerListener o, final Object val) { - if (val instanceof String) { + private void send(final IContainerListener o, Object val) { + if (fieldType.isAssignableFrom(ITextComponent.class)) { + if (o instanceof ServerPlayerEntity) { + String json = ""; + if (val != null) { + json = ITextComponent.Serializer.toJson((ITextComponent) val); + } + NetworkHandler.instance().sendTo(new PacketValueConfig("SyncDat." + this.channel, json), + (ServerPlayerEntity) o); + } + } + + // Types other than ITextComponent must be non-null + if (val == null) { + return; + } + + if (fieldType.equals(String.class)) { if (o instanceof ServerPlayerEntity) { NetworkHandler.instance().sendTo(new PacketValueConfig("SyncDat." + this.channel, (String) val), (ServerPlayerEntity) o); } - } else if (this.field.getType().isEnum()) { - o.sendWindowProperty(this.source, this.channel, ((Enum) val).ordinal()); - } else if (val instanceof Long || val.getClass() == long.class) { + } else if (this.fieldType.isEnum()) { + o.sendWindowProperty(this.source, this.channel, ((Enum) val).ordinal()); + } else if (val instanceof Long) { if (o instanceof ServerPlayerEntity) { NetworkHandler.instance().sendTo(new PacketProgressBar(this.channel, (Long) val), (ServerPlayerEntity) o); } - } else if (val instanceof Boolean || val.getClass() == boolean.class) { + } else if (fieldType.equals(Boolean.class) || fieldType.equals(boolean.class)) { o.sendWindowProperty(this.source, this.channel, ((Boolean) val) ? 1 : 0); - } else { + } else if (fieldType.equals(Integer.class) || fieldType.equals(int.class)) { o.sendWindowProperty(this.source, this.channel, (Integer) val); + } else { + throw new IllegalStateException("Unknown field type: " + fieldType); } this.clientVersion = val; } - public void update(final Object val) { + public void update(Object val) { try { - final Object oldValue = this.field.get(this.source); + final Object oldValue = this.getter.invoke(source); if (val instanceof String) { - this.updateString(oldValue, (String) val); + if (this.fieldType.isAssignableFrom(ITextComponent.class)) { + String json = (String) val; + ITextComponent text = null; + if (!json.isEmpty()) { + text = ITextComponent.Serializer.fromJson((String) val); + } + this.updateTextComponent(text); + } else { + this.updateString((String) val); + } } else { this.updateValue(oldValue, (Long) val); } - } catch (final IllegalArgumentException e) { - AELog.debug(e); - } catch (final IllegalAccessException e) { + } catch (Throwable e) { AELog.debug(e); } } - private void updateString(final Object oldValue, final String val) { + private void updateString(final String val) { try { - this.field.set(this.source, val); - } catch (final IllegalArgumentException e) { + this.setter.invoke(source, val); + } catch (Throwable e) { AELog.debug(e); - } catch (final IllegalAccessException e) { + } + } + + private void updateTextComponent(final ITextComponent val) { + try { + this.setter.invoke(source, val); + } catch (Throwable e) { AELog.debug(e); } } private void updateValue(final Object oldValue, final long val) { try { - if (this.field.getType().isEnum()) { - final EnumSet valList = EnumSet.allOf((Class) this.field.getType()); - for (final Enum e : valList) { - if (e.ordinal() == val) { - this.field.set(this.source, e); - break; - } - } + if (this.fieldType.isEnum()) { + Object e = this.fieldType.getEnumConstants()[(int) val]; + this.setter.invoke(source, e); } else { - if (this.field.getType().equals(int.class)) { - this.field.set(this.source, (int) val); - } else if (this.field.getType().equals(long.class)) { - this.field.set(this.source, val); - } else if (this.field.getType().equals(boolean.class)) { - this.field.set(this.source, val == 1); - } else if (this.field.getType().equals(Integer.class)) { - this.field.set(this.source, (int) val); - } else if (this.field.getType().equals(Long.class)) { - this.field.set(this.source, val); - } else if (this.field.getType().equals(Boolean.class)) { - this.field.set(this.source, val == 1); + if (this.fieldType.equals(int.class)) { + this.setter.invoke(source, (int) val); + } else if (this.fieldType.equals(long.class)) { + this.setter.invoke(source, val); + } else if (this.fieldType.equals(boolean.class)) { + this.setter.invoke(source, val == 1); + } else if (this.fieldType.equals(Integer.class)) { + this.setter.invoke(source, (int) val); + } else if (this.fieldType.equals(Long.class)) { + this.setter.invoke(source, val); + } else if (this.fieldType.equals(Boolean.class)) { + this.setter.invoke(source, val == 1); } } - this.source.onUpdate(this.field.getName(), oldValue, this.field.get(this.source)); - } catch (final IllegalArgumentException e) { - AELog.debug(e); - } catch (final IllegalAccessException e) { + this.source.onUpdate(this.field.getName(), oldValue, this.getter.invoke(source)); + } catch (Throwable e) { AELog.debug(e); } } diff --git a/src/main/java/appeng/container/implementations/ContainerCraftConfirm.java b/src/main/java/appeng/container/implementations/ContainerCraftConfirm.java index 24a9b473d..579309ec8 100644 --- a/src/main/java/appeng/container/implementations/ContainerCraftConfirm.java +++ b/src/main/java/appeng/container/implementations/ContainerCraftConfirm.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.concurrent.Future; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import com.google.common.collect.ImmutableSet; @@ -33,6 +34,7 @@ import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.container.ContainerType; import net.minecraft.inventory.container.IContainerListener; import net.minecraft.network.PacketBuffer; +import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.StringTextComponent; import net.minecraft.world.World; @@ -99,7 +101,7 @@ public class ContainerCraftConfirm extends AEBaseContainer { @GuiSync(6) public boolean noCPU = true; @GuiSync(7) - public String myName = ""; + public ITextComponent myName; public ContainerCraftConfirm(int id, PlayerInventory ip, ITerminalHost te) { super(TYPE, id, ip, te); @@ -121,11 +123,12 @@ public class ContainerCraftConfirm extends AEBaseContainer { if (this.getSelectedCpu() == -1) { this.setCpuAvailableBytes(0); this.setCpuCoProcessors(0); - this.setName(""); + this.setName(null); } else { - this.setName(this.cpus.get(this.getSelectedCpu()).getName().getString()); - this.setCpuAvailableBytes(this.cpus.get(this.getSelectedCpu()).getSize()); - this.setCpuCoProcessors(this.cpus.get(this.getSelectedCpu()).getProcessors()); + CraftingCPURecord cpu = this.cpus.get(this.getSelectedCpu()); + this.setName(cpu.getName()); + this.setCpuAvailableBytes(cpu.getSize()); + this.setCpuCoProcessors(cpu.getProcessors()); } } @@ -145,6 +148,7 @@ public class ContainerCraftConfirm extends AEBaseContainer { for (final CraftingCPURecord ccr : this.cpus) { if (ccr.getCpu() == c) { found = true; + break; } } @@ -280,11 +284,12 @@ public class ContainerCraftConfirm extends AEBaseContainer { this.setSelectedCpu(-1); this.setCpuAvailableBytes(0); this.setCpuCoProcessors(0); - this.setName(""); + this.setName(null); } else if (this.getSelectedCpu() != -1) { - this.setName(this.cpus.get(this.getSelectedCpu()).getName().getString()); - this.setCpuAvailableBytes(this.cpus.get(this.getSelectedCpu()).getSize()); - this.setCpuCoProcessors(this.cpus.get(this.getSelectedCpu()).getProcessors()); + CraftingCPURecord cpu = this.cpus.get(this.getSelectedCpu()); + this.setName(cpu.getName()); + this.setCpuAvailableBytes(cpu.getSize()); + this.setCpuCoProcessors(cpu.getProcessors()); } } @@ -386,11 +391,11 @@ public class ContainerCraftConfirm extends AEBaseContainer { this.selectedCpu = selectedCpu; } - public String getName() { + public ITextComponent getName() { return this.myName; } - private void setName(@Nonnull final String myName) { + private void setName(@Nullable final ITextComponent myName) { this.myName = myName; } diff --git a/src/main/java/appeng/container/implementations/ContainerCraftingStatus.java b/src/main/java/appeng/container/implementations/ContainerCraftingStatus.java index 3909cd33e..efaed6b9c 100644 --- a/src/main/java/appeng/container/implementations/ContainerCraftingStatus.java +++ b/src/main/java/appeng/container/implementations/ContainerCraftingStatus.java @@ -28,6 +28,7 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.ContainerType; import net.minecraft.network.PacketBuffer; +import net.minecraft.util.text.ITextComponent; import appeng.api.config.SecurityPermissions; import appeng.api.networking.crafting.ICraftingCPU; @@ -58,7 +59,7 @@ public class ContainerCraftingStatus extends ContainerCraftingCPU { @GuiSync(6) public boolean noCPU = true; @GuiSync(7) - public String myName = ""; + public ITextComponent myName; public ContainerCraftingStatus(int id, final PlayerInventory ip, final ITerminalHost te) { super(TYPE, id, ip, te); @@ -117,9 +118,9 @@ public class ContainerCraftingStatus extends ContainerCraftingCPU { if (this.selectedCpu >= this.cpus.size()) { this.selectedCpu = -1; - this.myName = ""; + this.myName = null; } else if (this.selectedCpu != -1) { - this.myName = this.cpus.get(this.selectedCpu).getName().getString(); + this.myName = this.cpus.get(this.selectedCpu).getName(); } if (this.selectedCpu == -1 && this.cpus.size() > 0) { @@ -153,10 +154,10 @@ public class ContainerCraftingStatus extends ContainerCraftingCPU { } if (this.selectedCpu == -1) { - this.myName = ""; + this.myName = null; this.setCPU(null); } else { - this.myName = this.cpus.get(this.selectedCpu).getName().getString(); + this.myName = this.cpus.get(this.selectedCpu).getName(); this.setCPU(this.cpus.get(this.selectedCpu).getCpu()); } } diff --git a/src/main/java/appeng/core/sync/packets/PacketValueConfig.java b/src/main/java/appeng/core/sync/packets/PacketValueConfig.java index 0a7168960..fee470deb 100644 --- a/src/main/java/appeng/core/sync/packets/PacketValueConfig.java +++ b/src/main/java/appeng/core/sync/packets/PacketValueConfig.java @@ -61,7 +61,6 @@ public class PacketValueConfig extends AppEngPacket { public PacketValueConfig(final PacketBuffer stream) { this.Name = stream.readString(); this.Value = stream.readString(); - // dis.close(); } // api @@ -202,7 +201,7 @@ public class PacketValueConfig extends AppEngPacket { } else if (this.Name.equals("CraftingStatus") && this.Value.equals("Clear")) { final Screen gs = Minecraft.getInstance().currentScreen; if (gs instanceof GuiCraftingCPU) { - ((GuiCraftingCPU) gs).clearItems(); + ((GuiCraftingCPU) gs).clearItems(); } } else if (c instanceof IConfigurableObject) { final IConfigManager cm = ((IConfigurableObject) c).getConfigManager();