da sich, wie ich sehe, immer mehr Leute dafür begeistern mit Clienten bzw. mit Python zu arbeiten habe ich mich dazu entschlossen eine kleine Einführung in die Geschichte von Metin2 und Python zu schreiben. Wir wollen auch nicht lange um das Thema herum reden und fangen direkt an, jedoch noch an dieser Stelle, ich bin kein "Profi" oder sonstiges ich lerne selbst noch und deshalb sind alle Angaben ohne Gewähr auf Richtigkeit! <--- Was nen Wort
Benötigtes:
Fangen wir erstmal mit ein paar Grundlagen an, die ihr für Pythondateien in Metin benötigt:Quote:
- Notepad ++
- Python 2.2 - Nicht umbedingt nötig, wird jedoch empfohlen
- Geduld
- Einen Metin2 Clienten den ihr entpacken und packen könnt
- Mt2PythonLoader von Musicinstructor
Jede Pythondatei in Metin (ausgenommen der, die für die grafische Positionierung verantwortlich ist) fangen in dem, wie ich ihn nenne, "Leerkopf" mit den Imports an. Imports sind mit die wichtigsten Instanzen in einer eigenständigen Pythondatei denn diese importieren, wer hätte das gedacht, bereits vorgegebende Bibiliotheken. Diese werden benötigt, damit ihr bestimmte Befehle verwenden könnt. So wird für den Befehl "net.SendChatPacket()" die Bibiliothek "net" benötigt. Allerdings fragen sich manche bestimmt wie importiere ich eine solche Bibiliothek und woher weiß ich welche für welchen Befehl benötigt wird? Zum Thema, welche Bibiliothek welche Befehle ermöglicht wird später eine Liste folgen. Nun zeige ich euch jedoch kurz mit 5 Bibiliotheken wie man eine Bibiliothek einbindet:
Das ist doch ganz einfach, oder? Jedoch ist es an dieser Stelle wichtig, dass ihr wisst, dass die ui in 90% aller Scripts importet wird, da sie eine weitere Grundlage für viele Befehle und Aktionen ist.
Weiter geht es dann in einer Datei mit den Klassen. Die Klassen definieren einen Gültigkeitsbereich für Variabeln und Funktionen. Ich belasse es an dieser Stelle jedoch vorerst dabei, da das nicht ganz richtig ist, ich aber nicht vorgreifen möchte! Eine Klasse ist meist in einer Datei nur 1-2 Mal vertreten und wird so defniert, wie im folgenden Zeilenbeispiel demonstriert wird.
Sie steht direkt unter den Imports.
Das sollte auch nicht weiter schwer sein zu verstehen, jedoch müsste man nun kurz erklären, was in den Klammern steht, jedoch belassen wir es auch hier dabei, dass dort eine andere Class in der ui aufgrufen wird und ihr hier
seht, dass die UI schon benutzt wird. Ich entschuldige mich dafür, aber an dieser Stelle reicht das Wissen darüber, dass dafür das ScriptWindow gebraucht wird vollkommen. Ich werde in späteren Ausführungen, in denen diese Bereiche eine wirklich wichtige Rolle spielen noch genauer darauf eingehen.
Nun kommen die Standartfunktionen, die in jeder Datei vorhanden sein müssen - wobei nicht alle von Bedeutung sind, ich diese aber aus Gewohnheit mittlerweile mit einbaue - und wir in unserem Fall in der Class das "ScriptWindow" benutzten. Diese wären jetzt:
Hierbei ist im Grunde nur zu bemerken, dass die __init__ Funktion der erste Einstiegspunkt von der Class ist, wenn diese aufgerufen wird. Mithilfe der __del__ wird ermöglich, die Class bzw. das Fenster zu "zerstören" bzw. zu beenden. Die Destory jedoch ist nicht, wie ihr Name sagt, zum zerstören da, sondern sie "versteckt" jediglich das, was hier aufgerufen wurde. Somit läuft es theoretisch im Hintergrund mit. Die Show jedoch macht genau das wozu ihr Name da ist, sie zeigt uns den Ablauf bzw den Aufruf an, welchen wir anwählen. Somit haben wir nun die Grundlagen für eine neue Pythondatei gelegt. Ich gebe euch jetzt noch ein fertiges Leerscript vor, welches keine Funktionen besitzt, aber von euch später erweitert werden soll.
Um jedoch die Grundlagen zu vervollständigen gebe ich jetzt noch ein Beispiel wie eine Variable definiert wird und wie man einen Funktionskopf erstellt. Beginnen wir mit der Variable: Diese wird mit ihrem Namen, einem Gleichheitszeichen und dem nachstehenden Wert definiert sprich:
Das ganze könnte man jetzt mit einem Beispiel in der Python (Commandline) veranschaulichen. Dazu müsstet ihr einfach die oben stehenden Variabeln abtippen und dann den Variabelnamen absenden, dann seht ihr, dass diese ihre nachstehenden Werte angenommen haben. Wichtig zu wissen ist, dass man eine Variable anders wie in manch anderer Sprache keinem Datentyp zuweisen muss, denn das übernimmt das System von alleine!
Eine Funktion beginnt immer mit einem Funktionskopf. Dieser wird DEFiniert mit deinem NAMEN und den Werten in den () und wird dann mit einem Doppelpunkt beendet. Das sähe dann so aus:
Wie ihr hier seht, besitzt die Funktion Test einen Attribut "self". Dieser wird immer angegeben, da das darauf verweißt, dass dieser Funktionskopf seinen "Körper" ausführt, sprich den Code den die Funktion an sich enthält. Jedoch kann eine Funktion auch Werte mitgeliefert bekommen, welche ihr dann in ihr weiter verarbeiten könnt. Das würde dann so aussehen:
In diesem Beispiel könnte man nun einen Wert errechnen. Dazu mache ich auch noch ein Beispiel, jetzt allerdings zeige ich euch zuerst wie dieser ihr den Wert weitergebt, was so geht:
Hier werden nun die Zahlen 19 und 1 übergeben, diese werden dann in unserer Testfuntkion addiert und das Ergebnis wird mit dem Befehl return zurück gegeben. Dieses Beispiel muss nicht zu 100% an dieser Stelle verstanden werden, jedoch sollte man wissen, wie man einen Wert einer Funktion übergibt und wie dafür der Funtkionskopf heißen muss!
PHP Code:
import ui
import app
import net
import chat
import player
Weiter geht es dann in einer Datei mit den Klassen. Die Klassen definieren einen Gültigkeitsbereich für Variabeln und Funktionen. Ich belasse es an dieser Stelle jedoch vorerst dabei, da das nicht ganz richtig ist, ich aber nicht vorgreifen möchte! Eine Klasse ist meist in einer Datei nur 1-2 Mal vertreten und wird so defniert, wie im folgenden Zeilenbeispiel demonstriert wird.
Sie steht direkt unter den Imports.
PHP Code:
class NAME(ui.ScriptWindow):
seht, dass die UI schon benutzt wird. Ich entschuldige mich dafür, aber an dieser Stelle reicht das Wissen darüber, dass dafür das ScriptWindow gebraucht wird vollkommen. Ich werde in späteren Ausführungen, in denen diese Bereiche eine wirklich wichtige Rolle spielen noch genauer darauf eingehen.
Nun kommen die Standartfunktionen, die in jeder Datei vorhanden sein müssen - wobei nicht alle von Bedeutung sind, ich diese aber aus Gewohnheit mittlerweile mit einbaue - und wir in unserem Fall in der Class das "ScriptWindow" benutzten. Diese wären jetzt:
PHP Code:
def __init__(self):
ui.ScriptWindow.__init__(self)
def __del__(self):
ui.ScriptWindow.__del__(self)
def Destroy(self):
self.Hide()
return TRUE
PHP Code:
import ui
class LernWindow(ui.ScriptWindow):
def __init__(self):
ui.ScriptWindow.__init__(self)
def __del__(self):
ui.ScriptWindow.__del__(self)
def Destroy(self):
self.Hide()
return TRUE
PHP Code:
Text = "Sie hat nun den Wert, welcher in den Gänsefüßchen steht"
Zahl = 18
Eine Funktion beginnt immer mit einem Funktionskopf. Dieser wird DEFiniert mit deinem NAMEN und den Werten in den () und wird dann mit einem Doppelpunkt beendet. Das sähe dann so aus:
PHP Code:
def Test(self):
PHP Code:
def Test(self, WERT1, WERT2):
PHP Code:
self.Test(19, 1)
def Test(self, WERT1, WERT2):
X = WERT1 + WERT2
return X
Kapitel 1.0 - Das erste Script
Nach der ganzen Theorie beginnen wir direkt damit eine Art von "Hallo Welt" - Script für den Chat in Metin2 zu erstellen. Das hört sich jetzt nich sooo spannend an, ist es auch nicht wirklich, trotzalledem legt es den Grundstein für die Arbeit mit dem Clienten bzw. mit Python im Bereich des Metin2 Clienten. Damit das ganze am Anfang noch sehr leicht ist, erstellen wir das Script in der game.py aus der root, weil dort nicht darauf geachtet werden muss, ob die Bibiliotheken beireits eingebunden sind und ihr keine Klasse starten müsst. Jetzt erstellen wir zuerst einen Abruf, welcher eine Funktion ausführen soll, wenn die Taste F10 gedrückt wird. Dafür sucht ihr nach:
PHP Code:
onPressKeyDict[app.DIK_F] = lambda : self.__PressFKey()
PHP Code:
onPressKeyDict[app.DIK_F10] = lambda : self.__HalloWelt()
Und schon haben wir einen Hotkey für die Funktion __HalloWelt bestimmt, welche wir jetzt nur noch erstellen müssen, damit das auch funktioniert, denn wenn man jetzt F5 drücken würde, so könnte man eine Fehlermeldung vom Clienten bekommen bzw. dieser würde garnicht erst starten, weil er die Funktion nicht finden kann.
Nun erstellen wir die Funktion __HalloWelt direkt über den anderen Hotkey-Funktionen. Dazu suchen wir jetzt nach
PHP Code:
def __PressNumKey(self,num):
PHP Code:
def __HalloWelt(self):
PHP Code:
def __HalloWelt(self):
net.SendChatPacket("Hier komme ich!")
unter diesen Beitrag.
Kapitel 2.0 - Das erste eigenständige Script als Board
Diesmal wollen wir etwas erschaffen, dass sich etwas schwerer gestalten sollte, da es sich nun um ein eigenständiges Board in einer alleinstehenden Pythondatei sein soll. Dazu erstellt ihr euch erstmal eine Pythondatei mit der Endung .py. Meine heißt in diesem Beispiel "uilernboard.py". So nun öffnen wir diese und legen erstmal die Imports fest. Deshalb muss man sich an der Stelle schon mal überlegen, was soll das Script machen und was brauche ich. Imports können ja immer noch später hinzugefügt werden, jedoch finde ich
bringt es schon mal eine kleine Übersicht in die Datei, wenn ich weiß, was ich brauche. Da wir ein Board erstellen wollen brauchen wir wie in den Grundlagen gelernt die ui. Weitere Imports werden an dieser Stelle jetzt noch nicht benötigt. Danach folgt jetzt erstmal die Klasse ich definiere diese jetzt als
PHP Code:
class LernWindow(ui.ScriptWindow):
PHP Code:
ui.ScriptWindow.__init__(self)
PHP Code:
self.LoadBoard()
da Python eine OpenSource - Sprache ist und es später für andere besser verständlich ist, diesen Quelltext zu lesen, als wenn da Variabeln und Funktionen mit Namen wie Noob, Raicon, Hsagd2 drin stehen. Jetzt aber wieder zurück zum Script. Nachdem wir nun unsere Funktion haben in der init aufrufen lassen, sollten wir diese auch erstellen und ihr eine wirkliche Funktion geben. So erstellen wir nun die Funtkion LoadBoard direkt unter der Destroy Funktion. Jetzt fehlt eigentlich nur noch das Board. Dieses erstellen wir auch nun, dazu solltet ihr euch einen Namen überlegen, der dazu passt, bei mir ist es nun Board, weil es ja auch ein Board ist. Nun kommt der wichtigste Schritt bei einem Board, denn es muss definiert werden ob es ein
Board mit festen Hintergrund ist oder eins mit durchsichtigen Hintergrund. Wir wählen jetzt das Board mit dem festen Hintergrund. Dazu schreiben wir nun, da wir unsere Variable Board auch als solches definieren wollen
PHP Code:
self.Board = ui.Board()
PHP Code:
self.Board.SetSize(300, 300)
PHP Code:
self.Board.SetCenterPosition()
Ich bitte euch diese Formel einzuprägen, da sie gebrauch finden wird, wenn ihr selbständig Fenster auf bestimme Positionen bringen wollt zur jeweiligen Fenstergröße. Jetzt müssen wir dem Board aber auch noch 2 weitere Attribute hinzufügen, da es sonst nicht bewegbar ist und starr an der Stelle stehen bleibt, wo es aufgerufen wurde. Deshalb schreiben wir nun die Attribute "movable" und "float" zum Board. Dies würde so aussehen:Quote:
Y_Position = FensterHöhe/2 - BoardHöhe/2
X_Position = FensterTiefe/2 - BoardTiefe/2
Gesamtformel = (FensterTiefe/2 - BoardTiefe/2), (FensterHöhe/2 - BoardHöhe/2)
PHP Code:
self.Board.AddFlag("movable")
self.Board.AddFlag("float")
PHP Code:
self.Board.Show()
PHP Code:
def Show(self):
self.Board.Show()
ACHTUNG! Unter eurer letzten Zeile müsst ihr eine Leerzeile anlegen, also eine Zeile ohne Inhalt, diese darf aber keinen grauen senkrechten Strich enthalten also den ich nenne es Funktionsbaum, sondern muss BLANK sein! Wie ihr das macht? Ihr geht direkt zum Anfang der Zeile, dabei dürfen keine TABs oder Leerzeichen in der Zeile sein, dann tippt ihr einen Buchstaben ein und löscht diesen wieder. Fertig eure Zeile ist nun blank! Hier noch ein Bild, oben ist es falsch darunter ist es richtig!
Habt ihr diese Blankozeile nicht kommt meistens dieser Fehler:
Somit ist das Script nun komplett. Jedoch kann man das Board nicht einfach in den Clienten packen und es wird automatisch aufgerufen, nein auch dafür muss man einen Hotkey festlegen und dies wird nun eure Aufgabe sein. Jedoch gibt es von mir noch etwas hilfe wie man ein anderes PyScript laden kann. Dazu schreibe ich euch diese ZeilenQuote:
0112 23:49:22395 :: File "networkModule.py", line 231, in SetGamePhase
0112 23:49:22395 :: File "system.py", line 141, in __pack_import
0112 23:49:22395 :: File "system.py", line 112, in _process_result
0112 23:49:22396 :: File "game.py", line 31, in ?
0112 23:49:22396 :: File "system.py", line 141, in __pack_import
0112 23:49:22396 :: File "
0112 23:49:22396 :: <string>
0112 23:49:22396 :: ", line
0112 23:49:22396 :: 29
0112 23:49:22396 ::
0112 23:49:22396 ::
0112 23:49:22396 :: self.Destroy()
0112 23:49:22396 ::
0112 23:49:22396 ::
0112 23:49:22396 ::
0112 23:49:22396 ::
0112 23:49:22396 ::
0112 23:49:22396 ::
0112 23:49:22396 ::
0112 23:49:22396 ::
0112 23:49:22396 ::
0112 23:49:22396 ::
0112 23:49:22396 ::
0112 23:49:22396 ::
0112 23:49:22396 ::
0112 23:49:22396 ::
0112 23:49:22396 :: ^
0112 23:49:22396 :: SyntaxError
0112 23:49:22396 :: :
0112 23:49:22396 :: invalid syntax
0112 23:49:22396 ::
Lösung:Quote:
import PYTHONDATEI
VARNAME = PYTHONDATEI.KLASSE() ### OHNE INHALT VON ui.Sc....
VARNAME.ATTRIBUT ZUM ANZEIGEN![]()
PHP Code:
import uiLernBoard
LernBoard = uiLernBoard.LernWindow()
LernBoard.Show()
Hier zum Abschluss noch ein Screen vom kompletten Script:
Hier auch noch der InGameScreen:
Abschließend will ich sagen, dass ich sehen werde ob ich diesen Thread hier Update und weitere Kapitel einfüge. Es kommt halt darauf an ob ihr daran interessiert seit oder halt nicht.
Und noch etwas, ich weiß das es für einige hier nichts besonderes mehr darstellt aber es ist für diejenigen, die es lernen möchten und noch keine bzw. kaum Erfahrung damit haben! Also sagt jetzt nicht, äh das kann doch jeder, denn genau das kann eben nicht jeder!
Spätziahlthancks:
LG RaiconQuote:
xCPx - Fürs Lehrer sein!
.Iscariot - Fürs testen!






