Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Home Page

Amazing Core

Amazing Core is an open-source server emulator for Amazing World, an MMO originally developed by Ganz and shut down in 2018. This project provides a modular, configurable framework with tools for server management, asset handling, and game services, accessible via a web-based dashboard.

⚠️ Still in development - not yet in a playable state.

  • No multiplayer, NPCs, or quests yet;
  • Only the intro level and the empty Spring Bay map are accessible;
  • Do not use your real username or password;
  • Use any dummy username and password to log in;

But you can check out the work-in-progress prototype and join our community!

Download the game

You can install the latest published version with the following Steam link: Install

The game has its page on SteamDB, where you can also see additional information.

It is also possible to find an Android version on the internet.

Connect to the demo server

After installation, navigate to the game folder and open the ServerConfig.xml file in a text editor.

Modify the server address value as shown below:

ServerIP = 'springbay.amazingcore.org'

Now you can start the game.

  • To play the intro level, click the I'm new! button in the main menu;
  • To explore the Spring Bay, click the Log in button and enter any username and password;

Host your own server

With your own server, you can access the admin dashboard to configure skins, maps, NPCs, and other features (work in progress)*.

Modify the server address value as shown below:

ServerIP = 'localhost'

Pre-compiled binaries

  1. Download the latest server release from the GitHub section.
  2. Extract the archive to a folder of your choice;
  3. Run the server binary;

Once started, it will download the blob.db file (~2 GB).*

When the download is finished, you can start the game.

  • The API server will be available at http://localhost:3000
  • Use admin / admin to log in to the dashboard
  • The game server will listen on localhost:8182

Configuration

You can customize server settings using the config.json file.

KeyDescription
logger.levelLog verbosity: debug, debug+sql, info, warn, error
logger.handlerLog format: pretty (colored, formatted), text, json
servers.apiHTTP API bind address (e.g. localhost:3000)
servers.gameTCP game server bind address (e.g. localhost:8182)
settings.assetDeliveryURLBase CDN URL sent to game clients
settings.syncServerIPSync server IP sent in InitLocation responses
settings.syncServerPortSync server port sent in InitLocation responses
storage.blob.downloadAuto-download blob.db on first start if missing
storage.blob.urlURL to fetch blob.db from
storage.databases.corePath to core.db - main SQLite database
storage.databases.blobPath to blob.db - assets SQLite database
storage.explorerEnable the dashboard SQL explorer - only for testing!
secure.auth.usernameDashboard admin username
secure.auth.passwordDashboard admin password
secure.session.keyCookie session signing key
secure.session.secureSet Secure flag on session cookie (enable behind HTTPS)

Running the game on macOS

The Steam version of the game is not compatible with modern macOS (Apple Silicon), but you can try following this guide.

License

This project is licensed under the GNU AGPL v3.

Amazing World™ is a registered trademark of Ganz. Amazing Core is an unofficial, fan-made project intended for personal and educational use only. It is not affiliated with or endorsed by Ganz or Amazing World™ in any way.

Cache Archive

Amazing World used Unity Streaming Assets, meaning things like images, audio, and asset bundles were stored on official servers and loaded by the game whenever they were needed. These files were also cached locally. Below is a list of known assets that have been found and shared by members of the community.


Loading cache list...

GSFOID Calculator

A simple calculator for checking the OID (a unique object identifier) used by the game.

  • The CDN ID is a base64 representation of GSF OID.
  • The GSF OID is an int64 number that is sliced into specific groups of bits.

Build from source

Build using Go

To build the server from source, you will need Go 1.25 or newer:

make
# or
go build -o ./build/server ./cmd/server/main.go

To build and run with a single command:

make run
# or
go run ./cmd/server/main.go

You can choose between SQLite drivers by setting the CGO_ENABLED environment variable:

  • Build with CGO_ENABLED=0 to use modernc.org/sqlite driver (default);
  • Build with CGO_ENABLED=1 to use github.com/mattn/go-sqlite3 driver;

Folder structure

amazing-core/
├── cmd/
│   └── server/
│       └── main.go           - server entry point
├── data/
│   ├── cache.json            - asset metadata generated by cache-tool
│   └── sql/
│       ├── core_db/
│       │   ├── base.sql      - core.db base migration
│       │   └── updates/      - incremental migrations
│       ├── blob_db/
│       │   └── base.sql      - blob.db schema
│       └── queries/          - sql queries for admin dashboard explorer
├── internal/
│   ├── api/                  - http server for admin dashboard and asset streaming
│   ├── game/                 - game server and gsf messages handling
│   ├── network/              - tcp server protocol implementation
│   ├── services/             - business logic and database interaction
│   ├── config/               - configuration variables
│   └── lib/                  - shared libraries (e.g. logging, helpers)
├── tools/                    - development tools (e.g. asset importers)
└── web/                      - embedded frontend for admin dashboard

Data and databases

The data/ directory contains .sql database migrations and a cache.json file with currently known asset files metadata.

SQLite Databases

For simplicity and portability, the project uses SQLite. The data/sql/ directory is embedded into the server binary at compile time, and migrations are run automatically at startup.

core.db

Schema: data/sql/core_db/

The main SQLite database. Contains the classified list of available assets and random names used in the sign-up scene.

Managed by goose using migrations in data/sql/core_db/updates/. Shortcuts for creating, applying, and resetting migrations are available in the Makefile.

An initial squashed migration (data/sql/core_db/base.sql) includes both schema and seed data.

Use data/sql/core_db/squash.sh to squash update migrations into base.sql.

Files under data/sql/queries/ are named example SQL queries available to the admin dashboard`s SQL Explorer.

blob.db

Schema: data/sql/blob_db/

A separate SQLite database storing the raw binary content of game asset files.

Downloaded on startup if blob.download = true and the database is missing.

When a client requests /cdn/{cdnid}, the server fetches the blob column for that cdnid.

The database can be populated using the blob-tool or the admin dashboard.

Cache Metadata

cache.json

A summary of known cache files, including name (CDN ID), size, type, hash, GSF OID and basic bundle info (version, object counts, scene roots).

Generated with the cache-tool Python script:

python tools/cache-tool/cache.py /path/to/cache/folder \
  --summary-file data/cache.json

This file is already included in the core.db base migration. For future updates (if new unique cache assets are discovered), add a new migration under updates/ with the additional data.

Networking

This section details the client-server communication protocol:

BitProtocol

Overview

The game client communicates with the server over a persistent TCP connection using a custom binary protocol. All data is serialized with the BitProtocol codec - a bit-level encoding scheme that compresses integers by encoding only the bytes that are actually needed.

The implementation lives in internal/network/

Wire Format

Every message follows this structure:

┌─────────────────────────────────────────────────────────┐
│  length prefix  │        payload bytes          │ 0x00  │
│  (varint)       │     (BitStream encoding)      │ (EOF) │
└─────────────────────────────────────────────────────────┘

Length prefix

The length prefix is a variable-length big-endian integer where the MSB of each byte signals whether more bytes follow:

Each group of 7 bits contributes to the value, MSB = continuation flag:

[1xxxxxxx] [1xxxxxxx] [1xxxxxxx] [0xxxxxxx]
 more bytes more bytes more bytes last byte

Payload

The payload is a BitStream - a sequence of bits packed into bytes. The stream is read and written bit-by-bit; byte boundaries are only respected for raw string/byte-array data (aligned reads/writes).

After the last payload byte comes a null terminator 0x00.

BitStream Encoding

Objects (nullable)

Objects begin with a null flag bit:

[0] -> object is not null
[1] -> null / not present

Booleans

A single bit: 1 = true, 0 = false.

Compressed integers (int16, int32, int64)

Integers are compressed using a variable-width encoding that minimizes bit usage for small values.

The encoding starts with a compressed flag bit:

[1] -> compressed (fewer than max bytes needed)
      followed by a count of how many bytes are needed
      [0]   -> 0 bytes -> value fits in 4 bits
      [10]  -> 1 byte  -> value is 1 byte  (8 bits)
      [110] -> 2 bytes -> value is 2 bytes (16 bits)
      ...
[0] -> full width (all bytes written)

Floating-point numbers (float32, float64)

Written as raw not compressed IEEE 754 bytes.

Strings

Strings are encoded as:

  1. A compressed int32 for the UTF-8 byte length.
  2. The raw UTF-8 bytes, byte-aligned (any remaining bits in the current byte are skipped before writing).

Byte arrays

Same as strings: compressed length prefix followed by byte-aligned data.

Dates

Dates are encoded relative to a fixed epoch (0001-03-01). A null flag bit precedes the value:

[1] -> zero time (null)
[0] -> seconds since epoch, written as a raw 8-byte integer

Message Structure

Every message has a header followed by an optional body. The outer wrapper adds a null flag for the entire message object.

[0]          -> message is not null
[header]     -> GSF header fields
[0]          -> body is not null
[body fields]

GSF Header

FieldTypeConditionDescription
flagsint32alwaysBit flags
svcClassint32alwaysMessage service class
msgTypeint32alwaysMessage type for the given svcClass
requestIdint32if IsService()Correlates request/response pairs
logCorrelatorstringif IsRequest()Client-side correlation string
resultCodeint32if IsResponse()Result code (0 = success)
appCodeint32if IsResponse()Application-level error code
appStringstringif appCode != 0Error description string
appCodesarrayif appCode == 17Extended error code list

Flag semantics:

BitMeaning
flags & 2 == 0IsService - a request/response pair
flags & 1 != 0IsResponse (only when IsService)
flags & 2 != 0IsNotify - fire-and-forget notification
flags & 16 != 0IsDiscardable

Annotated Example

The very first message the client sends after connecting is a GetClientVersionInfo request. It is 22 bytes total:

hex:  15 20 c2 5c 04 6d 0c 0c 18 41 6d 61 7a 69 6e 67 57 6f 72 6c 64 00

Breakdown:

BytesValueMeaning
1521Length prefix: payload is 21 bytes
20 c2 5c 04 6d 0c 0c 18bit streamHeader + body
41 6d 61 7a 69 6e 67 57 6f 72 6c 64AmazingWorldString content (byte-aligned)
000Null terminator

Bit-by-bit payload decoding:

Bit  8:  [0]                -> message is not null
Bit  9:  [0]                -> header is not null
Bit 10:  [1][0]             -> flags compressed, 0 bytes -> 4-bit value
Bit 14:  [0000]             -> flags = 0
Bit 16:  [1][1][0]          -> svcClass compressed, 1 byte follows
Bit 19:  [00010010]         -> svcClass = 18 (USER_SERVER)
Bit 27:  [1][1][1][0]       -> msgType compressed, 2 bytes follow
Bit 31:  [0000001000110110] -> msgType = 566 (GET_CLIENT_VERSION_INFO)
Bit 47:  [1][0]             -> requestId compressed, 0 bytes -> 4-bit value
Bit 51:  [0001]             -> requestId = 1
Bit 53:  [1][0]             -> logCorrelator length compressed, 0 bytes -> 4-bit value
Bit 57:  [0000]             -> length = 0 (empty string)
Bit 59:  [0]                -> body is not null
Bit 60:  [1][1][0]          -> clientName length compressed, 1 byte follows
Bit 63:  [00001100]         -> length = 12 (bytes in "AmazingWorld")
Bit 71:  [0] align          -> skip to byte boundary
Bits 72–167:                -> "AmazingWorld" (12 bytes, 96 bits)

Go Implementation

Reading a message

// 1. Read framing length from buffered reader
length, err := codec.ReadLength(stream)

// 2. Read 'length' bytes into data buffer
data := make([]byte, length)
io.ReadFull(stream, data)

// 3. Create a BitReader over the raw bytes
reader := bitprotocol.NewBitReader(data)

// 4. Parse the header
header, err := gsf.ReadHeader(reader)

// 5. Look up the handler
handler, ok := router.Lookup(header.SvcClass, header.MsgType)

// 6. Build request and response objects
conn := &gsf.Connection{remoteIP: remoteAddr}
req := gsf.NewRequest(ctx, header, reader, conn)
res := gsf.NewResponse(header, writer)

// 7. Call the handler
handler(res, req)

Implementing a handler

func GetClientVersionInfo(w gsf.ResponseWriter, r *gsf.Request) error {
    // Decode the request body
    req := &messages.GetClientVersionInfoRequest{}
    if err := r.Read(req); err != nil {
        return err
    }

    // Build and send the response
    res := &messages.GetClientVersionInfoResponse{
        ClientVersionInfo: "133852.true",
    }
    return w.Write(res)
}

Defining a message type

Request and response structs implement gsf.Deserializable and gsf.Serializable:

type GetClientVersionInfoRequest struct {
    ClientName string
}

func (req *GetClientVersionInfoRequest) Deserialize(reader gsf.ProtocolReader) {
    req.ClientName = reader.ReadString()
}

type GetClientVersionInfoResponse struct {
    ClientVersionInfo string
}

func (res *GetClientVersionInfoResponse) Serialize(writer gsf.ProtocolWriter) {
    writer.WriteString(res.ClientVersionInfo)
}

Collection helpers

The gsf package provides generic helpers for encoding and decoding slices, maps, and nullable values:

// Slices: int32 length prefix (−1 = nil), then elements
gsf.ReadSlice(reader, func() MyType { ... })
gsf.WriteSlice(writer, slice, func(v MyType) { ... })

// Maps: int32 length prefix (−1 = nil), then string key + value pairs
gsf.ReadMap(reader, func() MyType { ... })
gsf.WriteMap(writer, dict, func(v MyType) { ... })

// Nullable objects: bool null flag + optional value
gsf.ReadNullable(reader, func() MyType { ... })
gsf.WriteNullable(writer, value, func(v MyType) { ... })

GSF Classes

This section documents game requests and responses grouped by flow.

Each request is a GSF message sent by the client to the server.

Assembly-CSharp

The game is built using Unity engine. The latest version of the game was compiled with 5.3.6f1.

Most of the game’s core logic is contained in the Assembly-CSharp.dll file.

This DLL may be decompiled, modified, and recompiled using common .NET C# tools such as:

  • ILSpy: primary decompiler, successfully decompiles nearly all code without issues;
  • dnSpy: used for edge cases where ILSpy fails (in this project, only a single file required it);

Startup Messages

On game start, before the main menu becomes interactive, AkamaiServerCheck opens a temporary session to perform a version check, then closes it.

#MessageInvoked at
1GetClientVersionInfoAkamaiServerCheck.cs:70

GetClientVersionInfo

Description

Sent on game start, before the main menu is interactive. A temporary session is created for this check. The client needs to know whether it is running an outdated version of the game. On receiving the response, it compares the server version number against GameSettings.clientLocalVersion.

Request

FieldTypeDescription
ClientNamestringHardcoded to "AmazingWorld"

Response

FieldTypeDescription
ClientVersionInfostringVersion string in "<version>.<forceUpdate>" format, e.g. "133852.true". The forceUpdate part is either true (blocking) or false (optional).

System Messages

Request and response messages used in multiple flows.

GetSiteFrame

Description

  • Sent when the intro scene begins loading (on registration).
  • Sent after tiers are loaded, if SessionID is valid (on login).

Fetches the site frame configuration for the current session.

The response also carries AssetDeliveryURL, which the client stores in GameSettings.assetDeliveryURL and uses for asset downloads.

Request

FieldTypeDescription
TypeValueint32Hardcoded to 1
LanglocalePairIDOID“Class”: 4, “Type”: 19 “Server”: 0, “Number”: 9023265
TierIDOID“Class”: 0, “Type”: 0, “Server”: 0, “Number”: 0
BirthDatetime.Time#N/A
RegistrationDatetime.Time#N/A
PreviewDatetime.Time#N/A
IsPreviewEnabledboolfalse

Response

FieldTypeDescription
SiteFrameSiteFrameSiteFrame object
AssetDeliveryURLstringBase URL used for asset downloads

Registration Messages

When the player clicks “I’m new!” in the main menu, the intro sequence begins.

Player chooses a name, a family name, and account credentials.

#MessageInvoked at
1GetPublicItemCategoriesUSPopulateIntroInventoryGrid.cs:46
2GetSiteFrameIntroManager.cs:156
3GetRandomNamesIntroServiceCallManager.cs:74,88
4ValidateNameUSValidateName.cs:36, USRegisterPlayer.cs:151
5SelectPlayerNameUSWorldName.cs:349
6CheckUsernameIntroServiceCallManager.cs:111, RegistrationManager.cs:52
7RegisterPlayerIntroServiceCallManager.cs:135, USRegisterPlayer.cs:125
8RegisterAvatarForRegistrationIntroServiceCallManager.cs:322

GetPublicItemCategories

Description

This is the public item-category lookup used by the registration flow.

Its purpose is to give the intro scene enough category data to classify and render preview items that are shown before the player has fully registered.

The returned categories are added into InventoryManager and then used when the public items are converted into temporary GSFPlayerItems.

This message is for public preview content, while GetCMSItemCategories is for the actual logged-in game state.

Request

FieldTypeDescription
LanglocalePairIDOID“Class”: 4, “Type”: 19 “Server”: 0, “Number”: 9023265
TierIDOID“Class”: 0, “Type”: 0, “Server”: 0, “Number”: 0
BirthDatetime.Time#N/A
RegistrationDatetime.Time#N/A
PreviewDatetime.Time#N/A
IsPreviewEnabledboolfalse

Response

FieldTypeDescription
ItemCategories[]ItemCategoryList of item categories

GetRandomNames

Description

Sent in two situations during the intro sequence:

  • When the player requests a random Zing name;
  • When building the family name picker;

Returns a list of randomly selected names of the requested type.

Request

FieldTypeDescription
Amountint32Number of names to return
NamePartTypestring"second_name" for Zing names, "Family_1", "Family_2", "Family_3" for family name parts

Response

FieldTypeDescription
Names[]stringList of randomly selected names

ValidateName

Description

Sent when the player confirms their Zing name during the sign up.

Checks whether the chosen player name contains any filtered or prohibited words.

Request

FieldTypeDescription
NamestringThe player name to validate

Response

FieldTypeDescription
FilterNamestringThe client does not really care about the value. A non-empty value means the name was rejected.

SelectPlayerName

Description

Sent when the player confirms their family name by pressing the Next button.

Reserves the chosen family name on the server so no other player can claim it during the same session(?).

Request

FieldTypeDescription
NamestringThe family name to reserve

Response

No fields.

Success is implied by a non-error response.

On AppCode 71 (duplicate) the client shows an error dialog.

CheckUsername

Description

Sent when the player submits the registration form.

Verifies that the chosen username is not already taken.

Request

FieldTypeDescription
UsernamestringThe username to check
PasswordstringThe account password

Response

No fields.

Success is implied by a non-error response.

On AppCode 301 the server signals the username is already in use.

RegisterPlayer

Description

Sent when the player submits the registration form.

Creates the player account on the server.

On success, the returned PlayerID is immediately used by the client to call RegisterAvatarForRegistration, which associates the chosen avatar and starter items with the new account.

Request

FieldTypeDescription
Tokenstring
PasswordstringChosen password
ParentEmailAddressstringChosen email
BirthDatetime.Time
GenderstringPlayer gender (always "U" for unspecified)
LocationIDOID“Class”: 0, “Type”: 0, “Server”: 0, “Number”: 0
UsernamestringChosen username
WorldnamestringChosen family name
ChatAllowedboolWhether the player has enabled chat
CNLstringChannel: steam
ReferredByWorldnamestring
LoginTypeint32

Response

FieldTypeDescription
PlayerIDOIDThe newly created player’s OID

RegisterAvatarForRegistration

Description

Sent after a successful RegisterPlayer response.

Associates the chosen avatar and starter inventory items with the newly created player account.

Request

FieldTypeDescription
PlayerIDOIDThe OID returned by RegisterPlayer
SecretCodestring
NamestringAvatar name
Biostring
AvatarIDOIDOID of the selected avatar
GivenInventoryIDs[]OIDList of starter item OIDs selected during intro
GivenItemSlotIDs[]OIDList of inventory slot OIDs for the starter items

Response

FieldTypeDescription
PlayerAvatarPlayerAvatarThe created avatar object
InvalidCodeCountint32Number of invalid secret code attempts
InvalidCodeThresholdint32Maximum allowed invalid code attempts

Login Messages

When the player submits their credentials on the login screen, the client opens a session and begins the login sequence.

After the initial login response the client runs two load queues:

  • ClientServices: starts in ClientManager.StartLogin(), initialises background services (including connection to the SYNC server).

  • ZoneTransitionQueue: starts in ClientManager.LoadZone() after the SiteFrame assets are preloaded, runs the full zone-entry sequence.

After the SiteFrame load, AnimationLoaded() is then called inline, which starts preloading assets.

#MessageInvoked at
1LoginClientManager.cs:567
2GetTiersClientManager.cs:652
3GetSiteFrameClientManager.cs:647
4GetCMSItemCategoriesInventoryManager.cs:846
5GetOutfitItemsLoadCurrentOutfitCommand.cs:5
6GetAvatarsLoadAvatarsCommand.cs:13
7GetOutfitsAvatarAssetsLoader.cs:138
8GetZonesLoadZonesCommand.cs:18
9InitLocationLoadHomeZoneCommand.cs:23
10SyncLoginSyncManager.cs:331
11GetMazeItemsLoadMazeItemsCommand.cs:28
12GetChatChannelTypesLoadChatChannelTypesCommand.cs:7
13GetAnnouncementsLoadGlobalAnnouncementsCommand.cs:11
14EnterBuildingLoadEnterBuildingMazeCommand.cs:49
15GetOnlineStatusesInitFriendMangerNotificationManagerCommand.cs:9
16GetPlayerNPCsLoadNPCsCommand.cs:29

Login

Description

Sent when the player submits the login form.

Request

FieldTypeDescription
LoginIDstringPlayer username
PasswordstringPlayer password
SitePINint32Hardcoded to 1234
LanguageLocalePairIDOID“Class”: 4, “Type”: 19, “Server”: 0, “Number”: 9023265
UserQueueingTokenstringHardcoded to "Token"
ClientEnvInfoClientEnvironmentDataOS, resolution, Unity version, etc.
Tokenstring
LoginTypeint32
CNLstringChannel: steam

Response

FieldTypeDescription
SiteInfoSiteInfo
StatusSessionStatus
SessionIDOID
ConversationIDint64
AssetDeliveryURLstringBase URL used for asset downloads
PlayerPlayer
MaxOutfitint16
PlayerStats[]PlayerStats
PlayerInfoTOPlayerInfoTO
CurrentServerTimetime.Time
SystemLockoutTimetime.Time
SystemShutdownTimetime.Time
ClientInactivityTimeoutint32
CNLstring

GetTiers

Description

Sent immediately after a successful login response.

Fetches all subscription tiers. The client matches the player’s tierID from PlayerInfoTO against the returned list to determine whether the account is paid or free-play.

On success, GetSiteFrame() is called if SessionID is valid.

Request

No fields.

Response

FieldTypeDescription
Tiers[]TierList of tiers

GetCMSItemCategories

Description

This is the main item-category lookup for the logged-in game.

The response is cached into InventoryManager.itemCategories, and many systems rely on that cache to map category OIDs to semantic item types such as Clothing, Decoration, Yard, MazePiece, and so on.

Request

No fields.

Response

FieldTypeDescription
ItemCategories[]ItemCategoryList of item categories

GetOutfitItems

Description

Sent as the first step of the ZoneTransitionQueue.

Fetches the items currently equipped(?) by the player’s active avatar.

Request

FieldTypeDescription
PlayerAvatarOutfitIDOIDRequested avatar outfit OID
PlayerIDOIDRequested player OID

Response

FieldTypeDescription
OutfitItems[]PlayerItemList of player items

GetAvatars

Description

Sent during the ZoneTransitionQueue, after outfit items are loaded.

Fetches the list of player avatars. The returned list is stored in AvatarManager.Instance.GSFPlayerAvatars.

LoadAvatarsCommand.Step2() calls AvatarManager.LoadAvatarAssets() for the active player avatar, which in turn calls GetOutfits.

The active player avatar must be present in the returned array. (?)

Each PlayerAvatar.Avatar.AssetMap must contain a "Prefab_Unity3D" entry with at least one asset whose ResName is not "PF__Avatar.unity3d". (?)

Request

FieldTypeDescription
Startint32Start index, 0
Maxint32Max results, -1 for all
FilterIDs[]OIDEmpty filter list

Response

FieldTypeDescription
Avatars[]PlayerAvatarList of player avatars

GetOutfits

Description

Sent during the ZoneTransitionQueue after avatars are loaded, once per avatar whose assets are being loaded.

Fetches the saved outfits for a given player avatar. The results are stored as PresetOutfits on the AvatarAssets object.

Request

FieldTypeDescription
PlayerAvatarIDOIDRequested avatar OID
PlayerIDOIDRequested player OID

Response

FieldTypeDescription
PlayerAvatarOutfits[]PlayerAvatarOutfitList of avatar outfits

GetZones

Description

Sent during the ZoneTransitionQueue.

Fetches the list of available zones. The list is stored in ZoneManager.Instance.zones.

LoadNPCsCommand later calls SpawnPoints.Instance.ParseZone(NPCManager.HardCodedZoneId), so the NPC zone must be present in this list.

The array must include the NPC zone with OID { Class: 4, Type: 16, Server: 0, Number: 2937912 } (NPCManager.HardCodedZoneId). (?)

Request

No fields.

Response

FieldTypeDescription
Zones[]ZoneList of zones

InitLocation

Description

Sent during the ZoneTransitionQueue queue, after zones are loaded.

Returns the player’s home location data and the address of the SYNC server.

The Home.PlayerMaze.HomeTheme.AssetMap["Scene_Unity3D"] asset drives scene loading via LoadMazeCommand -> AssetDownloadManager.LoadMainScene().

Home.PlayerMaze.HomeTheme.AssetMap must contain a "Scene_Unity3D" entry used by LoadMazeCommand to load the main scene asset, e.g. Springtime003.unity3d (main map) or HomeLotSmall.unity3d (home lot). (?)

ZoneManager.InitLocationHomeResponseHandler() stores syncServerIP, syncServerToken, and syncServerPort in GameSettings. These are later used by SyncManager to open its session and send SyncLogin.

Request

FieldTypeDescription
LocIDOID

Response

FieldTypeDescription
ZoneInstanceZoneInstance
VillageVillage
HomePlayerHome
SyncServerTokenstringToken used to authenticate with the SYNC server
SyncServerIPstringIP address of the SYNC server
SyncServerPortint32Port of the SYNC server

SyncLogin

Description

Sent when the SYNC server opens TCP session.

The SYNC session is started by SyncManager.Instance.Start(), which is called from LoadServicesCommand.cs:21.

The sync server address and token come from the InitLocation response stored in GameSettings.

Authenticates the player on the SYNC server. The SYNC server handles real-time positional and social updates.

Request

FieldTypeDescription
UIDOID
TokenstringSync server token from the InitLocation response
MaxVisSizeint32

Response

No fields.

GetMazeItems

Description

Sent during the ZoneTransitionQueue, after the home location is initialised.

Fetches the items placed in the player’s current maze.

Request

FieldTypeDescription
PlayerMazeIDOIDRequested maze OID
PlayerIDOIDRequested player OID

Response

FieldTypeDescription
MazeItems[]PlayerItemList of player items

GetChatChannelTypes

Description

Sent during the ZoneTransitionQueue.

Fetches the available chat channel type definitions.

Request

No fields.

Response

FieldTypeDescription
ChatChannelTypes[]ChatChannelTypeList of chat channel types

GetAnnouncements

Description

Sent during the ZoneTransitionQueue.

Fetches login announcements to be displayed to the player on entry.

Request

FieldTypeDescription
UnMarkedbool

Response

FieldTypeDescription
Announcements[]AnnouncementList of announcements

EnterBuilding

Description

Sent during the ZoneTransitionQueue, after announcements are loaded.

Notifies the server that the player is entering a building.

During initial login with no active building context, this is a pass-through step. (?)

Request

FieldTypeDescription
LocIDOIDOID of the zone (?)
BuildingIDOIDOID of the building
PosPositionPlayer position
OrientationQTHPlayer orientation (quaternion)

Response

FieldTypeDescription
BuildingIDOIDOID of the building entered

GetOnlineStatuses

Description

Sent during the ZoneTransitionQueue.

Fetches the online statuses of the player’s friends. The result is stored in FriendManager.Instance.statusList.

Only sent once per session (InitFriendMangerNotificationManagerCommand.hasDone guards against repetition).

Request

No fields.

Response

FieldTypeDescription
OnlineStatuses[]OnlineStatusList of online statuses

GetPlayerNPCs

Description

Sent during the ZoneTransitionQueue, as the last major data fetch.

Fetches the NPCs for the player’s home zone.

SpawnPoints.Instance.ParseZone(NPCManager.HardCodedZoneId) is called beforehand to set up spawn points - this requires the NPC zone to have been returned by GetZones.

Request

r FieldTypeDescription
PlayerIDOIDRequested player OID
ZoneIDOIDRequested zone OID

Response

FieldTypeDescription
NPCs[]NPCList of NPCs

Object Types

This section documents game GSF object types.

Announcement

Asset

Description

Represents a single downloadable game file.

Fields

FieldTypeDescription
OIDOIDOID identifier
AssetTypeNamestringAsset classification (e.g. "Prefab_Unity3D")
CDNIDstringCDN identifier used to construct the download URL: AssetDeliveryURL + CDNID
ResNamestringResource name
GroupNamestringGroup classification (e.g. "Main_Scene", "3D Components", "Locked")
FileSizeint64File size in bytes

AssetContainer

Description

A container that groups assets by type and bundles optional asset packages.

Fields

FieldTypeDescription
OIDOIDContainer identifier
AssetMapmap[string][]AssetDictionary keyed by AssetTypeName containing a list of assets
AssetPackages[]AssetPackageList of asset packages for conditional/maze-specific asset groups

AssetPackage

Description

An AssetContainer with an additional tag used to conditionally load assets depending on which maze the player is entering.

Fields

FieldTypeDescription
OIDOIDInherited from AssetContainer
AssetMapmap[string][]AssetInherited from AssetContainer
AssetPackages[]AssetPackageInherited from AssetContainer
PTagstringTag matched against the current maze name to decide whether this package is loaded
CreateDatetime.Time

PTag matching

During LoadMazeCommand:238, the client iterates all packages from the home theme and applies this rule:

  • PTag == maze.name -> package is loaded (maze-specific assets)
  • PTag == "" (empty) -> package is always loaded (shared assets)
  • PTag is anything else -> package is skipped

This allows the server to ship assets for multiple different mazes in a single response, while the client only downloads what is relevant to the current location. (?)

ChatChannelType

ClientEnvironmentData

ItemCategory

OID

Description

A unique object GSFOID identifier usually stored as a big int64 number, that can be sliced into specific groups of bits to get the Class, Type, Server and Object number.

[Class][Type][Server][Number...]
  8b     8b     8b       40b

Fields

FieldTypeDescription
ClassbyteFor cache files is always 0
TypebyteFor cache files is always 0
ServerbyteServer version? Goes from 1 to 8 (higher = newer asset)
Numberint64Object number

Online Status

Player

PlayerAvatar

PlayerAvatarOutfit

PlayerHome

PlayerInfoTO

PlayerItem

PlayerStats

SessionStatus

SiteFrame

SiteInfo

Tier

NPC

Village

Zone

ZoneInstance

QA Tools Menu

The game contains a hidden QA tools menu that can be enabled through ServerConfig.xml.

Enabling it

Add a Version attribute to the config:

Version = '1.8'

After launching the game with this flag enabled, press F3 to open the QA tools menu.

F2 also should open a related QA layout, but it probably requires an additional UI file.

How It Works

The Version attribute is obfuscated, and is not treated as a normal version number.

The client decodes it as an encoded options flag in GameSettings.cs:748.

  1. Parse the value as a float.
  2. Multiply it by 10.
  3. Round it to an integer.
  4. If the result is divisible by 9, accept it as a valid options code.
  5. Divide it by 10 and interpret the result as a bitmask.

Bitmask Values

The decoded bitmask controls three flags:

1 -> debuggingEnabled
2 -> skipIntro
4 -> showVersion

In practice, valid values are:

1.8 -> debug enabled
2.7 -> skip intro
3.6 -> debug enabled + skip intro
4.5 -> show version
5.4 -> debug enabled + show version
6.3 -> skip intro + show version
7.2 -> debug enabled + skip intro + show version