IRCmud

Kommentare anzeigen Worklog abonnieren

Worklogs IRCmud

IRCmud ist tot!

Donnerstag, 25. März 2010 von hamZta
Eines vergangenen Abends, ich war gerade dabei an IRCmud weiterzuentwickeln und zu testen, stürzte der Server mit der undankbaren Meldung "EXCEPTION_ACCESS_VIOLATION" ab. Zum geschätzten 20sten Mal an besagtem Tag und ich war kurz davor BlitzMax gegen jede Wand meiner Wohnung zu werfen. Obendrein funktionierte das Datenbankmodul wieder mal nicht richtig, das machte die Sache nicht besser. Ich kam zu dem Schluss, dass BlitzMax für das was ich vorhatte einfach nicht geeignet ist.

Allerdings hatte sich schon vorher eine Idee in meinen Kopf eingenistet und nutzte die Gunst der Stunde: Ich hatte vor, IRCmud in C++ komplett neu zu schreiben und fortan mit dieser Sprache weiterzuentwickeln.
Gesagt, getan. Nicht ganz so flott, aber doch relativ schnell hatte ich mit der Portierung begonnen, fast 80% des Codes musste ich schreiben ohne ihn richtig testen zu können. Heute kann ich sagen: Es lebe IRCmud!

Die Neuentwicklung hat nun fast den letzten Stand der BlitzMax-Version erreicht, ist allerdings flotter und leidet nicht an den Kinderkrankheiten die BlitzMax so mit sich bringt.

Mit dem Umstieg auf C++ bedeutet das aber auch das Ende für das Worklog hier, Regeln sind nunmal Regeln Wink Wer trotzdem immer noch daran interessiert ist und vielleicht sogar bei der Entwicklung mithelfen will der soll sich ins neue Forum begeben: http://forum.ircmud.dreamfall.at

Vielen Dank für die Aufmerksamkeit, ich hoffe, es finden sich noch ein paar Interessenten unter euch! Smile

Grüße,
hamZta

Datenbanken...

Montag, 1. März 2010 von hamZta
... bringen mich irgendwann ins Grab. Bis eben lief noch alles wunderbar, nur plötzlich fiel mir auf, dass das Datenbankmodul von Brucey (BaH.DBMySQL) Prepared Statements nur noch einmal ausführt ... und danach stillschweigend dabei versagt. Das führte dazu dass sich nur ein Client einloggen konnte, die nachfolgenden hatte keine Attribute, keine Skills ... gar nichts mehr. Zur Info: Prepared Statements sind SQL-Ausdrücke die der Datenbankserver nur einmal auswerten muss, man sie aber beliebig oft aufrufen kann (/können sollte. *hust*), was vor allem Geschwindigkeitsvorteile hat.

Ich hatte ja schonmal Probleme mit dem Modul, anno dazumals funktionierten bei mir lokal keine Prepared Statements, nur normale, auf dem vServer von Smily genau umgekehrt, da klappten nur Prepared Statements.

Ich denke ich werde Bruceys Modul mal komplett zerlegen und schauen wo es da hakt. Oder mir selbst ein Modul dafür schreiben, aber das kostet viel, viel, viel Zeit.

Ansonsten habe ich heute ein kleines Framework zum Testen geschrieben, damit kann man recht simpel kleine Bots schreiben die sich automatisch einloggen und dann beliebige Aktionen durchführen, zB:
BlitzMax: [AUSKLAPPEN]

Type TTest01 Extends TTestClient

Field _firstRound:Byte
Field _userName:String

Method onPrivMsg(msg:TMessage)
Print msg.getParam(0)
End Method

Method onLoggedIn()
SetSlot(1, "Hit")
SetSlot(2, "Cut")
SetSlot(3, "Heal")
End Method

Method onRegistered()
Login(_username, _username)
End Method

Method onArrive()
SetUpTimer(Rand(1000, 10000))
For Local c:String = EachIn _clients
If c.StartsWith("+Wolf") Or c.StartsWith("+Fox") Or c.StartsWith("+Bear") Or c.StartsWith("+Boar") Or c.StartsWith("+Bat")
Attack(c)
_firstRound = True
Exit
End If
Next

If Rand(0, 100) < 20 Then
SendPrivMsg("*laber* *laber* Ich bin nur ein Bot, bitte beachte mich gar nicht!")
End If
End Method

Method onTimer()
If _attackState = 0
Local next_dir:Int = Rand(0, _directions.Length-1)
Move(_directions[next_dir])
End If
SetUpTimer(Rand(500, 1000))
End Method

Method onBattleTurn()
If _hp < 800 Then
Cast(3, _nick)
Else
If _firstRound
Cast(2)
_firstRound = False
Else
Cast(1)
End If
End If
End Method

Method onBattleWin()
Print "Battle won!"
End Method

Method onBattleLose()
Print "Battle lost!"
End Method

End Type


Dieser Bot wandert zufällig von Raum zu Raum. Findet er in einem Raum einen Wolf, Fuchs, Bär, Eber oder eine Fledermaus so greift er diese an. Die Kampf-"KI" heilt sich dabei selbst und haut anschließend eigentlich nur noch drauf.
Zum Testen ist das äußerst praktisch, weil man alleine schwer die Bedingungen herstellen kann die herrschen wenn mehrere Clients verbunden sind und Aktionen durchführen. Ich starte also einfach die Testanwendung ein paar Mal und schon wuseln einige Helferleins herum und töten alles was ihnen vor's Schwert kommt. Niedlich. Und praktisch.

Des weiteren konnte ich damit ein paar Bugs beheben, unter anderem ...

  • ... wird man bei !logout nichtmehr vom Server gekickt
  • ... setzt !logout den Clienten jetzt korrekt zurück (vorher blieben Skills erhalten)
  • ... werden getötete NPCs jetzt auch wirklich gelöscht
  • ... wurde eine Schwachstelle im Message-Parsing gefixt wodurch der Server nichtmehr so leicht gecrasht werden kann
  • ... wurde einem Spieler bei Nickwechsel zweimal die NICK-Nachricht gesandt
  • ... kann man Fledermäuse und Eber jetzt auch wirklich angreifen Wink


Ich hoffe, dass ich den Datenbankmist bald hinter mir habe, dann kann ich mich wieder voll auf die Entwicklung stürzen.

Würde mich über Feedback natürlich absolut freuen! *wink* *wink*

hamZta

Einleitung

Samstag, 27. Februar 2010 von hamZta
IRCmud - Worklog

Jetzt fange ich doch auch mit einem Worklog an, vielleicht interessierts ja den einen oder anderen was ich mir so beim Basteln denke.

Ich fange am Besten mal damit an, wie der Server bis jetzt so funktioniert.

Server
Im Hintergrund werkelt ein kleiner IRC-Server, programmiert mit BlitzMax, für die Netzwerkkommunikation wird BNetEx verwendet.
Dieser Server stellt das Grundgerüst dar, d.h. er kümmert sich um die Abwicklung des im IRC-RFC spezifizierten Standards.
Er empfängt Nachrichten von Clients und sendet entsprechende Antworten o.ä. zurück. Zum Beispiel schickt er regelmäßig PINGs und trennt dadurch Clients die die Verbindung verloren haben vom Server. Außerdem sorgt er dafür, dass normale Nachrichten an Clients oder Channels wie gewohnt verschickt und empfangen werden.

Persistente Spielerdaten wie Namen, Passwörter, erlernte Skills etc. werden in einer MySQL-Datenbank gespeichert bzw. aus dieser beim Start geladen. Während des Spielablaufs wird die Datenbank nicht mehr benötigt, unter anderem aus Geschwindigkeitsgründen. D.h. der Server lädt sich alle Daten die er braucht in den RAM und arbeitet dann dort damit. Lediglich wenn sich neue Spieler einloggen wird aus der Datenbank nachgeladen.

Muss der Server Spielerdaten speichern passiert dies ebenfalls nicht in der Datenbank - dafür ist ein anderer Prozess zuständig. Gespeichert werden die Daten in einer Datei in ein spezielles Verzeichnis - jeder Spieler erhält so eine Speicherdatei, benannt nach einer eindeutigen ID je Client.

Im Hintergrund läuft ein anderer Prozess (liebevoll Saveslave genannt), dieser schaut in regelmäßigen Abständen ob sich derartige Dateien im Ordner befinden, liest diese aus, speichert die Daten in die Datenbank und löscht anschließend die Datei.

Dieser "Umweg" hat mehrere Vorteile: Zum einen wird der Server nicht durch Datenbankoperationen ausgebremst. Weiters kann durch diesen Weg sichergestellt werden, dass Spielerdaten auch gesichert werden wenn die Datenbank offline sein sollte - loggt sich ein Spieler ein für den noch eine Speicherdatei existiert wird von dieser anstatt von der Datenbank geladen.

Inhalt
Um vom leeren Grundgerüst zu einer lebendigen Welt zu kommen fehlt allerdings noch der Inhalt. Ohne diesen wäre der Server kaum mehr (eher etwas weniger) als ein normaler IRC-Server, ohne jegliche Channel- oder Usermodes. Normales Chatten wäre allerdings möglich.
Für den Inhalt wird die Scriptsprache Lua verwendet. Sie ist schnell, klein, einfach zu programmieren und noch einfacher aus BlitzMax heraus zu verwenden.
Der Server stellt dafür über 60 Funktionen bereit, mit denen sich allerlei Dinge anstellen lassen. In Lua sind zum Beispiel sämtliche Räume, Fertigkeiten und NPCs und deren Verhalten definiert - das reicht von einfachen, leeren Räumen über komplizierte Zaubersprüche bis hin zu aufwändigen Bossgegnern. Um einen guten Kompromiss aus Performance und Flexibilität zu gewährleisten basiert das Ganze mehr oder weniger auf einem Event-System. Jedes Objekt (Räume, NPCs und Fertigkeiten sind Objekte) definiert verschiedenste Events die vom Server dann aufgerufen werden. Betritt zum Beispiel ein Spieler einen Raum so wird das Event onJoin() des Raumes aufgerufen - aber auch das aller NPCs, damit diese darauf reagieren können.

Über Charaktere (also Spieler und NPCs) weiß der Server so wenig wie nur möglich - er kennt ihr Level, ihre Erfahrung und ihre Lebenspunkte, mehr allerdings nicht. Zum Beispiel Elemente, Lernpunkte oder Gold, so wie sie im aktuellen Spiel zu finden sind sind rein in Lua implementiert. Es ist also zum Beispiel möglich Spiele die ohne Währung auskommen zu entwickeln, zusätzliche Attribute einzuführen oder NPCs in Fraktionsgruppen zu unterteilen - der Fantasie sind nahezu keine Grenzen gesetzt.
Um derlei Daten ebenfalls persistent speichern zu können, ohne genau zu wissen worum es sich handelt hat jeder Client (Spieler und NPCs) einen Datenbereich mit 50 Feldern zur Verfügung. Dieser Datenbereich wird in der Datenbank gespeichert und kann beliebig beschrieben werden.

Bis jetzt besteht der Server samt Inhalt (also Luascripts) aus rund 6200 Zeilen reinem Code.

Beispiele
Der momentan aufwändigste NPC ist ein "Firegolem", mit 70 Zeilen Code. Fällt sein Leben im Kampf unter 90% beschwört er einen Diener der für ihn kämpft. Stirbt dieser Diener, steigt der Golem ein paar Stufen auf und wird dadurch stärker. Dasselbe tritt bei 50% nochmal auf.

Ein "Darkwolf" sucht im Kampf den Raum ab und ruft einen anderen Darkwolf zu Hilfe - sofern gerade einer verfügbar ist. Dieser tritt dem Kampf bei und attackiert den Spieler.

Aussicht
Neben dem Spiel soll auch eine Website dafür entwickelt werden, wo spieler sich einloggen und ihre Charaktere untersuchen können. Gezeigt werden dabei Lebenspunkte, Erfahrung, Skills, etc. Außerdem soll man über die Website Nachrichten an eingeloggte Spieler auf dem Server verschicken und empfangen können.

Ganz wichtig ist, dass das System durchgetestet wird. Deshalb wird es in den nächsten Tagen (hoffentlich) ein paar Tests geben, die dazu führen werden, dass ich das Spiel durchgehend auf einem Server (danke an Smily an dieser Stelle) laufen lassen kann um soviele Daten wie möglich zu sammeln. Eventuell werde ich dafür auch ein Testframework schreiben, um automatisierte Tests durchzuführen. Da der Server momentan noch in einem Thread läuft würde ich gerne die Netzwerkperformance unter Last testen.

Teilweise ausgearbeitet sind momentan Konzepte für Gegenstände, ein Postsystem, Handel unter Spielern & Verkauf an NPCs, Quests, Crafting (Herstellen von Gegenständen durch Spieler) und Duelle. Das Hauptproblem bei den meisten genannten Punkten ist es, die Inhalte durch das sehr eingeschränkte User-Interface verständlich und einfach an den Spieler zu bringen.

Damit hier nicht nur Text steht, hier ein frühes Bild einer Karte für das Spiel:
user posted image

So. Wer's bis hierher geschafft hat: Gratulation und vielen Dank für's Lesen. Für Vorschläge, Ideen und Anregungen bin ich natürlich immer offen, einfach einen Kommentar oder eine PN schreiben!

Grüße,
hamZta