Wie bekannt sein dürfte werden die Python Scripts aus dem M2 Client mittels CPython im Client Source verarbeitet. CPython ist open-source auf github verfügbar, was das ganze sehr freundlich gestaltet das Update an sich zu machen.
Ich habe mich dazu entschieden mit CPython 3.10 zu arbeiten, da die Version 3.11 noch ein paar Einschränkungen hatte (als ich mit dem Projekt gestartet habe) und version 3.12 war noch kein stable release.
Schritt 1 war es also das repo zu klonen und die entsprechenden Schritte aus den Docs durchzuführen.
Bitte melden Sie sich an, um diesen Link zu sehen.
Die Vorbereitung zum Kompilieren der entsprechenden libs für den Client sind einfach. Das repo gibt ein batch Script für Windows Hosts, welches alles für einen erledigt.
Alle nötigen Infos sind auch in einer Bitte melden Sie sich an, um diesen Link zu sehen. zu finden, dieses file war mein bester Freund um die Solution zum laufen zu bekommen.
Um die passenden Libraries für den M2 Client zu kompilieren habe ich jeweils im Debug und Release Mode für Win32 Konfiguration folgende Projekte der Solution kompiliert:
- python
- python3dll
Die daraus resultierenden Libraries sind dann im Ordner PCBuild\win32 zu finden.
Für den Client an sich, nicht die Executable, wird die Python310.dll benötigt.
Als Include im Source (Extern\Python3\libs) die python3.lib, python310.lib und python311.lib. Wenn man Funktionen aus der CPython library debugen will, dann auch die entsprechenden *_d.lib Libraries.
Warum die python311.lib benötigt wird ist mir nicht ganz klar, diese ist jedoch im repo unter "externals\pythonx86\tools\libs" zu finden.
Kommen wir generell zum Include im Metin2 Source. In dem EXTERN Ordner, wie er bei den meisten von euch wahrscheinlich auch heißt, habe ich einfach einen neuen Unterordner "Python3" erstellt. Darin sind alle nötigen C/C++ Header und die entsprechenden libraries enthalten. Den Ordner, so wie ich ihn habe, lade ich hier als Anhang hoch.
Der Python3\libs Ordner muss noch in den Einstellungen von dem UserInterface Projekt mit in die Configs(Debug/Distribute*/Release*) aufgenommen werden:
- UserInterface -> Linker -> Alle Optionen -> Zusätzliche Bibliotheksverzeichnisse -> $(ProjectDir)../../Extern\Python3\libs
* Welche Konfiguration ihr benutzt ist hier entscheidend
Nun konnte ich auch anfangen richtigen Code zu schreiben und den M2 Client Source anpassen. Erster Schritt war es ein neues Präprozesser Symbol in der locale_inc.h zu definieren
Alle meine Änderungen habe ich immer über das Symbol bedingt, sodass ich auch ein Fallback auf Python2 jederzeit möglich ist.
Erste Aufgabe für mich war es die Initalisierungsfunktionen für die Python Module wie app, player, item usw. zu korrigieren. Mit dem Upgrade von Python2.X auf Python3 hat sich da grundsätzlich etwas geändert.
Die Funktionen zum Initialisieren der Extension Modules müssen 1. vor dem Initialisieren des eigentlichen Python Interpreters ausgerufen werden und 2. auch anders als Modul registriert werden.
Als Einstiegspunkt dafür nehmen wir den Kontruktor der CPythonLauncher Klasse -> ScriptLib\PythonLauncher.cpp -> CPythonLauncher::CPythonLauncher()
Bevor Py_Initialize(); aufgerufen wird müssen alle Module initialisiert werden. Die Liste der benötigten Module ist in UserInterface.cpp zu finden:
bool RunMainScript(CPythonLauncher& pyLauncher, const char* lpCmdLine)
Hierbei sind alle Funktionen mit folgendem Schema zu berücksichtigen:
initpack();
initdbg();
initime();
initgrp();
initgrpImage();
initgrpText();
Ich bin jeweils so vorgegangen, dass ich mir zu jeder der Funktionen die Deklaration angesehen habe, das war meistens in den StdAfx.h files von den entspechenden Projekten, und dort erstmal die Deklaration verändert habe. Beispiel aus der StdAfx.h aus UserInterface
- #ifdef PYTHON_3
- PyMODINIT_FUNC PyInit_udp(void);
- PyMODINIT_FUNC PyInit_app(void);
- PyMODINIT_FUNC PyInit_ime(void);
- PyMODINIT_FUNC PyInit_systemSetting(void);
- PyMODINIT_FUNC PyInit_chr(void);
- PyMODINIT_FUNC PyInit_chrmgr(void);
- PyMODINIT_FUNC PyInit_Chat(void);
- PyMODINIT_FUNC PyInit_TextTail(void);
- PyMODINIT_FUNC PyInit_Item(void);
- PyMODINIT_FUNC PyInit_NonPlayer(void);
- PyMODINIT_FUNC PyInit_net(void);
- PyMODINIT_FUNC PyInit_Player(void);
- PyMODINIT_FUNC PyInit_SectionDisplayer(void);
- PyMODINIT_FUNC PyInit_ServerStateChecker(void);
- #ifdef ENABLE_RENDER_TARGET
- PyMODINIT_FUNC PyInit_RenderTarget(void);
- #endif
- PyMODINIT_FUNC PyInit_Trade(void);
- PyMODINIT_FUNC PyInit_MiniMap(void);
- PyMODINIT_FUNC PyInit_Profiler(void);
- PyMODINIT_FUNC PyInit_Event(void);
- PyMODINIT_FUNC PyInit_effect(void);
- PyMODINIT_FUNC PyInit_snd(void);
- PyMODINIT_FUNC PyInit_eventMgr(void);
- PyMODINIT_FUNC PyInit_Background(void);
- PyMODINIT_FUNC PyInit_wndMgr(void);
- PyMODINIT_FUNC PyInit_shop(void);
- PyMODINIT_FUNC PyInit_pack(void);
- PyMODINIT_FUNC PyInit_skill(void);
- PyMODINIT_FUNC PyInit_fly(void);
- PyMODINIT_FUNC PyInit_quest(void);
- PyMODINIT_FUNC PyInit_safebox(void);
- PyMODINIT_FUNC PyInit_guild(void);
- PyMODINIT_FUNC PyInit_Messenger(void);
- #ifdef ENABLE_ACCE_SYSTEM
- PyMODINIT_FUNC PyInit_Acce(void);
- #endif
- #ifdef __USE_PYTHON_SHINING__
- PyMODINIT_FUNC PyInit_Shining(void);
- #endif
- #else
- void initudp();
- void initapp();
- void initime();
- void initsystemSetting();
- void initchr();
- void initchrmgr();
- void initChat();
- void initTextTail();
- void initime();
- void initItem();
- void initNonPlayer();
- void initnet();
- void initPlayer();
- void initSectionDisplayer();
- void initServerStateChecker();
- #ifdef ENABLE_RENDER_TARGET
- void initRenderTarget();
- #endif
- void initTrade();
- void initMiniMap();
- void initProfiler();
- void initEvent();
- void initeffect();
- void initsnd();
- void initeventmgr();
- void initBackground();
- void initwndMgr();
- void initshop();
- void initpack();
- void initskill();
- void initfly();
- void initquest();
- void initsafebox();
- void initguild();
- void initMessenger();
- #ifdef ENABLE_ACCE_SYSTEM
- void initAcce();
- #endif
- #ifdef __USE_PYTHON_SHINING__
- void initShining();
- #endif
- #endif
Alles anzeigen
Dieses Vorgehen habe ich für alle Funktionsaufrufe aus der o.g. Funktion RunMainScript angewandt.
Hierbei ist unbedingt darauf zu achten, dass die Init Funktionen zu 100% nach dem Schema benannt werden:
PyMODINITFUNC PyInit_<ModuleName>(void)
Die Dokumentation weißt dort explizit drauf hin.
Nun müssen noch die Funktionen an sich verändert werden.
Die jeweiligen Implementierungen müssen angepasst werden, z.B. wie hier
- #ifdef PYTHON_3
- PyMODINIT_FUNC PyInit_app(void)
- #else
- void initapp()
- #endif
Nun kommt der erste etwas komplizierte Teil. jede der Init Funktionen muss zwangsweise ein PyObject zurückgeben, dieses wird in der Funktion selbst erstellt. Dazu wurde in der alten Python Version die Funktion Py_InitModule() benutzt. Diese Funktion ist mittlerweile aber nicht mehr verfügbar. Es muss nun wie folgt vorgegangen werden:
- #ifdef PYTHON_3
- static struct PyModuleDef app =
- {
- PyModuleDef_HEAD_INIT, //base -> always has to be PyModuleDef_HEAD_INIT
- "app", //Name of the module
- "app interface", //Documentation, can be an empty string
- -1, //size of the module -> -1 means that the module does not support sub-interpreters, because it has global state. required for multi-phase init
- s_methods //pointer to a table of module-level functions, described by PyMethodDef values. Can be NULL if no functions are present.
- };
- PyObject * poModule = PyModule_Create(&app);
- #else
- PyObject * poModule = Py_InitModule("app", s_methods);
- #endif
Alles anzeigen
Wir erstellen ein struct PyModuleDef mit dem Namen des Moduls. Die Parameter des structs sind als Kommentar im Code beschrieben. Mit diesem struct wird die PyModule_Create Funktion aufgerufen und wir bekommen ein PyObject zurück.
Nun ist es wichtig zu unterscheiden ob mit diesem PyObject (Module) noch etwas passiert, also ob noch Konstanten zugewiesen werden wie z.B. in dem app Module
- PyModule_AddIntConstant(poModule, "INFO_ITEM", CPythonApplication::INFO_ITEM);
- PyModule_AddIntConstant(poModule, "INFO_ACTOR", CPythonApplication::INFO_ACTOR);
- PyModule_AddIntConstant(poModule, "INFO_EFFECT", CPythonApplication::INFO_EFFECT);
- PyModule_AddIntConstant(poModule, "INFO_TEXTTAIL", CPythonApplication::INFO_TEXTTAIL);
- PyModule_AddIntConstant(poModule, "DEGREE_DIRECTION_SAME", DEGREE_DIRECTION_SAME);
- PyModule_AddIntConstant(poModule, "DEGREE_DIRECTION_RIGHT", DEGREE_DIRECTION_RIGHT);
- PyModule_AddIntConstant(poModule, "DEGREE_DIRECTION_LEFT", DEGREE_DIRECTION_LEFT);
Wenn dies der Fall ist, dann dürfen wir das PyObject erst ganz am Ende der Funktion zurückgeben. Wenn mit dem Module, also dem Object, nichts mehr passiert, dann könne wir direkt ein return programmieren wie in diesem Beispiel.
- #ifdef PYTHON_3
- static struct PyModuleDef grpImage =
- {
- PyModuleDef_HEAD_INIT,
- "grpImage",
- "grpImage module",
- -1,
- s_methods
- };
- return PyModule_Create(&grpImage);
- #else
- Py_InitModule("grpImage", s_methods);
- #endif
- }
Alles anzeigen
Nachdem ich alle vorhandenen Init Funktionen umgeschrieben habe, habe ich diese im Konstruktur des PythonLaunchers augerufen und die Module entsprechend registriert.
- CPythonLauncher::CPythonLauncher()
- {
- #ifdef PYTHON_3
- PyImport_AppendInittab("pack", PyInit_pack);
- PyImport_AppendInittab("dbg", PyInit_dbg);
- PyImport_AppendInittab("ime", PyInit_ime);
- PyImport_AppendInittab("grp", PyInit_grp);
- PyImport_AppendInittab("grpImage", PyInit_grpImage);
- PyImport_AppendInittab("grpText", PyInit_grpText);
- PyImport_AppendInittab("wndMgr", PyInit_wndMgr);
- PyImport_AppendInittab("udp", PyInit_udp);
- PyImport_AppendInittab("app", PyInit_app);
- PyImport_AppendInittab("systemSetting", PyInit_systemSetting);
- PyImport_AppendInittab("chr", PyInit_chr);
- PyImport_AppendInittab("chrmgr", PyInit_chrmgr);
- PyImport_AppendInittab("Player", PyInit_Player);
- PyImport_AppendInittab("Item", PyInit_Item);
- PyImport_AppendInittab("NonPlayer", PyInit_NonPlayer);
- PyImport_AppendInittab("Trade", PyInit_Trade);
- PyImport_AppendInittab("Chat", PyInit_Chat);
- PyImport_AppendInittab("TextTail", PyInit_TextTail);
- PyImport_AppendInittab("net", PyInit_net);
- PyImport_AppendInittab("MiniMap", PyInit_MiniMap);
- PyImport_AppendInittab("Profiler", PyInit_Profiler);
- PyImport_AppendInittab("Event", PyInit_Event);
- PyImport_AppendInittab("effect", PyInit_effect);
- PyImport_AppendInittab("fly", PyInit_fly);
- PyImport_AppendInittab("snd", PyInit_snd);
- PyImport_AppendInittab("eventMgr", PyInit_eventMgr);
- PyImport_AppendInittab("shop", PyInit_shop);
- PyImport_AppendInittab("skill", PyInit_skill);
- PyImport_AppendInittab("quest", PyInit_quest);
- PyImport_AppendInittab("Background", PyInit_Background);
- PyImport_AppendInittab("Messenger", PyInit_Messenger);
- #ifdef ENABLE_ACCE_SYSTEM
- PyImport_AppendInittab("Acce", PyInit_Acce);
- #endif
- PyImport_AppendInittab("safebox", PyInit_safebox);
- PyImport_AppendInittab("guild", PyInit_guild);
- PyImport_AppendInittab("ServerStateChecker", PyInit_ServerStateChecker);
- #ifdef ENABLE_RENDER_TARGET
- PyImport_AppendInittab("RenderTarget", PyInit_RenderTarget);
- #endif
- #ifdef __USE_PYTHON_SHINING__
- PyImport_AppendInittab("Shining", PyInit_Shining);
- #endif
- #endif
- Py_Initialize();
- }
Alles anzeigen
Gleichzeitig musste ich die "alten" Funktionsaufrufe ungültig machen, bzw. durch das Preprocessor Symbol ausschließen
- bool RunMainScript(CPythonLauncher& pyLauncher, const char* lpCmdLine)
- {
- #ifndef PYTHON_3
- initpack();
- initdbg();
- initime();
- initgrp();
- initgrpImage();
- [...]
- #endif
Direkt in dem selben Source File musste ich feststellen, dass sich der Python Modulimport für "__builtin__" verändert hat. Dieses Modul ist nun mit "builtins" zu importieren.
- #ifdef PYTHON_3
- PyObject* builtins = PyImport_ImportModule("builtins");
- #else
- PyObject * builtins = PyImport_ImportModule("__builtin__");
- #endif
Zusätzlich muss direkt am Anfang der UserInterface.cpp noch auf die neue Python lib verwiesen werden. Auch hier kann wieder unterschieden werden zwischen Debug und nicht Debug, das habe ich mir aber geschenkt da ich keinen Sinn darin sehe die CPython Funktionen aus der Lib zu debuggen.
- #ifdef PYTHON_3
- #pragma comment( lib, "python310.lib" )
- #else
- #pragma comment( lib, "python2.lib" )
- #endif
So richtig trial & error war es heruaszufinden welcher der bytecode libs nun wirklich benötigt werden und welche nicht. Ich bin mit dieser Anpassung in UserInterface bis jetzt ganz gut klargekommen.
- static const char * sc_apszPythonLibraryFilenames[] =
- {
- #ifndef PYTHON_3
- "UserDict.pyc",
- #endif
- "__future__.pyc",
- #ifdef PYTHON_3
- "copyreg.pyc",
- #else
- "copy_reg.pyc",
- #endif
- "linecache.pyc",
- "ntpath.pyc",
- "os.pyc",
- "site.pyc",
- "stat.pyc",
- "string.pyc",
- "traceback.pyc",
- "types.pyc",
- "\n",
- };
Alles anzeigen
Generell müssen sämtliche Includes von Python2 Header Files durch das preprocessor symbol bedingt werden. Ich hier bin ich mir noch nicht zu 100% sicher ob ich etwas Wichtiges ausgelassen habe, so weit konnte ich leider noch nicht testen.
Das erste Include befindet sich in scriptLib/PythonLauncher.cpp sowie in dem entspechenden Header File
- #ifdef PYTHON_3
- #include "../UserInterface/StdAfx.h"
- #include "../../Extern/Python3/frameobject.h"
- #else
- #include "../../Extern/Python2/frameobject.h"
- #endif
- #pragma once
- #ifdef PYTHON_3
- #include "../../Extern/Python3/frameobject.h"
- #else
- #include "../../Extern/Python2/frameobject.h"
- #endif
- #ifdef _DEBUG
- #undef _DEBUG
- #ifdef PYTHON_3
- #include "../../Extern/Python3/Python.h"
- #else
- #include "../../Extern/Python2/Python.h"
- #endif
- #define _DEBUG
- #else
- #ifdef PYTHON_3
- #include "../../Extern/Python3/Python.h"
- #else
- #include "../../Extern/Python2/Python.h"
- #endif
- #endif
- #ifdef PYTHON_3
- #include "../../Extern/Python3/token.h"
- #include "../../Extern/Python3/errcode.h"
- #include "../../Extern/Python3/compile.h"
- #include "../../Extern/Python3/marshal.h"
- #else
- #include "../../Extern/Python2/node.h"
- #include "../../Extern/Python2/grammar.h"
- #include "../../Extern/Python2/token.h"
- #include "../../Extern/Python2/parsetok.h"
- #include "../../Extern/Python2/errcode.h"
- #include "../../Extern/Python2/compile.h"
- #include "../../Extern/Python2/symtable.h"
- #include "../../Extern/Python2/eval.h"
- #include "../../Extern/Python2/marshal.h"
- #endif
Alles anzeigen
Ein Include musste tatsächlich ausgebaut werden, hier habe ich kein Replacement zu gefunden bzw. keine wirkliche verwendung im Quellcode
- #ifndef PYTHON_3
- #include "../../Extern/Python2/longintrepr.h"
- #endif
Ein weiteres Problem, welches ich irgendwie auflösen musste, war das Update von PyString_* zu PyUnicode_*, neue Funktionen/getter-setter von PyFrameObjects sowie Update von PyInt_* zu PyLong_*. Diese Themen gab es glücklicherweise nicht allzu oft, den ganzen Kack aufzulösen hat ewig gedauert. Ich komprimiere hier mal als Code-Ausschnitte was ich alles geändert habe.
- void CWindow::OnUpdate()
- {
- if (!m_poHandler)
- return;
- if (!IsShow())
- return;
- #ifdef PYTHON_3
- static PyObject* poFuncName_OnUpdate = PyUnicode_InternFromString("OnUpdate");
- #else
- static PyObject* poFuncName_OnUpdate = PyString_InternFromString("OnUpdate");
- #endif
- //PyCallClassMemberFunc(m_poHandler, "OnUpdate", BuildEmptyTuple());
- PyCallClassMemberFunc_ByPyString(m_poHandler, poFuncName_OnUpdate, BuildEmptyTuple());
- }
Alles anzeigen
- void Traceback()
- {
- std::string str;
- for (int i = 0; i < g_nCurTraceN; ++i)
- {
- str.append(g_stTraceBuffer[i]);
- str.append("\n");
- }
- PyObject * exc;
- PyObject * v;
- PyObject * tb;
- const char * errStr;
- PyErr_Fetch(&exc, &v, &tb);
- #ifdef PYTHON_3
- if (PyUnicode_Check(v))
- {
- errStr = (const char*)PyUnicode_2BYTE_DATA(v);
- str.append("Error: ");
- str.append(errStr);
- Tracef("%s\n", errStr);
- }
- #else
- if (PyString_Check(v))
- {
- errStr = PyString_AS_STRING(v);
- str.append("Error: ");
- str.append(errStr);
- Tracef("%s\n", errStr);
- }
- #endif
- Py_XDECREF(exc); //changed to XDECREF to allow NULL parameters
- Py_XDECREF(v); //changed to XDECREF to allow NULL parameters
- Py_XDECREF(tb); //changed to XDECREF to allow NULL parameters
- LogBoxf("Traceback:\n\n%s\n", str.c_str());
- }
- int TraceFunc(PyObject * obj, PyFrameObject * f, int what, PyObject *arg)
- {
- const char * funcname;
- char szTraceBuffer[128];
- #ifdef PYTHON_3
- int lineNo = 0;
- #endif
- switch (what)
- {
- case PyTrace_CALL:
- if (g_nCurTraceN >= 512)
- return 0;
- if (Py_OptimizeFlag)
- #ifdef PYTHON_3
- lineNo = PyCode_Addr2Line(PyFrame_GetCode(f), f->f_lasti); //Use "PyFrame_GetLasti(f)" instead of "f->f_lasti" in Python 3.11 and above
- #else
- f->f_lineno = PyCode_Addr2Line(f->f_code, f->lasti);
- #endif
- #ifdef PYTHON_3
- if (PyFrame_GetCode(f) != NULL)
- {
- funcname = PyUnicode_AS_DATA(PyFrame_GetCode(f)->co_name);
- _snprintf(szTraceBuffer, sizeof(szTraceBuffer), "Call: File \"%s\", line %d, in %s",
- PyUnicode_AS_DATA(PyFrame_GetCode(f)->co_filename),
- PyFrame_GetLineNumber(f),
- funcname);
- }
-
- #else
- funcname = PyString_AsString(f->f_code->co_name);
- _snprintf(szTraceBuffer, sizeof(szTraceBuffer), "Call: File \"%s\", line %d, in %s",
- PyString_AsString(f->f_code->co_filename),
- f->f_lineno,
- funcname);
- #endif
- g_stTraceBuffer[g_nCurTraceN++]=szTraceBuffer;
- break;
- case PyTrace_RETURN:
- if (g_nCurTraceN > 0)
- --g_nCurTraceN;
- break;
- case PyTrace_EXCEPTION:
- if (g_nCurTraceN >= 512)
- return 0;
- PyObject * exc_type, * exc_value, * exc_traceback;
- PyTuple_GetObject(arg, 0, &exc_type);
- PyTuple_GetObject(arg, 1, &exc_value);
- PyTuple_GetObject(arg, 2, &exc_traceback);
- int len;
- const char * exc_str;
- PyObject_AsCharBuffer(exc_type, &exc_str, &len);
- #ifdef PYTHON_3
- if (PyFrame_GetCode(f) != nullptr)
- {
- _snprintf(szTraceBuffer, sizeof(szTraceBuffer), "Exception: File \"%s\", line %d, in %s",
- PyUnicode_AS_DATA(PyFrame_GetCode(f)->co_filename),
- PyFrame_GetLineNumber(f),
- PyUnicode_AS_DATA(PyFrame_GetCode(f)->co_name));
- }
-
- #else
- _snprintf(szTraceBuffer, sizeof(szTraceBuffer), "Exception: File \"%s\", line %d, in %s",
- PyString_AS_STRING(f->f_code->co_filename),
- f->f_lineno,
- PyString_AS_STRING(f->f_code->co_name));
- #endif
- g_stTraceBuffer[g_nCurTraceN++]=szTraceBuffer;
- break;
- }
- return 0;
- }
- bool CPythonLauncher::Create(const char* c_szProgramName)
- {
- NANOBEGIN
- #ifdef PYTHON_3
- Py_SetProgramName((const wchar_t*)c_szProgramName);
- #else
- Py_SetProgramName((char*)c_szProgramName);
- #endif
- #ifdef _DEBUG
- //PyEval_SetTrace(TraceFunc, NULL);
- #endif
- m_poModule = PyImport_AddModule((char *) "__main__");
- if (!m_poModule)
- return false;
- m_poDic = PyModule_GetDict(m_poModule);
- #ifdef PYTHON_3
- PyObject* builtins = PyImport_ImportModule("builtins");
- #else
- PyObject * builtins = PyImport_ImportModule("__builtin__");
- #endif
- PyModule_AddIntConstant(builtins, "TRUE", 1);
- PyModule_AddIntConstant(builtins, "FALSE", 0);
- #ifdef PYTHON_3
- PyDict_SetItemString(m_poDic, "builtins", builtins);
- #else
- PyDict_SetItemString(m_poDic, "__builtins__", builtins);
- #endif
- Py_DECREF(builtins);
- if (!RunLine("import __main__"))
- return false;
- if (!RunLine("import sys"))
- return false;
- NANOEND
- return true;
- }
- bool CPythonLauncher::RunCompiledFile(const char* c_szFileName)
- {
- NANOBEGIN
- FILE * fp = fopen(c_szFileName, "rb");
- if (!fp)
- return false;
- PyCodeObject *co;
- PyObject *v;
- long magic;
- long PyImport_GetMagicNumber(void);
- magic = _PyMarshal_ReadLongFromFile(fp);
- if (magic != PyImport_GetMagicNumber())
- {
- PyErr_SetString(PyExc_RuntimeError, "Bad magic number in .pyc file");
- fclose(fp);
- return false;
- }
- _PyMarshal_ReadLongFromFile(fp);
- v = _PyMarshal_ReadLastObjectFromFile(fp);
- fclose(fp);
- if (!v || !PyCode_Check(v))
- {
- Py_XDECREF(v);
- PyErr_SetString(PyExc_RuntimeError, "Bad code object in .pyc file");
- return false;
- }
- #ifdef PYTHON_3
- v = PyEval_EvalCode(v, m_poDic, m_poDic);
- #else
- co = (PyCodeObject*)v;
- v = PyEval_EvalCode(co, m_poDic, m_poDic);
- #endif
- /* if (v && flags)
- flags->cf_flags |= (co->co_flags & PyCF_MASK);*/
- Py_DECREF(co);
- if (!v)
- {
- Traceback();
- return false;
- }
- Py_DECREF(v);
- #ifndef PYTHON_3
- if (Py_FlushLine())
- #endif
- PyErr_Clear();
- NANOEND
- return true;
- }
- bool CPythonLauncher::RunLine(const char* c_szSrc)
- {
- #ifdef PYTHON_3
- PyObject* v = PyRun_String(c_szSrc, Py_file_input, m_poDic, m_poDic);
- #else
- PyObject * v = PyRun_String((char *) c_szSrc, Py_file_input, m_poDic, m_poDic);
- #endif
- if (!v)
- {
- Traceback();
- return false;
- }
- Py_DECREF(v);
- return true;
- }
- const char* CPythonLauncher::GetError()
- {
- PyObject* exc;
- PyObject* v;
- PyObject* tb;
- PyErr_Fetch(&exc, &v, &tb);
- #ifdef PYTHON_3
- if (PyUnicode_Check(v))
- return PyUnicode_AS_DATA(v);
- #else
- if (PyString_Check(v))
- return PyString_AS_STRING(v);
- #endif
- return "";
- }
Alles anzeigen
- static PyObject * r_object(RFILE *p)
- {
- PyObject *v, *v2;
- long i, n;
- int type = r_byte(p);
- switch (type) {
- case EOF:
- PyErr_SetString(PyExc_EOFError,
- "EOF read where object expected");
- return NULL;
- case TYPE_NULL:
- return NULL;
- case TYPE_NONE:
- Py_INCREF(Py_None);
- return Py_None;
- case TYPE_STOPITER:
- Py_INCREF(PyExc_StopIteration);
- return PyExc_StopIteration;
- case TYPE_ELLIPSIS:
- Py_INCREF(Py_Ellipsis);
- return Py_Ellipsis;
- case TYPE_INT:
- #ifdef PYTHON_3
- return PyLong_FromLong(r_long(p));
- #else
- return PyInt_FromLong(r_long(p));
- #endif
- case TYPE_INT64:
- return r_long64(p);
- case TYPE_LONG:
- {
- int size;
- PyLongObject* ob;
- n = r_long(p);
- size = n<0 ? -n : n;
- ob = _PyLong_New(size);
- if (ob == NULL)
- return NULL;
- #ifndef PYTHON_3
- ob->ob_size = n;
- #endif
- for (i = 0; i < size; i++)
- ob->ob_digit[i] = (short) r_short(p);
- return (PyObject *) ob;
- }
- case TYPE_FLOAT:
- {
- char buf[256];
- double dx;
- n = r_byte(p);
- if (r_string(buf, (int)n, p) != n) {
- PyErr_SetString(PyExc_EOFError,
- "EOF read where object expected");
- return NULL;
- }
- buf[n] = '\0';
- PyFPE_START_PROTECT("atof", return 0)
- dx = atof(buf);
- PyFPE_END_PROTECT(dx)
- return PyFloat_FromDouble(dx);
- }
- #ifndef WITHOUT_COMPLEX
- case TYPE_COMPLEX:
- {
- char buf[256];
- Py_complex c;
- n = r_byte(p);
- if (r_string(buf, (int)n, p) != n) {
- PyErr_SetString(PyExc_EOFError,
- "EOF read where object expected");
- return NULL;
- }
- buf[n] = '\0';
- PyFPE_START_PROTECT("atof", return 0)
- c.real = atof(buf);
- PyFPE_END_PROTECT(c)
- n = r_byte(p);
- if (r_string(buf, (int)n, p) != n) {
- PyErr_SetString(PyExc_EOFError,
- "EOF read where object expected");
- return NULL;
- }
- buf[n] = '\0';
- PyFPE_START_PROTECT("atof", return 0)
- c.imag = atof(buf);
- PyFPE_END_PROTECT(c)
- return PyComplex_FromCComplex(c);
- }
- #endif
- case TYPE_STRING:
- n = r_long(p);
- if (n < 0) {
- PyErr_SetString(PyExc_ValueError, "bad marshal data");
- return NULL;
- }
- #ifdef PYTHON_3
- v = PyUnicode_FromStringAndSize((char*)NULL, n);
- if (v != NULL) {
- if (r_string(const_cast<char *>(PyUnicode_AS_DATA(v)), (int)n, p) != n) {
- Py_DECREF(v);
- v = NULL;
- PyErr_SetString(PyExc_EOFError,
- "EOF read where object expected");
- }
- }
- #else
- v = PyString_FromStringAndSize((char *)NULL, n);
- if (v != NULL) {
- if (r_string(PyString_AS_STRING(v), (int)n, p) != n) {
- Py_DECREF(v);
- v = NULL;
- PyErr_SetString(PyExc_EOFError,
- "EOF read where object expected");
- }
- }
- #endif
- return v;
- #ifdef Py_USING_UNICODE
- case TYPE_UNICODE:
- {
- char *buffer;
- n = r_long(p);
- if (n < 0) {
- PyErr_SetString(PyExc_ValueError, "bad marshal data");
- return NULL;
- }
- buffer = PyMem_NEW(char, n);
- if (buffer == NULL)
- return PyErr_NoMemory();
- if (r_string(buffer, (int)n, p) != n) {
- PyMem_DEL(buffer);
- PyErr_SetString(PyExc_EOFError,
- "EOF read where object expected");
- return NULL;
- }
- v = PyUnicode_DecodeUTF8(buffer, n, NULL);
- PyMem_DEL(buffer);
- return v;
- }
- #endif
- case TYPE_TUPLE:
- n = r_long(p);
- if (n < 0) {
- PyErr_SetString(PyExc_ValueError, "bad marshal data");
- return NULL;
- }
- v = PyTuple_New((int)n);
- if (v == NULL)
- return v;
- for (i = 0; i < n; i++) {
- v2 = r_object(p);
- if ( v2 == NULL ) {
- Py_DECREF(v);
- v = NULL;
- break;
- }
- PyTuple_SET_ITEM(v, (int)i, v2);
- }
- return v;
- case TYPE_LIST:
- n = r_long(p);
- if (n < 0) {
- PyErr_SetString(PyExc_ValueError, "bad marshal data");
- return NULL;
- }
- v = PyList_New((int)n);
- if (v == NULL)
- return v;
- for (i = 0; i < n; i++) {
- v2 = r_object(p);
- if ( v2 == NULL ) {
- Py_DECREF(v);
- v = NULL;
- break;
- }
- PyList_SetItem(v, (int)i, v2);
- }
- return v;
- case TYPE_DICT:
- v = PyDict_New();
- if (v == NULL)
- return NULL;
- for (;;) {
- PyObject *key, *val;
- key = r_object(p);
- if (key == NULL)
- break; /* XXX Assume TYPE_NULL, not an error */
- val = r_object(p);
- if (val != NULL)
- PyDict_SetItem(v, key, val);
- Py_DECREF(key);
- Py_XDECREF(val);
- }
- return v;
- case TYPE_CODE:
- #ifndef PYTHON_3
- if (PyEval_GetRestricted()) {
- PyErr_SetString(PyExc_RuntimeError,
- "cannot unmarshal code objects in "
- "restricted execution mode");
- return NULL;
- }
- else {
- #else
- {
- #endif
- int argcount = r_short(p);
- int nlocals = r_short(p);
- int stacksize = r_short(p);
- int flags = r_short(p);
- PyObject *code = NULL;
- PyObject *consts = NULL;
- PyObject *names = NULL;
- PyObject *varnames = NULL;
- PyObject *freevars = NULL;
- PyObject *cellvars = NULL;
- PyObject *filename = NULL;
- PyObject *name = NULL;
- int firstlineno = 0;
- PyObject *lnotab = NULL;
- #ifdef PYTHON_3
- PyObject* exceptiontable = NULL;
- PyObject* whatever = NULL;
- #endif
- code = r_object(p);
- if (code) consts = r_object(p);
- if (consts) names = r_object(p);
- if (names) varnames = r_object(p);
- if (varnames) freevars = r_object(p);
- if (freevars) cellvars = r_object(p);
- if (cellvars) filename = r_object(p);
- if (filename) name = r_object(p);
- if (name) {
- firstlineno = r_short(p);
- lnotab = r_object(p);
- }
- #ifdef PYTHON_3
- if (!PyErr_Occurred()) {
- //Use this code for Python 3.11 and above
- /*v = (PyObject*)PyCode_New(
- argcount, 0, nlocals, stacksize, flags,
- code, consts, names, varnames,
- freevars, cellvars, filename, name, whatever,
- firstlineno, lnotab, exceptiontable);
- */
- v = (PyObject*)PyCode_New(argcount, 0, nlocals, stacksize, flags,
- code, consts, names, varnames,
- freevars, cellvars, filename, name,
- firstlineno, lnotab);
- }
- #else
- if (!PyErr_Occurred()) {
- v = (PyObject *) PyCode_New(
- argcount, nlocals, stacksize, flags,
- code, consts, names, varnames,
- freevars, cellvars, filename, name,
- firstlineno, lnotab);
- }
- #endif
- else
- v = NULL;
- Py_XDECREF(code);
- Py_XDECREF(consts);
- Py_XDECREF(names);
- Py_XDECREF(varnames);
- Py_XDECREF(freevars);
- Py_XDECREF(cellvars);
- Py_XDECREF(filename);
- Py_XDECREF(name);
- Py_XDECREF(lnotab);
- }
- return v;
- default:
- /* Bogus data got written, which isn't ideal.
- This will let you keep working and recover. */
- PyErr_SetString(PyExc_ValueError, "bad marshal data");
- return NULL;
- }
- }
Alles anzeigen
- bool PyTuple_GetString(PyObject* poArgs, int pos, char** ret)
- {
- if (pos >= PyTuple_Size(poArgs))
- return false;
- PyObject* poItem = PyTuple_GetItem(poArgs, pos);
- if (!poItem)
- return false;
- #ifdef PYTHON_3
- if (!PyUnicode_Check(poItem))
- return false;
- *ret = const_cast<char*>(PyUnicode_AS_DATA(poItem));
- #else
- if (!PyString_Check(poItem))
- return false;
- *ret = PyString_AsString(poItem);
- #endif
- return true;
- }
Alles anzeigen
- PyObject* appShowWebPage(PyObject* poSelf, PyObject* poArgs)
- {
- char* szWebPage;
- if (!PyTuple_GetString(poArgs, 0, &szWebPage))
- return Py_BuildException();
- PyObject* poRect=PyTuple_GetItem(poArgs, 1);
- if (!PyTuple_Check(poRect))
- return Py_BuildException();
- RECT rcWebPage;
- #ifdef PYTHON_3
- rcWebPage.left = PyLong_AsLong(PyTuple_GetItem(poRect, 0));
- rcWebPage.top = PyLong_AsLong(PyTuple_GetItem(poRect, 1));
- rcWebPage.right = PyLong_AsLong(PyTuple_GetItem(poRect, 2));
- rcWebPage.bottom = PyLong_AsLong(PyTuple_GetItem(poRect, 3));
- #else
- rcWebPage.left=PyInt_AsLong(PyTuple_GetItem(poRect, 0));
- rcWebPage.top=PyInt_AsLong(PyTuple_GetItem(poRect, 1));
- rcWebPage.right=PyInt_AsLong(PyTuple_GetItem(poRect, 2));
- rcWebPage.bottom=PyInt_AsLong(PyTuple_GetItem(poRect, 3));
- #endif
- CPythonApplication::Instance().ShowWebPage(
- szWebPage,
- rcWebPage
- );
- return Py_BuildNone();
- }
- PyObject* appMoveWebPage(PyObject* poSelf, PyObject* poArgs)
- {
- PyObject* poRect=PyTuple_GetItem(poArgs, 0);
- if (!PyTuple_Check(poRect))
- return Py_BuildException();
- RECT rcWebPage;
- #ifdef PYTHON_3
- rcWebPage.left = PyLong_AsLong(PyTuple_GetItem(poRect, 0));
- rcWebPage.top = PyLong_AsLong(PyTuple_GetItem(poRect, 1));
- rcWebPage.right = PyLong_AsLong(PyTuple_GetItem(poRect, 2));
- rcWebPage.bottom = PyLong_AsLong(PyTuple_GetItem(poRect, 3));
- #else
- rcWebPage.left=PyInt_AsLong(PyTuple_GetItem(poRect, 0));
- rcWebPage.top=PyInt_AsLong(PyTuple_GetItem(poRect, 1));
- rcWebPage.right=PyInt_AsLong(PyTuple_GetItem(poRect, 2));
- rcWebPage.bottom=PyInt_AsLong(PyTuple_GetItem(poRect, 3));
- #endif
- CPythonApplication::Instance().MoveWebPage(rcWebPage);
- return Py_BuildNone();
- }
- PyObject* appGetFileList(PyObject* poSelf, PyObject* poArgs)
- {
- char* szFilter;
- if (!PyTuple_GetString(poArgs, 0, &szFilter))
- return Py_BuildException();
- PyObject* poList=PyList_New(0);
- WIN32_FIND_DATA wfd;
- memset(&wfd, 0, sizeof(wfd));
- HANDLE hFind = FindFirstFile(szFilter, &wfd);
- if (hFind != INVALID_HANDLE_VALUE)
- {
- do
- {
- #ifdef PYTHON_3
- PyObject* poFileName = PyUnicode_FromString(wfd.cFileName);
- #else
- PyObject* poFileName=PyString_FromString(wfd.cFileName);
- #endif
- PyList_Append(poList, poFileName);
- }
- while (FindNextFile(hFind, &wfd));
- FindClose(hFind);
- }
- return poList;
- }
Alles anzeigen
- PyObject* playerSendDragonSoulRefine(PyObject* poSelf, PyObject* poArgs)
- {
- BYTE bSubHeader;
- PyObject* pDic;
- TItemPos RefineItemPoses[DS_REFINE_WINDOW_MAX_NUM];
- if (!PyTuple_GetByte(poArgs, 0, &bSubHeader))
- return Py_BuildException();
- switch (bSubHeader)
- {
- case DS_SUB_HEADER_CLOSE:
- break;
- case DS_SUB_HEADER_DO_UPGRADE:
- case DS_SUB_HEADER_DO_IMPROVEMENT:
- case DS_SUB_HEADER_DO_REFINE:
- {
- if (!PyTuple_GetObject(poArgs, 1, &pDic))
- return Py_BuildException();
- int pos = 0;
- PyObject* key, *value;
- int size = PyDict_Size(pDic);
- while (PyDict_Next(pDic, &pos, &key, &value))
- {
- #ifdef PYTHON_3
- int i = PyLong_AsLong(key);
- #else
- int i = PyInt_AsLong(key);
- #endif
- if (i > DS_REFINE_WINDOW_MAX_NUM)
- return Py_BuildException();
- if (!PyTuple_GetByte(value, 0, &RefineItemPoses[i].window_type)
- || !PyTuple_GetInteger(value, 1, &RefineItemPoses[i].cell))
- {
- return Py_BuildException();
- }
- }
- }
- break;
- }
- CPythonNetworkStream& rns=CPythonNetworkStream::Instance();
- rns.SendDragonSoulRefinePacket(bSubHeader, RefineItemPoses);
- return Py_BuildNone();
- }
Alles anzeigen