Protokol GMCP - Dokumentacja dla tworcow klientow
Protokol GMCP - Dokumentacja dla tworcow klientow
Spis tresci
- Przeglad
- Negocjacja Telnet
- Format WebSocket
- Pakiety: Char (postac)
- Pakiety: Room (pokoj)
- Pakiety: Combat (walka)
- Pakiety: Party (druzyna)
- Pakiety: Quest
- Pakiety: Client (klient)
- Kierunki i srodowiska
Przeglad
GMCP (Generic MUD Communication Protocol) umozliwia komunikacje strukturalnych danych JSON miedzy serwerem FinalMUD a klientem. Wszystkie dane sa kodowane w UTF-8, serializowane w formacie JSON z konwencja camelCase.
Serwer wysyla pakiety GMCP automatycznie w odpowiedzi na zdarzenia gry (ruch, walka, zmiana statystyk). Klient moze rowniez wysylac pakiety do serwera (zapis danych, zapytania).
Negocjacja Telnet
Kod opcji
GMCP uzywa kodu opcji Telnet 201 (0xC9).
Handshake
Przy kazdym nowym polaczeniu TCP serwer wysyla:
IAC WILL GMCP (255 251 201)
Klient odpowiada WILL GMCP lub DO GMCP, co wlacza obsluge GMCP.
Format ramki GMCP
IAC SB GMCP <nazwa_pakietu> <spacja> <dane_json> IAC SE
255 250 201 [bajty UTF-8] 32 [bajty UTF-8] 255 240
Inicjalizacja klienta
Po nawiazaniu polaczenia klient moze wyslac:
Core.Hello {"client":"NazwaKlienta","version":"1.0"}- identyfikacja klientaCore.Supports.Set ["Char 1", "Room 1", "Combat 1"]- deklaracja obslugiwanych pakietow
Format WebSocket
Polaczenia WebSocket (port 4001) nie uzywaja ramek IAC. GMCP jest automatycznie wlaczane.
Serwer wysyla:
Package.Name {"json":"data"}
Klient wysyla:
GMCP Package.Name {"json":"data"}
Kontrola echa (WebSocket): Client.Echo {"enabled":true/false}
Pakiety: Char (postac)
Char.Info
Kierunek: Serwer → Klient Kiedy: login, wejscie do pokoju
{
"name": "Aldric",
"race": "czlowiek",
"gender": "mezczyzna",
"trait1": "wojownik",
"trait2": "nieustraszony",
"age": 42,
"createdAt": "2025-03-01",
"lastSeen": "2025-06-10",
"deposit": 1500000
}
| Pole | Typ | Opis |
|---|---|---|
name |
string | Imie postaci |
race |
string | Rasa |
gender |
string | Plec: mezczyzna lub kobieta |
trait1 |
string | Pierwsza cecha |
trait2 |
string | Druga cecha |
age |
int | Wiek w dniach od stworzenia postaci |
createdAt |
string | Data stworzenia (yyyy-MM-dd) |
lastSeen |
string | Data ostatniego logowania (yyyy-MM-dd) |
deposit |
long | Stan portfela w miedzianych monetach |
Char.Vitals
Kierunek: Serwer → Klient Kiedy: login, wejscie do pokoju, zmiana HP, kazda runda walki, regeneracja
{
"hp": 150,
"maxHp": 200,
"mp": 80,
"maxMp": 100,
"stamina": 90,
"maxStamina": 100,
"fatigue": 15,
"maxFatigue": 100,
"fatiguePercent": 15,
"shield": 0,
"inCombat": true,
"combatTargetId": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"companionHp": 80,
"companionMaxHp": 120,
"companionName": "wilk"
}
| Pole | Typ | Opis |
|---|---|---|
hp |
int | Aktualne punkty zycia |
maxHp |
int | Maksymalne punkty zycia |
mp |
int | Aktualna mana |
maxMp |
int | Maksymalna mana |
stamina |
int | Aktualna wytrzymalosc |
maxStamina |
int | Maksymalna wytrzymalosc |
fatigue |
int | Aktualne zmeczenie |
maxFatigue |
int | Maksymalne zmeczenie |
fatiguePercent |
int | Zmeczenie w procentach (0-100) |
shield |
int | Wartosc tarczy magicznej |
inCombat |
bool | Czy postac walczy |
combatTargetId |
string? | GUID celu walki (format N, bez myslnikow). Pomijane gdy null |
companionHp |
int? | HP chowanca (opcjonalne, gdy gracz ma chowanca) |
companionMaxHp |
int? | Max HP chowanca (opcjonalne) |
companionName |
string? | Nazwa chowanca (opcjonalne) |
Char.Stats
Kierunek: Serwer → Klient Kiedy: login, wejscie do pokoju, zmiana statystyk
{
"str": 12, "strExp": 4500, "strExpNext": 10000,
"dex": 14, "dexExp": 8200, "dexExpNext": 10000,
"con": 10, "conExp": 1000, "conExpNext": 10000,
"int": 8, "intExp": 0, "intExpNext": 5000,
"wis": 9, "wisExp": 0, "wisExpNext": 5000,
"cha": 11, "chaExp": 0, "chaExpNext": 5000,
"attack": 45,
"defense": 30,
"armorClass": 12
}
| Pole | Typ | Opis |
|---|---|---|
str, dex, con, int, wis, cha |
int | Wartosc atrybutu |
strExp, dexExp, conExp, intExp, wisExp, chaExp |
long | Doswiadczenie atrybutu |
strExpNext, dexExpNext, conExpNext, intExpNext, wisExpNext, chaExpNext |
long | Doswiadczenie do nastepnego poziomu |
attack |
int | Wartosc ataku |
defense |
int | Wartosc obrony |
armorClass |
int | Klasa pancerza |
Char.Skills
Kierunek: Serwer → Klient Kiedy: login, wejscie do pokoju, zmiana umiejetnosci
{
"skills": {
"miecze": { "level": 5, "exp": 320, "expNext": 500, "mastery": "Uczen" },
"tarcze": { "level": 3, "exp": 100, "expNext": 250, "mastery": "Nowicjusz" }
}
}
| Pole | Typ | Opis |
|---|---|---|
skills |
object | Mapa: nazwa umiejetnosci → dane |
level |
int | Poziom umiejetnosci |
exp |
long | Aktualne doswiadczenie |
expNext |
long | Doswiadczenie do nastepnego poziomu |
mastery |
string | Tytul mistrzostwa |
Char.Effects
Kierunek: Serwer → Klient Kiedy: razem z Char.Vitals (kazdy tick game loop)
{
"effects": [
{
"name": "Trucizna",
"type": "dot",
"remainingRounds": 3,
"stacks": 2,
"maxStacks": 5,
"damagePerTick": 10
},
{
"name": "Tarcza Magiczna",
"type": "aura",
"remainingRounds": 10
}
]
}
| Pole | Typ | Opis |
|---|---|---|
name |
string | Nazwa efektu |
type |
string | Typ: dot, stun, fear, slow, armor_crush, aura, aura_heal |
remainingRounds |
int | Pozostale rundy |
stacks |
int? | Ilosc stosow (tylko DoT) |
maxStacks |
int? | Maks stosy (tylko DoT) |
damagePerTick |
int? | Obrazenia na ture (tylko DoT) |
defenseReduction |
int? | Redukcja obrony w % (tylko armor_crush) |
damageReduction |
int? | Redukcja obrazen w % (tylko slow) |
Char.SoulWeapon
Kierunek: Serwer → Klient
Kiedy: login, zdobycie exp broni duszy, komendy dusza
Gdy gracz ma bron duszy:
{
"active": true,
"weaponType": "sword",
"weaponName": "Miecz",
"customName": "Piekielnik",
"tier": 3,
"tierName": "Przebudzenie I",
"level": 45,
"exp": 1250000,
"expNext": 4500000,
"totalKills": 3421,
"isMastered": false,
"twoHanded": false,
"path": "bonus_id",
"pathName": "Nazwa sciezki",
"appearance": "ethereal",
"equipped": true
}
Gdy gracz nie ma broni duszy: { "active": false }
| Pole | Typ | Opis |
|---|---|---|
active |
bool | Czy gracz ma aktywna bron duszy |
weaponType |
string? | Typ broni (sword, axe, mace, dagger, spear, hammer, polearm, knuckles, staff) |
weaponName |
string? | Polska nazwa typu broni |
customName |
string? | Nadane imie broni (od Tier 2) |
tier |
int | Tier 1-5 |
tierName |
string? | Nazwa tieru |
level |
int | Poziom 1-100 |
exp |
long | Biezace doswiadczenie |
expNext |
long | Doswiadczenie do nastepnego poziomu |
totalKills |
long | Laczna liczba zabic |
isMastered |
bool | Czy osiagnieto mistrzostwo (Tier 5, Lvl 100) |
twoHanded |
bool | Czy tryb dwureczny |
path |
string? | ID sciezki specjalizacji (od Tier 3) |
pathName |
string? | Nazwa sciezki |
appearance |
string? | ID wygladu (od Tier 3) |
equipped |
bool | Czy bron jest dobyta |
Char.Aspects
Kierunek: Serwer → Klient Kiedy: login, zmiana aspektow
{
"activeCount": 2,
"maxActive": 3,
"expMultiplier": 100,
"effectiveLevelCap": 50,
"canChange": true,
"aspects": [
{
"type": "warrior",
"name": "Wojownik",
"category": "physical",
"level": 15,
"effectiveLevel": 15,
"exp": 45000,
"expNext": 60000,
"isActive": true,
"isMaxLevel": false
}
]
}
| Pole | Typ | Opis |
|---|---|---|
activeCount |
int | Liczba aktywnych aspektow |
maxActive |
int | Maks aktywnych aspektow |
expMultiplier |
int | Mnoznik exp w % |
effectiveLevelCap |
int | Efektywny cap poziomu |
canChange |
bool | Czy mozna zmieniac aspekty (cooldown) |
cooldownSeconds |
int? | Pozostaly cooldown w sekundach (opcjonalne) |
aspects[].type |
string | ID aspektu |
aspects[].name |
string | Nazwa aspektu |
aspects[].category |
string | Kategoria: magical lub physical |
aspects[].level |
int | Poziom aspektu |
aspects[].effectiveLevel |
int? | Efektywny poziom (gdy aktywny) |
aspects[].exp |
long? | Doswiadczenie (gdy aktywny i nie max) |
aspects[].expNext |
long? | Exp do nastepnego poziomu (gdy aktywny i nie max) |
aspects[].isActive |
bool | Czy aspekt jest aktywny |
aspects[].isMaxLevel |
bool | Czy osiagnieto max poziom |
Pakiety: Room (pokoj)
Room.Info
Kierunek: Serwer → Klient Kiedy: login, kazde wejscie do pokoju (ruch, respawn, teleport)
{
"id": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"idPrev": "b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5",
"name": "Plac Miasta",
"area": "VALDORIA_Solgard",
"environment": "ROOM_IN_CITY",
"services": ["ROOM_SERVICE_SHOP", "ROOM_SERVICE_BANK"],
"exits": {
"polnoc": "c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6",
"wschod": "d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1"
},
"previousCommand": "poludnie"
}
| Pole | Typ | Opis |
|---|---|---|
id |
string | ID pokoju (hash MD5, 32 znaki hex) |
idPrev |
string? | ID poprzedniego pokoju (pomijane przy loginie/teleporcie) |
name |
string | Nazwa pokoju |
area |
string | Nazwa strefy |
environment |
string | Typ srodowiska (patrz tabela ponizej) |
services |
string[] | Lista uslug dostepnych w pokoju |
exits |
object | Mapa: kierunek polski → ID pokoju docelowego |
previousCommand |
string? | Komenda kierunku ktora doprowadzila tu gracza (pomijane przy loginie/teleporcie) |
Room.Players
Kierunek: Serwer → Klient Kiedy: wejscie do pokoju
Lista graczy w pokoju oprocz odbiorcy.
{
"players": [
{ "id": "a1b2c3...", "name": "Aldric" },
{ "id": "b2c3d4...", "name": "Zyra" }
]
}
Room.NPCs
Kierunek: Serwer → Klient Kiedy: wejscie do pokoju, zmiana stanu NPC (obrazenia, smierc, respawn)
Zawiera tylko zywych NPC (hp > 0).
{
"npcs": [
{
"id": "c3d4e5...",
"name": "straznik",
"nameDisplay": "silny straznik",
"hostile": true,
"inCombat": false,
"hp": 120,
"maxHp": 150,
"isSummon": false,
"isMine": false,
"isBoss": false,
"isCompanion": false
}
]
}
| Pole | Typ | Opis |
|---|---|---|
id |
string | GUID NPC |
name |
string | Wewnetrzna nazwa obiektu |
nameDisplay |
string | Nazwa wyswietlana (mianownik z przymiotnikami) |
hostile |
bool | Czy wrogi |
inCombat |
bool | Czy w walce |
hp |
int | Aktualne HP |
maxHp |
int | Maksymalne HP |
isSummon |
bool | Czy to przywolany stwor |
isMine |
bool | Czy to przywolany stwor gracza-odbiorcy |
isBoss |
bool | Czy to boss |
ownerName |
string? | Imie wlasciciela przywolanca (opcjonalne) |
isCompanion |
bool | Czy to chowaniec |
companionType |
string? | Typ chowanca (opcjonalne) |
Room.Items
Kierunek: Serwer → Klient Kiedy: wejscie do pokoju
Zawiera tylko rzeczywiste przedmioty na ziemi (nie elementy scenografii).
{
"items": [
{
"id": "d4e5f6...",
"name": "miecz",
"nameDisplay": "zelazny miecz"
}
]
}
Pakiety: Combat (walka)
Combat.Start
Kierunek: Serwer → Klient Kiedy: rozpoczecie walki
{
"target": {
"id": "c3d4e5...",
"name": "straznik",
"hp": 120,
"maxHp": 150
}
}
Combat.End
Kierunek: Serwer → Klient Kiedy: zakonczenie walki
{
"reason": "victory",
"target": "straznik"
}
Wartosc reason |
Opis |
|---|---|
victory |
Zwyciestwo |
flee |
Ucieczka |
targetDied |
Cel zginal |
playerDied |
Gracz zginal |
Combat.Rounds
Kierunek: Serwer → Klient Kiedy: batch rund walki per tick game loop
Glowny pakiet walki. Tablica obiektow rund:
[
{
"attacker": "Aldric",
"defender": "straznik",
"damage": 35,
"result": "hit",
"damageType": "melee",
"defenderHp": 85,
"defenderMaxHp": 150,
"roundId": 12345
},
{
"attacker": "straznik",
"defender": "Aldric",
"damage": 0,
"result": "dodge",
"damageType": "melee",
"defenderHp": 150,
"defenderMaxHp": 200,
"roundId": 12345
}
]
| Pole | Typ | Opis |
|---|---|---|
attacker |
string | Nazwa atakujacego |
defender |
string | Nazwa broniacego sie |
damage |
int | Zadane obrazenia |
heal |
int? | Wartosc leczenia (opcjonalne, dla akcji leczenia) |
result |
string | Wynik ataku (patrz tabela) |
damageType |
string | Typ obrazen (patrz tabela) |
spellName |
string? | Nazwa zaklecia (opcjonalne) |
defenderHp |
int | HP broniacego po ataku |
defenderMaxHp |
int | Max HP broniacego |
roundId |
long | Globalny numer rundy |
sourceEffect |
string? | Efekt zrodlowy (np. "Trucizna", "Tarcza Magiczna") |
interceptor |
string? | Nazwa stworzenia ktore przechwycilo cios |
Wartosci result:
| Wartosc | Opis |
|---|---|
hit |
Trafienie |
miss |
Pudlo |
dodge |
Unik |
block |
Blok tarcza |
parry |
Parowanie |
heal |
Leczenie |
dot_tick |
Tick obrazen periodycznych |
absorb |
Calkowita absorpcja (tarcza) |
partial_absorb |
Czesciowa absorpcja |
intercept |
Przechwycenie ciosu |
reflect |
Odbicie obrazen |
Wartosci damageType:
| Wartosc | Opis |
|---|---|
melee |
Atak wrecz |
magic |
Obrazenia magiczne |
skill |
Obrazenia z umiejetnosci |
heal |
Leczenie |
poison |
Trucizna |
holy |
Obrazenia swiete |
aura |
Obrazenia z aury |
aura_heal |
Leczenie z aury |
life_drain |
Kradziez zycia |
reflect |
Odbite obrazenia |
Combat.Round (starszy format)
Pojedyncza runda - rzadko uzywany, zastapiony przez Combat.Rounds.
{
"attacker": "Aldric",
"defender": "straznik",
"damage": 35,
"result": "hit",
"defenderHp": 85,
"defenderMaxHp": 150
}
Combat.SkillGain
Kierunek: Serwer → Klient Kiedy: zdobycie exp umiejetnosci lub awans
{
"skill": "miecze",
"exp": 15,
"newLevel": 6,
"mastery": "Adept"
}
| Pole | Typ | Opis |
|---|---|---|
skill |
string | Nazwa umiejetnosci |
exp |
int | Zdobyte doswiadczenie |
newLevel |
int? | Nowy poziom (pomijane gdy brak awansu) |
mastery |
string? | Nowy tytul mistrzostwa (pomijane gdy brak awansu) |
Combat.TargetEffects
Kierunek: Serwer → Klient Kiedy: kazdy tick gdy gracz jest w walce
Efekty nalozoone na cel walki gracza.
{
"targetId": "c3d4e5...",
"effects": [
{
"name": "Trucizna",
"type": "dot",
"remainingRounds": 3,
"stacks": 2,
"maxStacks": 5,
"damagePerTick": 10
}
]
}
Format efektow identyczny jak w Char.Effects.
Pakiety: Party (druzyna)
Party.Vitals
Kierunek: Serwer → Klient Kiedy: zmiana vitali czlonka druzyny, dolaczenie/opuszczenie druzyny
Wysylane tylko do czlonkow druzyny w tym samym pokoju.
{
"members": [
{
"id": "a1b2c3...",
"name": "Aldric",
"hp": 150,
"maxHp": 200,
"mp": 80,
"maxMp": 100,
"stamina": 90,
"maxStamina": 100,
"inCombat": true,
"guarding": ["Zyra"],
"guardedBy": []
}
]
}
| Pole | Typ | Opis |
|---|---|---|
id |
string | GUID gracza |
name |
string | Imie gracza |
hp, maxHp |
int | Punkty zycia |
mp, maxMp |
int | Mana |
stamina, maxStamina |
int | Wytrzymalosc |
inCombat |
bool | Czy w walce |
guarding |
string[] | Lista chronionych graczy |
guardedBy |
string[] | Lista chronionych przez |
Pakiety: Quest
Quest.RepeatableList
Kierunek: Klient → Serwer (zadanie), Serwer → Klient (odpowiedz) Rate limit: 1 zapytanie na 60 sekund per IP
Zadanie (puste cialo):
GMCP Quest.RepeatableList
Odpowiedz:
{
"quests": [
{
"id": "daily_hunt_wolves",
"name": "Polowanie na wilki",
"completionCount": 3,
"ready": true
},
{
"id": "weekly_dungeon",
"name": "Dungeon tygodniowy",
"completionCount": 1,
"ready": false,
"remainingSeconds": 3600,
"resetAtUtc": "2025-06-11T00:00:00Z"
}
]
}
| Pole | Typ | Opis |
|---|---|---|
id |
string | ID questa |
name |
string | Nazwa questa |
completionCount |
int | Ile razy ukonczono |
ready |
bool | Czy quest jest dostepny |
remainingSeconds |
int? | Sekundy do odnowienia (gdy niedostepny) |
resetAtUtc |
string? | Data odnowienia ISO 8601 (gdy niedostepny) |
Pakiety: Client (klient)
Client.GUI
Kierunek: Serwer → Klient Kiedy: wejscie do pokoju (gdy skonfigurowany MudletPackageUrl)
{
"version": "1.0",
"url": "https://finalmud.org/FinalMUD.mpackage"
}
Client.Data.Load
Kierunek: Klient → Serwer (zadanie bez ciala), Serwer → Klient (odpowiedz)
Odpowiedz:
{
"mapData": "{ ...dane mapy... }",
"scriptingData": "{ ...dane skryptow... }",
"layoutData": "{ ...dane layoutu... }",
"mapSize": 12345,
"scriptingSize": 4567,
"layoutSize": 890,
"totalSize": 17802,
"maxSize": 524288,
"version": 3,
"officialScripts": "{ ...oficjalne skrypty... }",
"officialScriptsVersion": 1
}
Client.Data.SaveMap / SaveScripting / SaveLayout
Kierunek: Klient → Serwer (zadanie), Serwer → Klient (odpowiedz)
Zadanie:
{ "data": "{ ...serializowane dane... }" }
Odpowiedz:
{
"success": true,
"error": null,
"mapSize": 12345,
"scriptingSize": 4567,
"totalSize": 17802,
"maxSize": 524288
}
Client.Data.Reset
Kierunek: Klient → Serwer
{ "type": "all" }
Wartosci type: map, scripting, all
Client.Data.Info
Kierunek: Klient → Serwer (zadanie bez ciala), Serwer → Klient (odpowiedz)
{
"mapSize": 12345,
"scriptingSize": 4567,
"totalSize": 16912,
"maxSize": 524288,
"maxMapSize": 262144,
"maxScriptingSize": 262144,
"mapUpdatedAt": "2025-06-10T14:30:00Z",
"scriptingUpdatedAt": "2025-06-09T10:00:00Z"
}
Client.Data.SaveNow
Kierunek: Serwer → Klient Kiedy: przed rozlaczeniem gracza (shutdown, kick)
Puste cialo: {}
Klient powinien natychmiast wyslac SaveMap, SaveScripting i SaveLayout.
Kierunki i srodowiska
Kierunki w wyjsciach (exits)
| Kierunek polski | Alias angielski | Offset (x, y, z) |
|---|---|---|
polnoc |
north/n | (0, +2, 0) |
polnocny-wschod |
northeast/ne | (+2, +2, 0) |
polnocny-zachod |
northwest/nw | (-2, +2, 0) |
wschod |
east/e | (+2, 0, 0) |
zachod |
west/w | (-2, 0, 0) |
poludnie |
south/s | (0, -2, 0) |
poludniowy-wschod |
southeast/se | (+2, -2, 0) |
poludniowy-zachod |
southwest/sw | (-2, -2, 0) |
gora |
up/u | (0, 0, +2) |
dol |
down/d | (0, 0, -2) |
Wyjscia o niestandardowych nazwach (np. "wejscie", "drzwi") nie maja zdefiniowanego offsetu.
Srodowiska pokoi (environment)
| Wartosc | ID | Opis |
|---|---|---|
ROOM_NORMAL |
0 | Domyslny |
ROOM_IN_WATER |
1 | Plytka woda |
ROOM_UNDER_WATER |
2 | Pod woda |
ROOM_IN_AIR |
3 | W powietrzu |
ROOM_BEACH |
4 | Plaza |
ROOM_IN_LOW_MOUNTAINS |
5 | Niskie gory |
ROOM_IN_HIGH_MOUNTAINS |
6 | Wysokie gory |
ROOM_IN_HILLS |
7 | Wzgorza |
ROOM_IN_FOREST |
8 | Las |
ROOM_IN_PLAIN |
9 | Rownina |
ROOM_IN_CAVE |
10 | Jaskinia |
ROOM_IN_SWAMP |
11 | Bagno |
ROOM_IN_ROAD |
12 | Droga |
ROOM_IN_CITY |
13 | Miasto |
ROOM_IN_VILLAGE |
14 | Wioska |
ROOM_UNVISITED |
15 | Nieodwiedzony |
ROOM_INSIDE |
16 | Wnetrze budynku |
ROOM_TEMPLE |
17 | Swiatynia |
Uslugi pokoi (services)
| Wartosc | ID | Opis |
|---|---|---|
ROOM_SERVICE_POSTOFFICE |
1 | Poczta |
ROOM_SERVICE_SMITH |
2 | Kowal |
ROOM_SERVICE_SHOP |
3 | Sklep |
ROOM_SERVICE_BANK |
4 | Bank |
ROOM_SERVICE_MESSAGEBOARD |
5 | Tablica ogloszen |
ROOM_SERVICE_WATER |
6 | Zrodlo wody |
ROOM_SERVICE_PUB |
7 | Karczma |
ROOM_SERVICE_BARBER |
8 | Fryzjer |
Sekwencja GMCP przy logowaniu
Serwer wysyla nastepujace pakiety w kolejnosci po zalogowaniu gracza:
Char.InfoChar.StatsChar.SkillsChar.SoulWeaponChar.AspectsRoom.Info(bezidPrevipreviousCommand)Room.NPCsRoom.PlayersRoom.ItemsChar.VitalsChar.Effects
Uwagi implementacyjne
- JSON: camelCase, brak wciecia, kodowanie UTF-8
- GUID format: format "N" (bez myslnikow, 32 znaki hex) dla ID pokoi i celow walki
- Opcjonalne pola: pola oznaczone jako
?sa pomijane w JSON gdy maja wartosc null - Personalizacja: Combat.Rounds sa personalizowane per obserwator - nazwy atakujacych/broniacych sie sa rozwiazywane na podstawie systemu met/nomet (rozpoznawanie graczy)
- Batching: Combat.Rounds i Room.NPCs sa grupowane per tick game loop dla wydajnosci
- Telnet port: 4000 (z ramkami IAC)
- WebSocket port: 4001 (bez ramek IAC)