MUD-Engine jak sama nazwa wskazuje jest silnikiem do tworzenia gier typu MUD, czyli Multi User Dungeon. Interakcja z grami tego typu odbywa się wyłącznie za pomocą komend i czytania opisów. Silnik w całości napisany jest w Javie, natomiast skryptowany jest w JavaScripcie, a definicje przedmiotów, lokacji itp sa zapisane jako JSON. Zmienne elementy gry, takie jak model gracza czy przedmioty na lokacjach, zapisywane są w bazie Postgres.
Silnik budowany jest z myślą o zachowaniu minimalnych zależności i minimalnej konfiguracji, więc do działania wymaga jedynie Javy 8 i Postgres 10.
Jest to plik szeroko opisany w dokumentacji Spring Boot. Zalecana konfiguracja to:
W tym pliku definiujemy lokalizacje główne dla wszystkich assetów (lokacje, itemy, skrypty) Więcej info patrz -> Lokalizacje plikow gry
W pliku znajduje się mapowanie komend do klas implementujących ich działanie. Tzw komendy systemowe. Więcej info patrz -> Komendy
W pliku znajdują się wszystkie komunikaty występujące w silniku Więcej info patrz -> Teksty powiadomień
Lokalizacje plikow gry domyslnie znajdują się pod:
locations
items
scripts
response
Przy czym sciezki do folderów można modyfikować przez zmianę ścieżek do nich w pliku assets.properties
, gdzie:
assets.json.path.locations
to ścieżka do folderu lokacjiassets.json.path.items
to ścieżka do folderu przedmiotówassets.json.path.scripts
to ścieżka do folderu skryptówassets.response.templates.path
to ścieżka do folderu szablonówJedyny sposób interakcji ze światem odbywa się przez komendy wywoływane przez gracza. Silnik posiada zaimplementowane podstawowe komendy jak i pozwala na implementację własnych - powiązanych z przedmiotami.
Komendy wbudowane dostępne dla wszystkich graczy:
org.grizz.game.command.parsers.system.movement.NorthMoveCommand
org.grizz.game.command.parsers.system.movement.SouthMoveCommand
org.grizz.game.command.parsers.system.movement.EastMoveCommand
org.grizz.game.command.parsers.system.movement.WestMoveCommand
org.grizz.game.command.parsers.system.movement.UpMoveCommand
org.grizz.game.command.parsers.system.movement.DownMoveCommand
org.grizz.game.command.parsers.system.LookAroundCommand
org.grizz.game.command.parsers.system.DropCommand
org.grizz.game.command.parsers.system.PickUpCommand
org.grizz.game.command.parsers.system.ShowEquipmentCommand
Komendy wbudowane dostępne dla administratorów:
org.grizz.game.command.parsers.admin.AdminTeleportCommand
org.grizz.game.command.parsers.admin.AdminGiveItemCommand
org.grizz.game.command.parsers.admin.AdminPutItemCommand
org.grizz.game.command.parsers.admin.AdminShowActivePlayerListCommand
Wbudowane komendy są zmapowane do słów pozwalających na wywołanie ich. Takie mapowanie znajduje się w pliku command-mapping.properties
. W pliku tym znajdziemy pary klucz wartośc gdzie:
(?<word>[\\D]+)
- dla danych słownych(?<amount>[\\d]+)
- dla danych liczbowych(?<playerName>[\\w-]{4,})
- dla nicków
Gdzie word
, amount
oraz playerName
to nazwy parametrów komendyKomendy wymagające podania parametrów wejściowych:
PickUpCommand
- parametry (nazwa i typ):
(?<itemName>[\\D]+)
- Nazwa przedmiotu, który chcesz podnieść i umieścić w ekwipunku(?<amount>[\\d]+)
- [Opcjonalny, wartość domyślna = 1] Liczba przedmiotów, które chcesz podnieść i umieścić w ekwipunkuDropCommand
- parametry (nazwa i typ):
(?<itemName>[\\D]+)
- Nazwa przedmiotu, który chcesz wyrzucić i umieścić na bierzącej lokacji(?<amount>[\\d]+)
- [Opcjonalny, wartość domyślna = 1] Liczba przedmiotów, które chcesz wyrzucić i umieścić na bierzącej lokacjiAdminTeleportCommand
- parametry (nazwa i typ):
(?<playerName>[\\w-]{4,})
- Nazwa gracza, którego chcesz teleportować(?<locationId>[\\w-]+)
- [Opcjonalny, wartość domyślna = obecna lokacja administratora] ID lokacji na jaką gracz ma być teleportowanyAdminGiveItemCommand
- parametry (nazwa i typ):
(?<itemName>[\\D]+)
- Nazwa przedmiotu(?<playerName>[\\w-]{4,})
- [Opcjonalny, wartość domyślna = nick administratora] Nazwa gracza, który ma otrzymać przedmiot(?<amount>[\\d]+)
- [Opcjonalny, wartość domyślna = 1] Liczba przedmiotów, którą ma otrzymać graczAdminPutItemCommand
- parametry (nazwa i typ):
(?<itemName>[\\D]+)
- Nazwa przedmiotu, który chcesz umieścić na bierzącej lokacji(?<amount>[\\d]+)
- [Opcjonalny, wartość domyślna = 1] Liczba przedmiotów, które chcesz umieścić na bierzącej lokacjiPlikiem konfiguracyjnym skryptów jest plik JSON znajdujący się w folderze domyślnym scripts
[*]:
[
{
"id": "100",
"name": "Always true script",
"path": "scripts/js/alwaysTrue.js"
}
]
Gdzie:
id
jest identyfikatorem używanym do odniesienia się do konkretnego skryptu w plikach przedmiotów, lokacji itpname
opisuje do czego służy skrypt - ma to zastosowanie czysto dokumentacyjnepath
to ścieżka do pliku javascriptW pliku pod ścieżką podaną w zmiennej path
znajduje się właściwy kod skryptu.
Skrypty odpalane są za pomocą silnika JavaScript Nashorn. Znaczy to, że można w skryptach używać wszystkiego na co silnik ten pozwala włącznie z obiektami Java. Przystepne materiały można znaleźć tutaj i tutaj
W każdym odpalonym skrypcie jest dostęp do następujących zmiennych podstawowych:
player
jest typu org.grizz.game.model. Player - pozwala na dostęp do wszystkich statystyk gracza, jego ekwipunku, parametrów, obecnej lokalizacji,response
jest typu org.grizz.game.model. PlayerResponse - udostępnia obiekt odpowiedziscriptId
jest typu java.lang. String - id uruchomionego skryptulog
jest typu org.slf4j. Logger - logger systemowy uruchomiony w kontekście klasy ScriptRunnerW przypadku skryptów odpalanych przez gracza za pomocą komendy z parametrami, parametry te są zmapowane do zmiennych w skrypcie. Przykładowo komenda uruchamiająca skrypt craftingu w kowadle zdefiniowana jako:
{
"command": "wykuj (?<itemName>[\\D]+) (?<amount>[\\d]+)",
"scriptId": "bs-anvil-crafting"
}
ma zadeklarowane 2 parametry wejściowe "itemName" i "amount", które zostaną zmapowane do zmiennych w kodzie JS. Przy czym każda zmienna będzie miała typ String, a w przypadku zmiennej "amount" należy sprawdzić jej istnienie i ewentualnie zainicjalizować ją wartością domyślną (patrz linijka 17 w anvil/crafting.js
)
Zmienne pod którymi dostępne są serwisy ułatwiające interakcję ze światem gry: Repozytoria: //TODO skonczylem tutaj
locationRepo
jest typu org.grizz.game.model.repository. LocationRepo - pozwala na pobieranie lokalizacji na podstawie IDitemRepo
jest typu org.grizz.game.model.repository. ItemRepo - pozwala na pobieranie przedmiotów na podstawie ID lub nazwyscriptRepo
jest typu org.grizz.game.model.repository. ScriptRepo - pozwala na pobieranie skryptów za pomocą IDplayerRepository
jest typu org.grizz.game.model.repository. PlayerRepository - pozwala na pobieranie graczy na podstawie nickulocationItemsRepository
jest typu org.grizz.game.model.repository. PlayerRepository - pozwala na pobieranie graczy na podstawie nickuSerwisy
adminRightsService
jest typu org.grizz.game.service. AdminRightsService - odpowiada za sprawdzenie czy obecny użytkownik ma uprawnienia administratoraequipmentService
jest typu org.grizz.game.service. EquipmentService - udostępnia operacje na ekwipunku graczalocationService
jest typu org.grizz.game.service. LocationService - udostępnia operacje na lokacjimultiplayerNotificationService
jest typu org.grizz.game.service.notifier MultiplayerNotificationService - odpowiada za komunikację miedzy graczami. Przykładowo udostępnia funkcjonalność wysyłania wiadomości na danej lokacji lub do danego graczacommandHandler
jest typu org.grizz.game.command.engine. CommandHandler - odpowiada za uruchamianie komend graczascriptRunner
jest typu org.grizz.game.service.script ScriptRunner - odpowiada za uruchamianie skryptówKonwertery
itemListToItemStackConverter
jest typu org.grizz.game.model.converters ItemListToItemStackConverter - przekształca listę przedmiotów w paczkę przedmiotów (stack)Wartość jaką zwróci skrypt jest wartością zwróconą przez ostatnią funkcję w skrypcie. Przykładową konstrukcją zwracającą zawsze wartość true jest:
function alwaysTrue() {
// here goes all the script instructions
return true;
}
alwaysTrue();
Obecnie zwracana wartość jest brana pod uwagę jedynie w przypadku skryptów beforeX na lokacjach. Skrypty są predykatami do wykonywanej lokacji i muszą zwracać wartość typu Boolean.
Pliki JSON opisujące właściwości przedmiotów znajdują się w folderze domyślnym items
[*]. Przykładowy wpis w pliku:
[
{
"id": "1",
"name": "Złota moneta",
"description": "Sporawy, złoty krążek z wizerunkiem jednego z dawno juz nie żyjących władców.",
"itemType": "MISC",
"commands": [
{
"command": "dzyn-dzyn",
"scriptId": "101"
}
]
}
]
Gdzie:
id
jest unikatowym identyfikatorem pliku. ID nie może się powtarzać na przestrzeni wszystkich plików JSON opisujących właściwości przedmiotów.name
jest to nazwa przedmiotu widoczna dla gracza. Gracz także będzie się odnosił do przedmiotu poprzez tą właśnie nazwędescription
jest to szczegółowy opis przedmiotu. Może być widoczny podczas podglądu ekwipunku lub przedmiotów na lokacjiitemType
jest to jedna z wartości [WEAPON
,ARMOR
,MISC
,STATIC
]. Dokładniejszy opis poniżejcommands
jest to mapowanie komend możliwych do wywołania na danym przedmiocie. Komenda nie może być taka sama jak jedna z wbudowanych komend, a w przypadku zduplikowania komendy na przestrzeni różnych przedmiotów i posiadanie tych dwóch różnych przedmiotów w ekwipunku nie gwarantuje wywołania komendy na własciwym przedmiocie.
command
jest to słowo/a wywołujące komendę. Możliwe jest używanie parametrów jak w przypadku zwykłego mapowania skryptów, jednak wtedy skrypt musi obsługiwać parsowanie komendy w celu pozyskania parametrów wejściowych.scriptID
jest to ID skryptuW przypadku przedmiotów innych typów niż MISC
dostępne są także dodatkowe zmienne. O tym poniżej
Jak opisano wyżej - przedmioty można oskryptować, za pomocą zmapowania skryptu w pliku konfiguracyjnym JSON. W przypadku zmapowania komendy przedmiotu do nieistniejącego skryptu - zostanie wyrzucony wyjątek podczas uruchamiania gry. Jednak jeśli zostanie zmapowanych kilka identycznych komend do różnych skryptów - nie jest gwarantowane który skrypt zostanie uruchomiony. Skrypty uruchamiane na przedmiotach nie oczekują zwrócenia żadnej wartości, także taka konstrukcja nie ma w tym przypadku zastosowania.
Istnieją obecnie 4 typy przedmiotów - [WEAPON
,ARMOR
,MISC
,STATIC
]. Niektóre typy, oprócz zmiennych podstawowych [id
,name
,description
,itemType
,commands
], posiadają także dodatkowe zmienne:
WEAPON
przedmioty opisujące broń możliwą do trzymania w rękach:
weaponType
jest to jedna z wartości określających typ broni:SWORD1H
- Miecze jednoręczneSWORD2H
- Miecze dwuręczneDAGGER
- Sztylety - broń jednoręcznaBOW
- Luki - broń dwuręczna, strzelająca na odległośćCROSSBOW
- Kusze - broń dwuręczna, strzelająca na odległośćAXE1H
- Topory jednoręczneAXE2H
- Topory dwuręczneHAMMER
- Młoty bojowe - dwuręcznePOLEARM
- Broń drzewcowa - dwuręcznaSTAFF
- Laski bojowe - dwuręczneTHROWN
- Broń rzucana - jednoręczna, zadająca obrażenia na odległośćminDamage
są to minimalne obrażeniamaxDamage
są to maksymalne obrażeniaARMOR
przedmioty opisujące elementy zbroi, możliwe do założenia na siebie:
MISC
różne przedmioty niekwalifikujące się do powyższych typów, takie jak: monety, drobiazgi, przedmioty questowe etcSTATIC
specjalny typ przedmiotów, których gracz nie może podnieść ani mieć w ekwipunku. Są to elementy interaktywne lokacji, takie jak: ołtarze, studnie, kowadła, dźwignie etc. Sens istnienia tych przedmiotów jest posiadanie zmapowanych komend