Complete technical documentation for building a Growtopia Private Server from scratch.
Growtopia is a 2D MMO sandbox game (originally by Seth Robinson & Hamumu Software, now Ubisoft). A Growtopia Private Server emulates the official game protocol so the unmodified retail client connects to your custom server instead.
The client uses ENet (reliable UDP) for gameplay and HTTPS for the initial login handshake. By redirecting DNS (or editing the hosts file), the client talks to your server transparently.
| # | File | Contents |
|---|---|---|
| 01 | Protocol | ENet configuration, message types, packet format |
| 02 | Login Flow | Full connection sequence from HTTP to world entry |
| 03 | Tank Packet | 56-byte binary packet layout, flags, usage |
| 04 | Variant System | Server-to-client RPC mechanism |
| 05 | World System | World structure, generation, binary format |
| 06 | Player System | Player data, inventory, clothing, roles |
| 07 | Item Database | items.dat binary format, encryption, types |
| 08 | Game Systems | Farming, locks, economy, trading, features |
| 09 | Dialog System | UI dialog markup language |
| 10 | Reference | All packet types, actions, variants, commands |
| 11 | Advanced Protocol | Inventory format, tile extras, ping, object pickup |
The protocol facts and binary layouts in these docs are cross-referenced against four working private servers. When something is documented as "verified", it means at least two of these sources agree:
| Server | Path | Strength |
|---|---|---|
| NiceTopia | D:\NiceTopia-Project2\Source (this repo) |
Largest fork (~800KB Source.cpp); covers most edge cases |
| Gurotopia | D:\artefak\Gurotopia-master |
Newest reference (Dec 2025); items.dat v25/v26, modern dialog builder |
| Windsverse | D:\artefak\WINDSVERSE\WINDSVERSE\source |
Tightly written ItemsManager, classic inventory packing |
| GTServer / HappyPS | D:\GTServer\GTServer |
Compact ENet wrapper, useful for verifying ENet config |
For items.dat field-by-field analysis, see also tools/itemsdat-codec/ (this
repo) which has been validated for round-trip identity on v18 and v21 files
and synthesizes correct v22-v26 output.
+-------------------+
| Growtopia Client |
+--------+----------+
|
+--------------+--------------+
| |
HTTPS POST (login) ENet UDP (gameplay)
| |
v v
+----------+----------+ +-----------+-----------+
| HTTP Server | | Game Server |
| /growtopia/ | | Port 17091 |
| server_data.php | | ENet + CRC32 + |
| Returns IP:port | | Range Coder |
+---------------------+ +-----------------------+
|
v
+----------+----------+
| Database |
| (players, worlds) |
+---------------------+
Transport ENet (reliable UDP) with CRC32 checksum + Range Coder compression
Login HTTPS POST to /growtopia/server_data.php
Game Data Binary protocol (56-byte tank packets) + pipe-delimited text
Item DB items.dat (~5-8 MB binary, served once, cached by client)
Default Port 17091 UDP
[x] HTTP endpoint returning server IP + port
[x] ENet host with CRC32 + Range Coder + usingNewPacketForServer enabled
[x] Send SERVER_HELLO on client connect
[x] Parse client login data (GENERIC_TEXT)
[x] Validate or create player account
[x] Send OnSuperMainStart variant (items.dat hash, CDN, settings)
[x] Serve items.dat binary (SEND_ITEM_DATABASE_DATA)
[x] Handle action|enter_game
[x] Handle action|join_request -> generate world -> send SEND_MAP_DATA
[x] Send OnSpawn for all players in world (with type|local for the joiner)
[x] Send SEND_INVENTORY_STATE
[x] Handle PACKET_STATE (movement) and broadcast to others
[x] Handle TILE_CHANGE_REQUEST (place/break) and broadcast
[x] Handle disconnect -> save player, broadcast OnRemove
| Symptom | Cause |
|---|---|
| Client disconnects immediately | CRC32 or Range Coder not enabled, or usingNewPacketForServer not set |
| Client ignores packets | Packet exceeds 16384 bytes header limit |
| Text packet fails | Missing null terminator |
| Client re-downloads items.dat every login | Hash mismatch in OnSuperMainStart |
| Players invisible to each other | net_id not unique per world |
| Player appears at wrong position | Using tile coords instead of pixels (pixel = tile * 32) |
| Variant call does nothing | Index 0 is not a string (must be function name) |
| Extended data missing | EXTENDED flag (0x08) not set in tank packet |
| Inventory pane empty | Wrong header — item_count is uint32, not uint16 |
| Byte corruption | Not using Little-Endian byte order |
| Tool | Description |
|---|---|
| itemsdat-codec | items.dat decoder/encoder (Node.js, zero deps, full v11–v26 support, future-proof v27+ via _unknownTrailingData) |
Built from reverse-engineering analysis of NiceTopia, GTServer/HappyPS, Gurotopia, Windsverse, and GTProxy-fix. Field offsets and binary layouts were validated by parser round-trip testing where possible.