FinalMUDWiki

Protokol GMCP - Dokumentacja dla tworcow klientow

Techniczne 14.03.2026 13:23 16 wyświetleń Edytor: [email protected]

Protokol GMCP - Dokumentacja dla tworcow klientow

Spis tresci

  1. Przeglad
  2. Negocjacja Telnet
  3. Format WebSocket
  4. Pakiety: Char (postac)
  5. Pakiety: Room (pokoj)
  6. Pakiety: Combat (walka)
  7. Pakiety: Party (druzyna)
  8. Pakiety: Quest
  9. Pakiety: Client (klient)
  10. 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 klienta
  • Core.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:

  1. Char.Info
  2. Char.Stats
  3. Char.Skills
  4. Char.SoulWeapon
  5. Char.Aspects
  6. Room.Info (bez idPrev i previousCommand)
  7. Room.NPCs
  8. Room.Players
  9. Room.Items
  10. Char.Vitals
  11. Char.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)