GUI Windows System
Note: This is unofficial community documentation created through decompilation and analysis. Some details may change in future versions.
The Hytale window system provides a server-authoritative GUI framework for displaying inventory interfaces, crafting tables, containers, and custom interfaces to players.
Architecture
Section titled “Architecture”WindowManager (Per-player window management)├── Window (Base abstract class)│ ├── ContainerWindow (Simple item container)│ ├── ContainerBlockWindow (Block-bound container)│ ├── ItemStackContainerWindow (ItemStack-based container)│ └── Custom window implementations├── WindowType (Protocol-defined window types)└── WindowAction (Client-to-server actions)
Window Interfaces:├── ItemContainerWindow - Windows with item storage├── MaterialContainerWindow - Windows with extra resources└── ValidatedWindow - Windows requiring periodic validationWindowManager
Section titled “WindowManager”The WindowManager handles all window operations for a specific player. It is accessed through the player’s component system.
Accessing WindowManager
Section titled “Accessing WindowManager”import com.hypixel.hytale.server.core.entity.entities.player.windows.WindowManager;import com.hypixel.hytale.server.core.entity.entities.Player;
// Get WindowManager from player componentPlayer playerComponent = store.getComponent(ref, Player.getComponentType());WindowManager windowManager = playerComponent.getWindowManager();Opening Windows
Section titled “Opening Windows”import com.hypixel.hytale.protocol.packets.window.OpenWindow;
// Open a window and get the packet to sendWindow myWindow = new ContainerWindow(itemContainer);OpenWindow packet = windowManager.openWindow(myWindow);
if (packet != null) { // Window opened successfully - packet is automatically sent int windowId = myWindow.getId();}
// Open multiple windows at onceWindow[] windows = { window1, window2, window3 };List<OpenWindow> packets = windowManager.openWindows(windows);
if (packets == null) { // One or more windows failed to open - all are closed}Updating Windows
Section titled “Updating Windows”// Manually update a window (sends UpdateWindow packet)windowManager.updateWindow(window);
// Mark a window as changed (will be updated on next tick)windowManager.markWindowChanged(windowId);
// Update all dirty windows (called automatically by server)windowManager.updateWindows();Closing Windows
Section titled “Closing Windows”// Close a specific window by IDWindow closedWindow = windowManager.closeWindow(windowId);
// Close all windows for the playerwindowManager.closeAllWindows();
// Close window from within the window instancewindow.close();Window ID Management
Section titled “Window ID Management”Window IDs are managed automatically by the WindowManager:
| ID | Description |
|---|---|
| -1 | Invalid/unassigned |
| 0 | Reserved for client-initiated windows |
| 1+ | Server-assigned IDs (auto-incremented) |
// Get a window by IDWindow window = windowManager.getWindow(windowId);
// Get all active windowsList<Window> allWindows = windowManager.getWindows();Validating Windows
Section titled “Validating Windows”Windows implementing ValidatedWindow are automatically validated each tick:
// Called automatically by the serverwindowManager.validateWindows();Window Base Class
Section titled “Window Base Class”All windows extend the abstract Window class.
Creating a Custom Window
Section titled “Creating a Custom Window”import com.hypixel.hytale.server.core.entity.entities.player.windows.Window;import com.hypixel.hytale.protocol.packets.window.WindowType;import com.google.gson.JsonObject;
public class CustomWindow extends Window { private final JsonObject windowData = new JsonObject();
public CustomWindow() { super(WindowType.Container); // Initialize window data windowData.addProperty("customProperty", "value"); }
@Override public JsonObject getData() { return windowData; }
@Override protected boolean onOpen0() { // Called when window opens // Return false to cancel opening return true; }
@Override protected void onClose0() { // Called when window closes // Clean up resources here }}Window Lifecycle
Section titled “Window Lifecycle”1. Window constructed2. WindowManager.openWindow() called3. Window.init() - receives PlayerRef and WindowManager4. Window.onOpen() -> onOpen0() - Return true to complete opening - Return false to cancel (window is closed)5. OpenWindow packet sent to client6. Window active - handles actions, updates7. Window.close() or WindowManager.closeWindow()8. Window.onClose() -> onClose0()9. WindowCloseEvent dispatched10. CloseWindow packet sent to clientWindow Data
Section titled “Window Data”Window data is sent to the client as JSON:
@Overridepublic JsonObject getData() { JsonObject data = new JsonObject(); data.addProperty("title", "My Window"); data.addProperty("capacity", 27); data.addProperty("customFlag", true); return data;}
// Mark window as needing a full rebuildprotected void setNeedRebuild() { this.needRebuild.set(true); this.getData().addProperty("needRebuild", Boolean.TRUE);}Window State Management
Section titled “Window State Management”// Mark window as dirty (will send update)protected void invalidate() { this.isDirty.set(true);}
// Check and consume dirty stateprotected boolean consumeIsDirty() { return this.isDirty.getAndSet(false);}
// Access window propertiespublic int getId() { return this.id; }public WindowType getType() { return this.windowType; }public PlayerRef getPlayerRef() { return this.playerRef; }WindowCloseEvent
Section titled “WindowCloseEvent”Register handlers for when a window closes:
import com.hypixel.hytale.event.EventPriority;import com.hypixel.hytale.event.EventRegistration;import com.hypixel.hytale.server.core.entity.entities.player.windows.Window.WindowCloseEvent;
// Register close handlerEventRegistration registration = window.registerCloseEvent(event -> { // Handle window closure System.out.println("Window closed!");});
// With priorityEventRegistration reg = window.registerCloseEvent( EventPriority.EARLY, event -> handleClose(event));
// Unregister when doneregistration.unregister();Client-Requestable Windows
Section titled “Client-Requestable Windows”Some windows can be opened by client request (like pocket crafting):
import com.hypixel.hytale.server.core.entity.entities.player.windows.Window;
// Register a client-requestable window typeWindow.CLIENT_REQUESTABLE_WINDOW_TYPES.put( WindowType.PocketCrafting, () -> new PocketCraftingWindow());
// In WindowManager - handles client requestUpdateWindow packet = windowManager.clientOpenWindow(window);WindowType Enum
Section titled “WindowType Enum”Defines the types of windows recognized by the protocol.
| Type | ID | Description |
|---|---|---|
Container | 0 | Generic item container |
PocketCrafting | 1 | Portable/pocket crafting interface |
BasicCrafting | 2 | Basic crafting table |
DiagramCrafting | 3 | Diagram-based crafting (schematics) |
StructuralCrafting | 4 | Structural/building crafting |
Processing | 5 | Processing bench (furnace, etc.) |
Memories | 6 | Memories/journal interface |
import com.hypixel.hytale.protocol.packets.window.WindowType;
// Get type from valueWindowType type = WindowType.fromValue(0); // Container
// Get value from typeint value = WindowType.Container.getValue(); // 0
// All typesWindowType[] allTypes = WindowType.VALUES;Window Interfaces
Section titled “Window Interfaces”ItemContainerWindow
Section titled “ItemContainerWindow”Windows that contain an ItemContainer for item storage.
import com.hypixel.hytale.server.core.entity.entities.player.windows.ItemContainerWindow;import com.hypixel.hytale.server.core.inventory.container.ItemContainer;
public class MyContainerWindow extends Window implements ItemContainerWindow { private final ItemContainer itemContainer;
public MyContainerWindow(ItemContainer container) { super(WindowType.Container); this.itemContainer = container; }
@Override public ItemContainer getItemContainer() { return itemContainer; }
// ... other methods}When a window implements ItemContainerWindow, the WindowManager automatically:
- Registers change events on the container
- Sends inventory updates to the client
- Unregisters events when the window closes
MaterialContainerWindow
Section titled “MaterialContainerWindow”Windows that display extra resources/materials (used by crafting benches).
import com.hypixel.hytale.server.core.entity.entities.player.windows.MaterialContainerWindow;import com.hypixel.hytale.server.core.entity.entities.player.windows.MaterialExtraResourcesSection;
public class CraftingWindow extends Window implements MaterialContainerWindow { private final MaterialExtraResourcesSection extraResources;
public CraftingWindow() { super(WindowType.BasicCrafting); this.extraResources = new MaterialExtraResourcesSection(); }
@Override public MaterialExtraResourcesSection getExtraResourcesSection() { return extraResources; }
@Override public void invalidateExtraResources() { extraResources.setValid(false); invalidate(); }
@Override public boolean isValid() { return extraResources.isValid(); }}MaterialExtraResourcesSection
Section titled “MaterialExtraResourcesSection”import com.hypixel.hytale.server.core.entity.entities.player.windows.MaterialExtraResourcesSection;import com.hypixel.hytale.protocol.ItemQuantity;
MaterialExtraResourcesSection section = new MaterialExtraResourcesSection();
// Set extra materials to displayItemQuantity[] materials = new ItemQuantity[] { /* ... */ };section.setExtraMaterials(materials);
// Track validitysection.setValid(true);boolean valid = section.isValid();
// Associated item containersection.setItemContainer(container);ItemContainer container = section.getItemContainer();ValidatedWindow
Section titled “ValidatedWindow”Windows that need periodic validation (e.g., distance checks, block existence).
import com.hypixel.hytale.server.core.entity.entities.player.windows.ValidatedWindow;
public class MyValidatedWindow extends Window implements ValidatedWindow {
@Override public boolean validate() { // Return true if window should remain open // Return false to close the window
PlayerRef playerRef = getPlayerRef(); if (playerRef == null) return false;
// Custom validation logic return isPlayerInRange(); }}Built-in Window Types
Section titled “Built-in Window Types”ContainerWindow
Section titled “ContainerWindow”Simple container window for displaying item storage.
import com.hypixel.hytale.server.core.entity.entities.player.windows.ContainerWindow;import com.hypixel.hytale.server.core.inventory.container.SimpleItemContainer;
// Create a containerItemContainer container = new SimpleItemContainer((short) 27);
// Create and open the windowContainerWindow window = new ContainerWindow(container);windowManager.openWindow(window);BlockWindow
Section titled “BlockWindow”Abstract base for windows tied to world blocks. Implements ValidatedWindow to automatically close when player moves too far or block changes.
import com.hypixel.hytale.server.core.entity.entities.player.windows.BlockWindow;import com.hypixel.hytale.server.core.asset.type.blocktype.config.BlockType;
public class CustomBlockWindow extends BlockWindow { private static final float MAX_DISTANCE = 7.0f;
public CustomBlockWindow(int x, int y, int z, int rotationIndex, BlockType blockType) { super(WindowType.Container, x, y, z, rotationIndex, blockType); }
// Access block position public int getX() { return x; } public int getY() { return y; } public int getZ() { return z; } public int getRotationIndex() { return rotationIndex; } public BlockType getBlockType() { return blockType; }
// Configure max interaction distance (default 7.0) public void setMaxDistance(double distance) { // Updates internal distance check }}The BlockWindow.validate() method checks:
- Player reference exists
- Player is within max distance
- Chunk is loaded
- Block at position matches original block type
ContainerBlockWindow
Section titled “ContainerBlockWindow”Block-based container (chests, storage blocks, etc.).
import com.hypixel.hytale.server.core.entity.entities.player.windows.ContainerBlockWindow;
// Create window for a block at positionContainerBlockWindow window = new ContainerBlockWindow( x, y, z, // Block position rotationIndex, // Block rotation blockType, // BlockType asset itemContainer // ItemContainer for storage);
// Window data includes blockItemId automaticallywindowManager.openWindow(window);ItemStackContainerWindow
Section titled “ItemStackContainerWindow”Window for an ItemStackItemContainer (items stored within other items, like backpacks).
import com.hypixel.hytale.server.core.entity.entities.player.windows.ItemStackContainerWindow;import com.hypixel.hytale.server.core.inventory.container.ItemStackItemContainer;
ItemStackItemContainer backpackContainer = // ... from item metadataItemStackContainerWindow window = new ItemStackContainerWindow(backpackContainer);windowManager.openWindow(window);Automatically closes when the parent item stack becomes invalid.
Crafting Window Hierarchy
Section titled “Crafting Window Hierarchy”Crafting uses specialized bench configurations:
Bench (Base configuration)├── CraftingBench│ ├── DiagramCraftingBench (WindowType.DiagramCrafting)│ └── (Basic crafting - WindowType.BasicCrafting)├── StructuralCraftingBench (WindowType.StructuralCrafting)└── ProcessingBench (WindowType.Processing)CraftingBench Categories:
// Access bench categoriesCraftingBench bench = // ... from block configBenchCategory[] categories = bench.getCategories();
for (BenchCategory category : categories) { String id = category.getId(); String name = category.getName(); String icon = category.getIcon(); BenchItemCategory[] itemCategories = category.getItemCategories();}StructuralCraftingBench:
StructuralCraftingBench bench = // ... from block config
// Check if category is a headerboolean isHeader = bench.isHeaderCategory("building");
// Get category sort orderint index = bench.getCategoryIndex("walls");
// Configuration flagsboolean allowCycling = bench.shouldAllowBlockGroupCycling();boolean showHints = bench.shouldAlwaysShowInventoryHints();WindowAction System
Section titled “WindowAction System”Window actions are client-to-server messages for interacting with windows.
Base WindowAction Class
Section titled “Base WindowAction Class”import com.hypixel.hytale.protocol.packets.window.WindowAction;
// Actions are deserialized from network packets// Type ID determines the specific action classAction Types
Section titled “Action Types”| ID | Action Class | Description |
|---|---|---|
| 0 | CraftRecipeAction | Craft a specific recipe |
| 1 | TierUpgradeAction | Upgrade crafting tier |
| 2 | SelectSlotAction | Select a slot in the window |
| 3 | ChangeBlockAction | Cycle block variant |
| 4 | SetActiveAction | Set active state |
| 5 | CraftItemAction | Generic craft action |
| 6 | UpdateCategoryAction | Change crafting category |
| 7 | CancelCraftingAction | Cancel current craft |
| 8 | SortItemsAction | Sort container items |
Built-in Actions
Section titled “Built-in Actions”CraftRecipeAction:
import com.hypixel.hytale.protocol.packets.window.CraftRecipeAction;
// FieldsString recipeId; // Recipe identifier (nullable)int quantity; // Number to craft
// Example handlingpublic void handleAction(Ref<EntityStore> ref, Store<EntityStore> store, WindowAction action) { if (action instanceof CraftRecipeAction craftAction) { String recipe = craftAction.recipeId; int qty = craftAction.quantity; // Process crafting... }}SelectSlotAction:
import com.hypixel.hytale.protocol.packets.window.SelectSlotAction;
// Fieldsint slot; // Selected slot index
// Creating an actionSelectSlotAction action = new SelectSlotAction(5);SortItemsAction:
import com.hypixel.hytale.protocol.packets.window.SortItemsAction;import com.hypixel.hytale.protocol.SortType;
// FieldsSortType sortType; // Name, Category, etc.
// Example from ContainerBlockWindow@Overridepublic void handleAction(Ref<EntityStore> ref, Store<EntityStore> store, WindowAction action) { if (action instanceof SortItemsAction sortAction) { SortType sortType = SortType.fromPacket(sortAction.sortType); itemContainer.sortItems(sortType); invalidate(); }}UpdateCategoryAction:
import com.hypixel.hytale.protocol.packets.window.UpdateCategoryAction;
// FieldsString category; // Main categoryString itemCategory; // Sub-categoryChangeBlockAction:
import com.hypixel.hytale.protocol.packets.window.ChangeBlockAction;
// Fieldsboolean down; // Direction of changeSetActiveAction:
import com.hypixel.hytale.protocol.packets.window.SetActiveAction;
// Fieldsboolean state; // New active stateHandling Actions in Custom Windows
Section titled “Handling Actions in Custom Windows”import com.hypixel.hytale.protocol.packets.window.WindowAction;import com.hypixel.hytale.component.Ref;import com.hypixel.hytale.component.Store;import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
public class CustomWindow extends Window {
@Override public void handleAction( @Nonnull Ref<EntityStore> ref, @Nonnull Store<EntityStore> store, @Nonnull WindowAction action ) { if (action instanceof SelectSlotAction selectAction) { int slot = selectAction.slot; handleSlotSelection(slot); } else if (action instanceof SortItemsAction sortAction) { handleSort(sortAction.sortType); } // Handle other action types... }}Network Packets
Section titled “Network Packets”OpenWindow (Server -> Client)
Section titled “OpenWindow (Server -> Client)”Sent when opening a new window.
| Field | Type | Description |
|---|---|---|
id | int | Window ID (unique per player) |
windowType | WindowType | Type of window |
windowData | String | JSON data (nullable) |
inventory | InventorySection | Item container data (nullable) |
extraResources | ExtraResources | Extra resource data (nullable) |
Packet ID: 200
UpdateWindow (Server -> Client)
Section titled “UpdateWindow (Server -> Client)”Sent when window data/contents change.
| Field | Type | Description |
|---|---|---|
id | int | Window ID |
windowData | String | Updated JSON data (nullable) |
inventory | InventorySection | Updated inventory (nullable) |
extraResources | ExtraResources | Updated resources (nullable) |
Packet ID: 201
CloseWindow (Server -> Client)
Section titled “CloseWindow (Server -> Client)”Sent when closing a window.
| Field | Type | Description |
|---|---|---|
id | int | Window ID to close |
Packet ID: 202
SendWindowAction (Client -> Server)
Section titled “SendWindowAction (Client -> Server)”Sent when player performs an action in a window.
| Field | Type | Description |
|---|---|---|
id | int | Window ID |
action | WindowAction | The action performed |
Packet ID: 203
ClientOpenWindow (Client -> Server)
Section titled “ClientOpenWindow (Client -> Server)”Sent when client requests to open a client-initiated window.
| Field | Type | Description |
|---|---|---|
type | WindowType | Requested window type |
Packet ID: 204
Only window types registered in Window.CLIENT_REQUESTABLE_WINDOW_TYPES can be opened this way.
Complete Example: Custom Shop Window
Section titled “Complete Example: Custom Shop Window”import com.google.gson.JsonObject;import com.hypixel.hytale.component.Ref;import com.hypixel.hytale.component.Store;import com.hypixel.hytale.protocol.packets.window.SelectSlotAction;import com.hypixel.hytale.protocol.packets.window.WindowAction;import com.hypixel.hytale.protocol.packets.window.WindowType;import com.hypixel.hytale.server.core.entity.entities.player.windows.ItemContainerWindow;import com.hypixel.hytale.server.core.entity.entities.player.windows.Window;import com.hypixel.hytale.server.core.inventory.container.ItemContainer;import com.hypixel.hytale.server.core.inventory.container.SimpleItemContainer;import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import javax.annotation.Nonnull;
public class ShopWindow extends Window implements ItemContainerWindow { private final JsonObject windowData = new JsonObject(); private final ItemContainer shopInventory; private final String shopName; private int selectedSlot = -1;
public ShopWindow(String shopName, int size) { super(WindowType.Container); this.shopName = shopName; this.shopInventory = new SimpleItemContainer((short) size);
// Initialize window data windowData.addProperty("shopName", shopName); windowData.addProperty("selectedSlot", selectedSlot); }
@Override @Nonnull public JsonObject getData() { windowData.addProperty("selectedSlot", selectedSlot); return windowData; }
@Override protected boolean onOpen0() { // Load shop items into inventory loadShopItems(); return true; }
@Override protected void onClose0() { // Save any changes if needed saveShopState(); }
@Override @Nonnull public ItemContainer getItemContainer() { return shopInventory; }
@Override public void handleAction( @Nonnull Ref<EntityStore> ref, @Nonnull Store<EntityStore> store, @Nonnull WindowAction action ) { if (action instanceof SelectSlotAction selectAction) { handleSlotSelection(ref, store, selectAction.slot); } }
private void handleSlotSelection( Ref<EntityStore> ref, Store<EntityStore> store, int slot ) { if (slot >= 0 && slot < shopInventory.getCapacity()) { selectedSlot = slot; invalidate(); // Mark window as dirty to send update
// Process purchase logic processPurchase(ref, store, slot); } }
private void loadShopItems() { // Load items into shopInventory }
private void saveShopState() { // Persist shop state }
private void processPurchase( Ref<EntityStore> ref, Store<EntityStore> store, int slot ) { // Handle purchase logic }}Using the Shop Window:
// In your plugin or command handlerpublic void openShopForPlayer(PlayerRef playerRef) { Player player = // ... get player component WindowManager windowManager = player.getWindowManager();
ShopWindow shop = new ShopWindow("General Store", 27); OpenWindow packet = windowManager.openWindow(shop);
if (packet != null) { // Window opened successfully
// Register close handler shop.registerCloseEvent(event -> { System.out.println("Player closed the shop"); }); }}Best Practices
Section titled “Best Practices”- Always check
openWindow()return value - Returns null if window failed to open - Clean up in
onClose0()- Unregister event handlers and release resources - Use
invalidate()for updates - Let the server batch updates efficiently - Implement
ValidatedWindowfor distance-based windows - Prevents exploit abuse - Handle all expected action types - Don’t ignore client actions silently
- Use JSON window data sparingly - Large data payloads affect network performance
- Register close events for cleanup - Ensure resources are freed when windows close
- Consider thread safety - Window operations may occur on different threads