1+
2+ package yutautil ;
3+
4+ #if cpp
5+ import cpp .Lib ;
6+ import cpp .Pointer ;
7+ import cpp .Native ;
8+ import haxe .Json ;
9+ import sys .io .File ;
10+
11+ class Pycript {
12+ // Python version info
13+ public static var pythonVersion (default , null ): String ;
14+ public static var pythonInitialized (default , null ): Bool = false ;
15+
16+ // Script management
17+ private var moduleName : String ;
18+ private var module : Dynamic ;
19+ private var callbacks : Map <String , String > = new Map ();
20+ private var transformCallbackNames : Bool = true ;
21+
22+ // Initialize Python interpreter
23+ public static function initPython () {
24+ if (pythonInitialized ) return ;
25+
26+ untyped __cpp__ ("
27+ Py_Initialize();
28+ PyEval_InitThreads(); // Initialize and acquire GIL
29+ " );
30+
31+ // Get Python version
32+ untyped __cpp__ ("
33+ char version[128];
34+ snprintf(version, sizeof(version), \" Python %d.%d.%d\" ,
35+ PY_MAJOR_VERSION, PY_MINOR_VERSION, PY_MICRO_VERSION);
36+ " );
37+ pythonVersion = untyped __cpp__ (' version' );
38+
39+ pythonInitialized = true ;
40+ trace (' Python initialized: $pythonVersion ' );
41+ }
42+
43+ // Constructor - Loads Python script
44+ public function new (scriptPath : String , moduleName : String ) {
45+ if (! pythonInitialized ) initPython ();
46+ this .moduleName = moduleName ;
47+
48+ // Execute script in isolated module
49+ var scriptContent = File .getContent (scriptPath );
50+ untyped __cpp__ ('
51+ // Create new module
52+ PyObject *module = PyModule_New("{0}");
53+ PyModule_AddStringConstant(module, "__file__", "{1}");
54+
55+ // Add to sys.modules
56+ PyObject *sys_modules = PyImport_GetModuleDict();
57+ PyDict_SetItemString(sys_modules, "{0}", module);
58+
59+ // Execute script in module context
60+ PyObject *globals = PyModule_GetDict(module);
61+ PyRun_StringFlags(
62+ {2}, Py_file_input,
63+ globals, globals, NULL
64+ );
65+
66+ // Store module reference
67+ {3} = module;
68+ ' , moduleName , scriptPath , scriptContent , cpp. Pointer .addressOf (module ));
69+
70+ // Call main function if exists
71+ if (functionExists (" main" )) {
72+ callFunction (" main" , []);
73+ }
74+ }
75+
76+ // Set callback name transformation (onNoteHit -> on_note_hit)
77+ public function setTransformCallbackNames (transform : Bool ) {
78+ transformCallbackNames = transform ;
79+ }
80+
81+ // Expose Haxe object to Python
82+ public function expose (name : String , obj : Dynamic ) {
83+ var json = Json .stringify (obj );
84+ untyped __cpp__ ('
85+ PyObject *pyObj = PyUnicode_FromString({0});
86+ PyObject *module = {1};
87+ PyObject *dict = PyModule_GetDict(module);
88+ PyDict_SetItemString(dict, {2}, pyObj);
89+ Py_DECREF(pyObj);
90+ ' , json , module , name );
91+ }
92+
93+ // Call Python function
94+ public function callFunction (funcName : String , args : Array <Dynamic >): Dynamic {
95+ if (! functionExists (funcName )) return null ;
96+
97+ var jsonArgs = Json .stringify (args );
98+ var result : Dynamic = null ;
99+
100+ untyped __cpp__ ('
101+ PyGILState_STATE gstate = PyGILState_Ensure();
102+
103+ try {
104+ PyObject *module = {0};
105+ PyObject *func = PyObject_GetAttrString(module, {1});
106+
107+ if (func && PyCallable_Check(func)) {
108+ // Convert Haxe args to Python tuple
109+ PyObject *pyArgs = PyTuple_New({2});
110+ for (int i = 0; i < {2}; i++) {
111+ PyObject *item = PyUnicode_FromString({3}[i]);
112+ PyTuple_SetItem(pyArgs, i, item);
113+ }
114+
115+ // Call function
116+ PyObject *pyResult = PyObject_CallObject(func, pyArgs);
117+
118+ // Convert result to JSON string
119+ if (pyResult) {
120+ PyObject *json = PyObject_CallMethod(pyResult, "__str__", NULL);
121+ {4} = PyUnicode_AsUTF8(json);
122+ Py_DECREF(json);
123+ Py_DECREF(pyResult);
124+ }
125+
126+ Py_DECREF(pyArgs);
127+ Py_DECREF(func);
128+ }
129+ } catch (...) {
130+ PyErr_Print();
131+ }
132+
133+ PyGILState_Release(gstate);
134+ ' , module , funcName , args .length , jsonArgs , cpp. Pointer .addressOf (result ));
135+
136+ try {
137+ return Json .parse (result );
138+ } catch (e : Dynamic ) {
139+ return result ;
140+ }
141+ }
142+
143+ // Register callback handler
144+ public function registerCallback (eventName : String , ? pyFunctionName : String ) {
145+ if (pyFunctionName == null ) {
146+ pyFunctionName = transformCallbackNames ?
147+ StringTools .replace (eventName , " on" , " on_" ).toLowerCase () :
148+ eventName ;
149+ }
150+ callbacks .set (eventName , pyFunctionName );
151+ }
152+
153+ // Trigger callback
154+ public function triggerCallback (eventName : String , args : Array <Dynamic >) {
155+ var funcName = callbacks .get (eventName );
156+ if (funcName != null && functionExists (funcName )) {
157+ callFunction (funcName , args );
158+ }
159+ }
160+
161+ // Check if function exists
162+ public function functionExists (funcName : String ): Bool {
163+ var exists = false ;
164+ untyped __cpp__ ('
165+ PyObject *module = {0};
166+ exists = (PyObject_HasAttrString(module, {1}) == 1;
167+ ' , module , funcName , cpp. Pointer .addressOf (exists ));
168+ return exists ;
169+ }
170+
171+ // Clean up resources
172+ public function destroy () {
173+ untyped __cpp__ ('
174+ PyGILState_STATE gstate = PyGILState_Ensure();
175+ Py_DECREF({0});
176+ PyGILState_Release(gstate);
177+ ' , module );
178+ }
179+ }
180+ #end
0 commit comments