From ffa5a02e44381983ffdbddad0debc4569c1a1994 Mon Sep 17 00:00:00 2001 From: Juuxel <6596629+Juuxel@users.noreply.github.com> Date: Fri, 5 Jun 2020 18:01:27 +0300 Subject: CottonInventoryController -> SyncedGuiDescription --- .../cotton/gui/CottonInventoryController.java | 458 --------------------- .../github/cottonmc/cotton/gui/GuiDescription.java | 2 +- .../cotton/gui/PropertyDelegateHolder.java | 2 +- .../cottonmc/cotton/gui/SyncedGuiDescription.java | 458 +++++++++++++++++++++ .../cotton/gui/client/CottonInventoryScreen.java | 10 +- 5 files changed, 465 insertions(+), 465 deletions(-) delete mode 100644 src/main/java/io/github/cottonmc/cotton/gui/CottonInventoryController.java create mode 100644 src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java (limited to 'src/main') diff --git a/src/main/java/io/github/cottonmc/cotton/gui/CottonInventoryController.java b/src/main/java/io/github/cottonmc/cotton/gui/CottonInventoryController.java deleted file mode 100644 index 219f576..0000000 --- a/src/main/java/io/github/cottonmc/cotton/gui/CottonInventoryController.java +++ /dev/null @@ -1,458 +0,0 @@ -package io.github.cottonmc.cotton.gui; - -import java.util.ArrayList; - -import javax.annotation.Nullable; - -import io.github.cottonmc.cotton.gui.client.BackgroundPainter; -import io.github.cottonmc.cotton.gui.client.LibGuiClient; -import io.github.cottonmc.cotton.gui.widget.*; -import net.fabricmc.api.EnvType; -import net.fabricmc.api.Environment; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.InventoryProvider; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.inventory.Inventory; -import net.minecraft.item.ItemStack; -import net.minecraft.screen.*; -import net.minecraft.screen.slot.Slot; -import net.minecraft.screen.slot.SlotActionType; -import net.minecraft.world.World; - -/** - * A screen handler-based GUI description for GUIs with slots. - */ -public class CottonInventoryController extends ScreenHandler implements GuiDescription { - - protected Inventory blockInventory; - protected PlayerInventory playerInventory; - protected World world; - protected PropertyDelegate propertyDelegate; - - protected WPanel rootPanel = new WGridPanel(); - protected int titleColor = WLabel.DEFAULT_TEXT_COLOR; - protected int darkTitleColor = WLabel.DEFAULT_DARKMODE_TEXT_COLOR; - - protected WWidget focus; - - public CottonInventoryController(int syncId, PlayerInventory playerInventory) { - super(null, syncId); - this.blockInventory = null; - this.playerInventory = playerInventory; - this.world = playerInventory.player.world; - this.propertyDelegate = null;//new ArrayPropertyDelegate(1); - } - - public CottonInventoryController(int syncId, PlayerInventory playerInventory, Inventory blockInventory, PropertyDelegate propertyDelegate) { - super(null, syncId); - this.blockInventory = blockInventory; - this.playerInventory = playerInventory; - this.world = playerInventory.player.world; - this.propertyDelegate = propertyDelegate; - if (propertyDelegate!=null && propertyDelegate.size()>0) this.addProperties(propertyDelegate); - } - - public WPanel getRootPanel() { - return rootPanel; - } - - public int getTitleColor() { - return LibGuiClient.config.darkMode ? darkTitleColor : titleColor; - } - - public CottonInventoryController setRootPanel(WPanel panel) { - this.rootPanel = panel; - return this; - } - - public CottonInventoryController setTitleColor(int color) { - this.titleColor = color; - return this; - } - - @Environment(EnvType.CLIENT) - public void addPainters() { - if (this.rootPanel!=null) { - this.rootPanel.setBackgroundPainter(BackgroundPainter.VANILLA); - } - } - - public void addSlotPeer(ValidatedSlot slot) { - this.addSlot(slot); - } - - @Override - public ItemStack onSlotClick(int slotNumber, int button, SlotActionType action, PlayerEntity player) { - if (action==SlotActionType.QUICK_MOVE) { - - if (slotNumber < 0) { - return ItemStack.EMPTY; - } - - if (slotNumber>=this.slots.size()) return ItemStack.EMPTY; - Slot slot = this.slots.get(slotNumber); - if (slot == null || !slot.canTakeItems(player)) { - return ItemStack.EMPTY; - } - - ItemStack remaining = ItemStack.EMPTY; - if (slot != null && slot.hasStack()) { - ItemStack toTransfer = slot.getStack(); - remaining = toTransfer.copy(); - //if (slot.inventory==blockInventory) { - if (blockInventory!=null) { - if (slot.inventory==blockInventory) { - //Try to transfer the item from the block into the player's inventory - if (!this.insertItem(toTransfer, this.playerInventory, true, player)) { - return ItemStack.EMPTY; - } - } else if (!this.insertItem(toTransfer, this.blockInventory, false, player)) { //Try to transfer the item from the player to the block - return ItemStack.EMPTY; - } - } else { - //There's no block, just swap between the player's storage and their hotbar - if (!swapHotbar(toTransfer, slotNumber, this.playerInventory, player)) { - return ItemStack.EMPTY; - } - } - - if (toTransfer.isEmpty()) { - slot.setStack(ItemStack.EMPTY); - } else { - slot.markDirty(); - } - } - - return remaining; - } else { - return super.onSlotClick(slotNumber, button, action, player); - } - } - - /** WILL MODIFY toInsert! Returns true if anything was inserted. */ - private boolean insertIntoExisting(ItemStack toInsert, Slot slot, PlayerEntity player) { - ItemStack curSlotStack = slot.getStack(); - if (!curSlotStack.isEmpty() && canStacksCombine(toInsert, curSlotStack) && slot.canTakeItems(player)) { - int combinedAmount = curSlotStack.getCount() + toInsert.getCount(); - if (combinedAmount <= toInsert.getMaxCount()) { - toInsert.setCount(0); - curSlotStack.setCount(combinedAmount); - slot.markDirty(); - return true; - } else if (curSlotStack.getCount() < toInsert.getMaxCount()) { - toInsert.decrement(toInsert.getMaxCount() - curSlotStack.getCount()); - curSlotStack.setCount(toInsert.getMaxCount()); - slot.markDirty(); - return true; - } - } - return false; - } - - /** WILL MODIFY toInsert! Returns true if anything was inserted. */ - private boolean insertIntoEmpty(ItemStack toInsert, Slot slot) { - ItemStack curSlotStack = slot.getStack(); - if (curSlotStack.isEmpty() && slot.canInsert(toInsert)) { - if (toInsert.getCount() > slot.getMaxStackAmount()) { - slot.setStack(toInsert.split(slot.getMaxStackAmount())); - } else { - slot.setStack(toInsert.split(toInsert.getCount())); - } - - slot.markDirty(); - return true; - } - - return false; - } - - private boolean insertItem(ItemStack toInsert, Inventory inventory, boolean walkBackwards, PlayerEntity player) { - //Make a unified list of slots *only from this inventory* - ArrayList inventorySlots = new ArrayList<>(); - for(Slot slot : slots) { - if (slot.inventory==inventory) inventorySlots.add(slot); - } - if (inventorySlots.isEmpty()) return false; - - //Try to insert it on top of existing stacks - boolean inserted = false; - if (walkBackwards) { - for(int i=inventorySlots.size()-1; i>=0; i--) { - Slot curSlot = inventorySlots.get(i); - if (insertIntoExisting(toInsert, curSlot, player)) inserted = true; - if (toInsert.isEmpty()) break; - } - } else { - for(int i=0; i=0; i--) { - Slot curSlot = inventorySlots.get(i); - if (insertIntoEmpty(toInsert, curSlot)) inserted = true; - if (toInsert.isEmpty()) break; - } - } else { - for(int i=0; i storageSlots = new ArrayList<>(); - ArrayList hotbarSlots = new ArrayList<>(); - boolean swapToStorage = true; - boolean inserted = false; - - for(Slot slot : slots) { - if (slot.inventory==inventory && slot instanceof ValidatedSlot) { - int index = ((ValidatedSlot)slot).getInventoryIndex(); - if (PlayerInventory.isValidHotbarIndex(index)) { - hotbarSlots.add(slot); - } else { - storageSlots.add(slot); - if (index==slotNumber) swapToStorage = false; - } - } - } - if (storageSlots.isEmpty() || hotbarSlots.isEmpty()) return false; - - if (swapToStorage) { - //swap from hotbar to storage - for(int i=0; i=wx && x=wy && yIf no inventory is found, returns {@link EmptyInventory#INSTANCE}. - * - *

Searches for these implementations in the following order: - *

    - *
  1. Blocks implementing {@code InventoryProvider}
  2. - *
  3. Block entities implementing {@code InventoryProvider}
  4. - *
  5. Block entities implementing {@code Inventory}
  6. - *
- * - * @param ctx the context - * @return the found inventory - */ - public static Inventory getBlockInventory(ScreenHandlerContext ctx) { - return ctx.run((world, pos) -> { - BlockState state = world.getBlockState(pos); - Block b = state.getBlock(); - - if (b instanceof InventoryProvider) { - Inventory inventory = ((InventoryProvider)b).getInventory(state, world, pos); - if (inventory != null) { - return inventory; - } - } - - BlockEntity be = world.getBlockEntity(pos); - if (be!=null) { - if (be instanceof InventoryProvider) { - Inventory inventory = ((InventoryProvider)be).getInventory(state, world, pos); - if (inventory != null) { - return inventory; - } - } else if (be instanceof Inventory) { - return (Inventory)be; - } - } - - return EmptyInventory.INSTANCE; - }).orElse(EmptyInventory.INSTANCE); - } - - /** - * Gets the property delegate at the context. - * - *

If no property delegate is found, returns an empty property delegate with no properties. - * - *

Searches for block entities implementing {@link PropertyDelegateHolder}. - * - * @param ctx the context - * @return the found property delegate - */ - public static PropertyDelegate getBlockPropertyDelegate(ScreenHandlerContext ctx) { - return ctx.run((world, pos) -> { - BlockEntity be = world.getBlockEntity(pos); - if (be!=null && be instanceof PropertyDelegateHolder) { - return ((PropertyDelegateHolder)be).getPropertyDelegate(); - } - - return new ArrayPropertyDelegate(0); - }).orElse(new ArrayPropertyDelegate(0)); - } - - //extends ScreenHandler { - @Override - public boolean canUse(PlayerEntity entity) { - return (blockInventory!=null) ? blockInventory.canPlayerUse(entity) : true; - } - //} - - @Override - public boolean isFocused(WWidget widget) { - return focus == widget; - } - - @Override - public WWidget getFocus() { - return focus; - } - - @Override - public void requestFocus(WWidget widget) { - //TODO: Are there circumstances where focus can't be stolen? - if (focus==widget) return; //Nothing happens if we're already focused - if (!widget.canFocus()) return; //This is kind of a gotcha but needs to happen - if (focus!=null) focus.onFocusLost(); - focus = widget; - focus.onFocusGained(); - } - - @Override - public void releaseFocus(WWidget widget) { - if (focus==widget) { - focus = null; - widget.onFocusLost(); - } - } -} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java b/src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java index 815b179..0c31912 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/GuiDescription.java @@ -16,7 +16,7 @@ import net.minecraft.screen.PropertyDelegate; * They also manage the focused widget. * * @see io.github.cottonmc.cotton.gui.client.LightweightGuiDescription - * @see CottonInventoryController + * @see SyncedGuiDescription */ public interface GuiDescription { public WPanel getRootPanel(); diff --git a/src/main/java/io/github/cottonmc/cotton/gui/PropertyDelegateHolder.java b/src/main/java/io/github/cottonmc/cotton/gui/PropertyDelegateHolder.java index af61892..6aa46bd 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/PropertyDelegateHolder.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/PropertyDelegateHolder.java @@ -6,7 +6,7 @@ import net.minecraft.screen.PropertyDelegate; * This interface can be implemented on block entity classes * for providing a property delegate. * - * @see CottonInventoryController#getBlockPropertyDelegate(net.minecraft.screen.ScreenHandlerContext) + * @see SyncedGuiDescription#getBlockPropertyDelegate(net.minecraft.screen.ScreenHandlerContext) */ public interface PropertyDelegateHolder { /** diff --git a/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java b/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java new file mode 100644 index 0000000..5f2bef0 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java @@ -0,0 +1,458 @@ +package io.github.cottonmc.cotton.gui; + +import java.util.ArrayList; + +import javax.annotation.Nullable; + +import io.github.cottonmc.cotton.gui.client.BackgroundPainter; +import io.github.cottonmc.cotton.gui.client.LibGuiClient; +import io.github.cottonmc.cotton.gui.widget.*; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.InventoryProvider; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.*; +import net.minecraft.screen.slot.Slot; +import net.minecraft.screen.slot.SlotActionType; +import net.minecraft.world.World; + +/** + * A screen handler-based GUI description for GUIs with slots. + */ +public class SyncedGuiDescription extends ScreenHandler implements GuiDescription { + + protected Inventory blockInventory; + protected PlayerInventory playerInventory; + protected World world; + protected PropertyDelegate propertyDelegate; + + protected WPanel rootPanel = new WGridPanel(); + protected int titleColor = WLabel.DEFAULT_TEXT_COLOR; + protected int darkTitleColor = WLabel.DEFAULT_DARKMODE_TEXT_COLOR; + + protected WWidget focus; + + public SyncedGuiDescription(int syncId, PlayerInventory playerInventory) { + super(null, syncId); + this.blockInventory = null; + this.playerInventory = playerInventory; + this.world = playerInventory.player.world; + this.propertyDelegate = null;//new ArrayPropertyDelegate(1); + } + + public SyncedGuiDescription(int syncId, PlayerInventory playerInventory, Inventory blockInventory, PropertyDelegate propertyDelegate) { + super(null, syncId); + this.blockInventory = blockInventory; + this.playerInventory = playerInventory; + this.world = playerInventory.player.world; + this.propertyDelegate = propertyDelegate; + if (propertyDelegate!=null && propertyDelegate.size()>0) this.addProperties(propertyDelegate); + } + + public WPanel getRootPanel() { + return rootPanel; + } + + public int getTitleColor() { + return LibGuiClient.config.darkMode ? darkTitleColor : titleColor; + } + + public SyncedGuiDescription setRootPanel(WPanel panel) { + this.rootPanel = panel; + return this; + } + + public SyncedGuiDescription setTitleColor(int color) { + this.titleColor = color; + return this; + } + + @Environment(EnvType.CLIENT) + public void addPainters() { + if (this.rootPanel!=null) { + this.rootPanel.setBackgroundPainter(BackgroundPainter.VANILLA); + } + } + + public void addSlotPeer(ValidatedSlot slot) { + this.addSlot(slot); + } + + @Override + public ItemStack onSlotClick(int slotNumber, int button, SlotActionType action, PlayerEntity player) { + if (action==SlotActionType.QUICK_MOVE) { + + if (slotNumber < 0) { + return ItemStack.EMPTY; + } + + if (slotNumber>=this.slots.size()) return ItemStack.EMPTY; + Slot slot = this.slots.get(slotNumber); + if (slot == null || !slot.canTakeItems(player)) { + return ItemStack.EMPTY; + } + + ItemStack remaining = ItemStack.EMPTY; + if (slot != null && slot.hasStack()) { + ItemStack toTransfer = slot.getStack(); + remaining = toTransfer.copy(); + //if (slot.inventory==blockInventory) { + if (blockInventory!=null) { + if (slot.inventory==blockInventory) { + //Try to transfer the item from the block into the player's inventory + if (!this.insertItem(toTransfer, this.playerInventory, true, player)) { + return ItemStack.EMPTY; + } + } else if (!this.insertItem(toTransfer, this.blockInventory, false, player)) { //Try to transfer the item from the player to the block + return ItemStack.EMPTY; + } + } else { + //There's no block, just swap between the player's storage and their hotbar + if (!swapHotbar(toTransfer, slotNumber, this.playerInventory, player)) { + return ItemStack.EMPTY; + } + } + + if (toTransfer.isEmpty()) { + slot.setStack(ItemStack.EMPTY); + } else { + slot.markDirty(); + } + } + + return remaining; + } else { + return super.onSlotClick(slotNumber, button, action, player); + } + } + + /** WILL MODIFY toInsert! Returns true if anything was inserted. */ + private boolean insertIntoExisting(ItemStack toInsert, Slot slot, PlayerEntity player) { + ItemStack curSlotStack = slot.getStack(); + if (!curSlotStack.isEmpty() && canStacksCombine(toInsert, curSlotStack) && slot.canTakeItems(player)) { + int combinedAmount = curSlotStack.getCount() + toInsert.getCount(); + if (combinedAmount <= toInsert.getMaxCount()) { + toInsert.setCount(0); + curSlotStack.setCount(combinedAmount); + slot.markDirty(); + return true; + } else if (curSlotStack.getCount() < toInsert.getMaxCount()) { + toInsert.decrement(toInsert.getMaxCount() - curSlotStack.getCount()); + curSlotStack.setCount(toInsert.getMaxCount()); + slot.markDirty(); + return true; + } + } + return false; + } + + /** WILL MODIFY toInsert! Returns true if anything was inserted. */ + private boolean insertIntoEmpty(ItemStack toInsert, Slot slot) { + ItemStack curSlotStack = slot.getStack(); + if (curSlotStack.isEmpty() && slot.canInsert(toInsert)) { + if (toInsert.getCount() > slot.getMaxStackAmount()) { + slot.setStack(toInsert.split(slot.getMaxStackAmount())); + } else { + slot.setStack(toInsert.split(toInsert.getCount())); + } + + slot.markDirty(); + return true; + } + + return false; + } + + private boolean insertItem(ItemStack toInsert, Inventory inventory, boolean walkBackwards, PlayerEntity player) { + //Make a unified list of slots *only from this inventory* + ArrayList inventorySlots = new ArrayList<>(); + for(Slot slot : slots) { + if (slot.inventory==inventory) inventorySlots.add(slot); + } + if (inventorySlots.isEmpty()) return false; + + //Try to insert it on top of existing stacks + boolean inserted = false; + if (walkBackwards) { + for(int i=inventorySlots.size()-1; i>=0; i--) { + Slot curSlot = inventorySlots.get(i); + if (insertIntoExisting(toInsert, curSlot, player)) inserted = true; + if (toInsert.isEmpty()) break; + } + } else { + for(int i=0; i=0; i--) { + Slot curSlot = inventorySlots.get(i); + if (insertIntoEmpty(toInsert, curSlot)) inserted = true; + if (toInsert.isEmpty()) break; + } + } else { + for(int i=0; i storageSlots = new ArrayList<>(); + ArrayList hotbarSlots = new ArrayList<>(); + boolean swapToStorage = true; + boolean inserted = false; + + for(Slot slot : slots) { + if (slot.inventory==inventory && slot instanceof ValidatedSlot) { + int index = ((ValidatedSlot)slot).getInventoryIndex(); + if (PlayerInventory.isValidHotbarIndex(index)) { + hotbarSlots.add(slot); + } else { + storageSlots.add(slot); + if (index==slotNumber) swapToStorage = false; + } + } + } + if (storageSlots.isEmpty() || hotbarSlots.isEmpty()) return false; + + if (swapToStorage) { + //swap from hotbar to storage + for(int i=0; i=wx && x=wy && yIf no inventory is found, returns {@link EmptyInventory#INSTANCE}. + * + *

Searches for these implementations in the following order: + *

    + *
  1. Blocks implementing {@code InventoryProvider}
  2. + *
  3. Block entities implementing {@code InventoryProvider}
  4. + *
  5. Block entities implementing {@code Inventory}
  6. + *
+ * + * @param ctx the context + * @return the found inventory + */ + public static Inventory getBlockInventory(ScreenHandlerContext ctx) { + return ctx.run((world, pos) -> { + BlockState state = world.getBlockState(pos); + Block b = state.getBlock(); + + if (b instanceof InventoryProvider) { + Inventory inventory = ((InventoryProvider)b).getInventory(state, world, pos); + if (inventory != null) { + return inventory; + } + } + + BlockEntity be = world.getBlockEntity(pos); + if (be!=null) { + if (be instanceof InventoryProvider) { + Inventory inventory = ((InventoryProvider)be).getInventory(state, world, pos); + if (inventory != null) { + return inventory; + } + } else if (be instanceof Inventory) { + return (Inventory)be; + } + } + + return EmptyInventory.INSTANCE; + }).orElse(EmptyInventory.INSTANCE); + } + + /** + * Gets the property delegate at the context. + * + *

If no property delegate is found, returns an empty property delegate with no properties. + * + *

Searches for block entities implementing {@link PropertyDelegateHolder}. + * + * @param ctx the context + * @return the found property delegate + */ + public static PropertyDelegate getBlockPropertyDelegate(ScreenHandlerContext ctx) { + return ctx.run((world, pos) -> { + BlockEntity be = world.getBlockEntity(pos); + if (be!=null && be instanceof PropertyDelegateHolder) { + return ((PropertyDelegateHolder)be).getPropertyDelegate(); + } + + return new ArrayPropertyDelegate(0); + }).orElse(new ArrayPropertyDelegate(0)); + } + + //extends ScreenHandler { + @Override + public boolean canUse(PlayerEntity entity) { + return (blockInventory!=null) ? blockInventory.canPlayerUse(entity) : true; + } + //} + + @Override + public boolean isFocused(WWidget widget) { + return focus == widget; + } + + @Override + public WWidget getFocus() { + return focus; + } + + @Override + public void requestFocus(WWidget widget) { + //TODO: Are there circumstances where focus can't be stolen? + if (focus==widget) return; //Nothing happens if we're already focused + if (!widget.canFocus()) return; //This is kind of a gotcha but needs to happen + if (focus!=null) focus.onFocusLost(); + focus = widget; + focus.onFocusGained(); + } + + @Override + public void releaseFocus(WWidget widget) { + if (focus==widget) { + focus = null; + widget.onFocusLost(); + } + } +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java index 5744aba..10ff4f6 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java @@ -1,5 +1,6 @@ package io.github.cottonmc.cotton.gui.client; +import io.github.cottonmc.cotton.gui.SyncedGuiDescription; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.ingame.HandledScreen; import net.minecraft.client.render.DiffuseLighting; @@ -10,17 +11,16 @@ import net.minecraft.text.Style; import net.minecraft.text.Text; import org.lwjgl.glfw.GLFW; -import io.github.cottonmc.cotton.gui.CottonInventoryController; import io.github.cottonmc.cotton.gui.widget.WPanel; import io.github.cottonmc.cotton.gui.widget.WWidget; /** - * A screen for a {@link CottonInventoryController}. + * A screen for a {@link SyncedGuiDescription}. * - * @param the controller type + * @param the description type */ -public class CottonInventoryScreen extends HandledScreen implements TextHoverRendererScreen { - protected CottonInventoryController description; +public class CottonInventoryScreen extends HandledScreen implements TextHoverRendererScreen { + protected SyncedGuiDescription description; protected WWidget lastResponder = null; /** -- cgit