Skip to content

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.

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 validation

The WindowManager handles all window operations for a specific player. It is accessed through the player’s component system.

import com.hypixel.hytale.server.core.entity.entities.player.windows.WindowManager;
import com.hypixel.hytale.server.core.entity.entities.Player;
// Get WindowManager from player component
Player playerComponent = store.getComponent(ref, Player.getComponentType());
WindowManager windowManager = playerComponent.getWindowManager();
import com.hypixel.hytale.protocol.packets.window.OpenWindow;
// Open a window and get the packet to send
Window 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 once
Window[] windows = { window1, window2, window3 };
List<OpenWindow> packets = windowManager.openWindows(windows);
if (packets == null) {
// One or more windows failed to open - all are closed
}
// 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();
// Close a specific window by ID
Window closedWindow = windowManager.closeWindow(windowId);
// Close all windows for the player
windowManager.closeAllWindows();
// Close window from within the window instance
window.close();

Window IDs are managed automatically by the WindowManager:

IDDescription
-1Invalid/unassigned
0Reserved for client-initiated windows
1+Server-assigned IDs (auto-incremented)
// Get a window by ID
Window window = windowManager.getWindow(windowId);
// Get all active windows
List<Window> allWindows = windowManager.getWindows();

Windows implementing ValidatedWindow are automatically validated each tick:

// Called automatically by the server
windowManager.validateWindows();

All windows extend the abstract Window class.

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
}
}
1. Window constructed
2. WindowManager.openWindow() called
3. Window.init() - receives PlayerRef and WindowManager
4. Window.onOpen() -> onOpen0()
- Return true to complete opening
- Return false to cancel (window is closed)
5. OpenWindow packet sent to client
6. Window active - handles actions, updates
7. Window.close() or WindowManager.closeWindow()
8. Window.onClose() -> onClose0()
9. WindowCloseEvent dispatched
10. CloseWindow packet sent to client

Window data is sent to the client as JSON:

@Override
public 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 rebuild
protected void setNeedRebuild() {
this.needRebuild.set(true);
this.getData().addProperty("needRebuild", Boolean.TRUE);
}
// Mark window as dirty (will send update)
protected void invalidate() {
this.isDirty.set(true);
}
// Check and consume dirty state
protected boolean consumeIsDirty() {
return this.isDirty.getAndSet(false);
}
// Access window properties
public int getId() { return this.id; }
public WindowType getType() { return this.windowType; }
public PlayerRef getPlayerRef() { return this.playerRef; }

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 handler
EventRegistration registration = window.registerCloseEvent(event -> {
// Handle window closure
System.out.println("Window closed!");
});
// With priority
EventRegistration reg = window.registerCloseEvent(
EventPriority.EARLY,
event -> handleClose(event)
);
// Unregister when done
registration.unregister();

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 type
Window.CLIENT_REQUESTABLE_WINDOW_TYPES.put(
WindowType.PocketCrafting,
() -> new PocketCraftingWindow()
);
// In WindowManager - handles client request
UpdateWindow packet = windowManager.clientOpenWindow(window);

Defines the types of windows recognized by the protocol.

TypeIDDescription
Container0Generic item container
PocketCrafting1Portable/pocket crafting interface
BasicCrafting2Basic crafting table
DiagramCrafting3Diagram-based crafting (schematics)
StructuralCrafting4Structural/building crafting
Processing5Processing bench (furnace, etc.)
Memories6Memories/journal interface
import com.hypixel.hytale.protocol.packets.window.WindowType;
// Get type from value
WindowType type = WindowType.fromValue(0); // Container
// Get value from type
int value = WindowType.Container.getValue(); // 0
// All types
WindowType[] allTypes = WindowType.VALUES;

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

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();
}
}
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 display
ItemQuantity[] materials = new ItemQuantity[] { /* ... */ };
section.setExtraMaterials(materials);
// Track validity
section.setValid(true);
boolean valid = section.isValid();
// Associated item container
section.setItemContainer(container);
ItemContainer container = section.getItemContainer();

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();
}
}

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 container
ItemContainer container = new SimpleItemContainer((short) 27);
// Create and open the window
ContainerWindow window = new ContainerWindow(container);
windowManager.openWindow(window);

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:

  1. Player reference exists
  2. Player is within max distance
  3. Chunk is loaded
  4. Block at position matches original block type

Block-based container (chests, storage blocks, etc.).

import com.hypixel.hytale.server.core.entity.entities.player.windows.ContainerBlockWindow;
// Create window for a block at position
ContainerBlockWindow window = new ContainerBlockWindow(
x, y, z, // Block position
rotationIndex, // Block rotation
blockType, // BlockType asset
itemContainer // ItemContainer for storage
);
// Window data includes blockItemId automatically
windowManager.openWindow(window);

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 metadata
ItemStackContainerWindow window = new ItemStackContainerWindow(backpackContainer);
windowManager.openWindow(window);

Automatically closes when the parent item stack becomes invalid.

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 categories
CraftingBench bench = // ... from block config
BenchCategory[] 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 header
boolean isHeader = bench.isHeaderCategory("building");
// Get category sort order
int index = bench.getCategoryIndex("walls");
// Configuration flags
boolean allowCycling = bench.shouldAllowBlockGroupCycling();
boolean showHints = bench.shouldAlwaysShowInventoryHints();

Window actions are client-to-server messages for interacting with windows.

import com.hypixel.hytale.protocol.packets.window.WindowAction;
// Actions are deserialized from network packets
// Type ID determines the specific action class
IDAction ClassDescription
0CraftRecipeActionCraft a specific recipe
1TierUpgradeActionUpgrade crafting tier
2SelectSlotActionSelect a slot in the window
3ChangeBlockActionCycle block variant
4SetActiveActionSet active state
5CraftItemActionGeneric craft action
6UpdateCategoryActionChange crafting category
7CancelCraftingActionCancel current craft
8SortItemsActionSort container items

CraftRecipeAction:

import com.hypixel.hytale.protocol.packets.window.CraftRecipeAction;
// Fields
String recipeId; // Recipe identifier (nullable)
int quantity; // Number to craft
// Example handling
public 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;
// Fields
int slot; // Selected slot index
// Creating an action
SelectSlotAction action = new SelectSlotAction(5);

SortItemsAction:

import com.hypixel.hytale.protocol.packets.window.SortItemsAction;
import com.hypixel.hytale.protocol.SortType;
// Fields
SortType sortType; // Name, Category, etc.
// Example from ContainerBlockWindow
@Override
public 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;
// Fields
String category; // Main category
String itemCategory; // Sub-category

ChangeBlockAction:

import com.hypixel.hytale.protocol.packets.window.ChangeBlockAction;
// Fields
boolean down; // Direction of change

SetActiveAction:

import com.hypixel.hytale.protocol.packets.window.SetActiveAction;
// Fields
boolean state; // New active state
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...
}
}

Sent when opening a new window.

FieldTypeDescription
idintWindow ID (unique per player)
windowTypeWindowTypeType of window
windowDataStringJSON data (nullable)
inventoryInventorySectionItem container data (nullable)
extraResourcesExtraResourcesExtra resource data (nullable)

Packet ID: 200

Sent when window data/contents change.

FieldTypeDescription
idintWindow ID
windowDataStringUpdated JSON data (nullable)
inventoryInventorySectionUpdated inventory (nullable)
extraResourcesExtraResourcesUpdated resources (nullable)

Packet ID: 201

Sent when closing a window.

FieldTypeDescription
idintWindow ID to close

Packet ID: 202

Sent when player performs an action in a window.

FieldTypeDescription
idintWindow ID
actionWindowActionThe action performed

Packet ID: 203

Sent when client requests to open a client-initiated window.

FieldTypeDescription
typeWindowTypeRequested window type

Packet ID: 204

Only window types registered in Window.CLIENT_REQUESTABLE_WINDOW_TYPES can be opened this way.

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 handler
public 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");
});
}
}
  1. Always check openWindow() return value - Returns null if window failed to open
  2. Clean up in onClose0() - Unregister event handlers and release resources
  3. Use invalidate() for updates - Let the server batch updates efficiently
  4. Implement ValidatedWindow for distance-based windows - Prevents exploit abuse
  5. Handle all expected action types - Don’t ignore client actions silently
  6. Use JSON window data sparingly - Large data payloads affect network performance
  7. Register close events for cleanup - Ensure resources are freed when windows close
  8. Consider thread safety - Window operations may occur on different threads