You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2381 lines
78 KiB
2381 lines
78 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, Inc. |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
////////////////////////////////////////////////////////////////////// |
|
// |
|
// PythonInterface - The Python interface to the Python dll |
|
// |
|
// NOTE: Eventually, this will be made into a separate dll, because there should |
|
// only be one instance of this interface. |
|
// |
|
|
|
#include <Python.h> |
|
#include <marshal.h> |
|
#include "pyGeometry3.h" |
|
#include "pyKey.h" |
|
#include "pyMatrix44.h" |
|
#pragma hdrstop |
|
|
|
#include "cyPythonInterface.h" |
|
#include "plPythonPack.h" |
|
|
|
#include "pyEnum.h" |
|
#include "cyDraw.h" |
|
#include "cyParticleSys.h" |
|
#include "cyPhysics.h" |
|
#include "pySceneObject.h" |
|
#include "cyMisc.h" |
|
#include "cyCamera.h" |
|
#include "pyNotify.h" |
|
#include "cyAvatar.h" |
|
#include "pyColor.h" |
|
#include "pyDynamicText.h" |
|
#include "cyAnimation.h" |
|
#include "pyPlayer.h" |
|
#include "pyImage.h" |
|
#include "pyDniCoordinates.h" |
|
#include "cyInputInterface.h" |
|
#include "pySDL.h" |
|
#include "cyAccountManagement.h" |
|
|
|
// GUIDialog and its controls |
|
#include "pyGUIDialog.h" |
|
#include "pyGUIControlButton.h" |
|
#include "pyGUIControlDragBar.h" |
|
#include "pyGUIControlCheckBox.h" |
|
#include "pyGUIControlListBox.h" |
|
#include "pyGUIControlEditBox.h" |
|
#include "pyGUIControlMultiLineEdit.h" |
|
#include "pyGUIControlRadioGroup.h" |
|
#include "pyGUIControlTextBox.h" |
|
#include "pyGUIControlValue.h" |
|
#include "pyGUIControlDynamicText.h" |
|
#include "pyGUIControlClickMap.h" |
|
#include "pyGUIControlDraggable.h" |
|
#include "pyGUIPopUpMenu.h" |
|
#include "pyGUISkin.h" |
|
|
|
#include "plPythonSDLModifier.h" |
|
|
|
// For printing to the log |
|
#include "plStatusLog/plStatusLog.h" |
|
#include "plNetGameLib/plNetGameLib.h" |
|
|
|
// vault |
|
#include "pyVaultNode.h" |
|
#include "pyVaultFolderNode.h" |
|
#include "pyVaultPlayerInfoListNode.h" |
|
#include "pyVaultImageNode.h" |
|
#include "pyVaultTextNoteNode.h" |
|
#include "pyVaultAgeLinkNode.h" |
|
#include "pyVaultChronicleNode.h" |
|
#include "pyVaultPlayerInfoNode.h" |
|
#include "pyVaultAgeInfoNode.h" |
|
#include "pyVaultAgeInfoListNode.h" |
|
#include "pyVaultSDLNode.h" |
|
#include "pyVaultNodeRef.h" |
|
#include "pyVaultMarkerGameNode.h" |
|
#include "pyVaultSystemNode.h" |
|
|
|
// player vault |
|
#include "pyVault.h" |
|
// age vault |
|
#include "pyAgeVault.h" |
|
|
|
// net linking mgr |
|
#include "pyNetLinkingMgr.h" |
|
#include "pyAgeInfoStruct.h" |
|
#include "pyAgeLinkStruct.h" |
|
|
|
// dni info source |
|
#include "pyDniInfoSource.h" |
|
|
|
// audio setting stuff |
|
#include "pyAudioControl.h" |
|
|
|
//CCR stufff |
|
#include "pyCCRMgr.h" |
|
|
|
// spawn point def |
|
#include "pySpawnPointInfo.h" |
|
|
|
#include "pyMarkerMgr.h" |
|
#include "pyStatusLog.h" |
|
|
|
// Guess what this is for :P |
|
#include "pyJournalBook.h" |
|
|
|
#include "pyKeyMap.h" |
|
#include "pyStream.h" |
|
|
|
#include "pyMoviePlayer.h" |
|
#include "pyDrawControl.h" |
|
|
|
#include "pyWaveSet.h" |
|
#include "pySwimCurrentInterface.h" |
|
|
|
#include "pyCluster.h" |
|
#include "pyGrassShader.h" |
|
|
|
#include "pyGameScore.h" |
|
#include "pyGameScoreMsg.h" |
|
|
|
#include "pyCritterBrain.h" |
|
|
|
// Game manager stuff |
|
#include "Games/pyGameMgrMsg.h" |
|
#include "Games/pyGameCliMsg.h" |
|
#include "Games/pyGameCli.h" |
|
#include "Games/TicTacToe/pyTTTMsg.h" |
|
#include "Games/TicTacToe/pyTTTGame.h" |
|
#include "Games/Heek/pyHeekMsg.h" |
|
#include "Games/Heek/pyHeekGame.h" |
|
#include "Games/Marker/pyMarkerMsg.h" |
|
#include "Games/Marker/pyMarkerGame.h" |
|
#include "Games/BlueSpiral/pyBlueSpiralMsg.h" |
|
#include "Games/BlueSpiral/pyBlueSpiralGame.h" |
|
#include "Games/ClimbingWall/pyClimbingWallMsg.h" |
|
#include "Games/ClimbingWall/pyClimbingWallGame.h" |
|
#include "Games/VarSync/pyVarSyncMsg.h" |
|
#include "Games/VarSync/pyVarSyncGame.h" |
|
|
|
int32_t PythonInterface::initialized = 0; // only need to initialize all of Python once |
|
bool PythonInterface::FirstTimeInit = true; // start with "this is the first time" |
|
bool PythonInterface::IsInShutdown = false; // whether we are _really_ in shutdown mode |
|
|
|
PyMethodDef* PythonInterface::plasmaMethods = nil; // the Plasma module's methods |
|
PyObject* PythonInterface::plasmaMod = nil; // pointer to the Plasma module |
|
PyObject* PythonInterface::plasmaConstantsMod = nil; // pointer to the PlasmaConstants module |
|
PyObject* PythonInterface::plasmaNetConstantsMod = nil; // pointer to the PlasmaNetConstants module |
|
PyObject* PythonInterface::plasmaVaultConstantsMod = nil; // pointer to the PlasmaVaultConstants module |
|
PyMethodDef* PythonInterface::plasmaGameMethods = nil; // the PlasmaGame module's methods |
|
PyObject* PythonInterface::plasmaGameMod = nil; // python object that holds the PlasmaGame module |
|
PyObject* PythonInterface::plasmaGameConstantsMod = nil; // python object that holds the PlasmaGameConstants module |
|
PyObject* PythonInterface::stdOut = nil; // python object of the stdout file |
|
PyObject* PythonInterface::stdErr = nil; // python object of the err file |
|
|
|
bool PythonInterface::debug_initialized = false; // has the debug been initialized yet? |
|
PyObject* PythonInterface::dbgMod = nil; // display module for stdout and stderr |
|
PyObject* PythonInterface::dbgOut = nil; |
|
PyObject* PythonInterface::dbgSlice = nil; // time slice function for the debug window |
|
plStatusLog* PythonInterface::dbgLog = nil; // output logfile |
|
|
|
#if defined(HAVE_CYPYTHONIDE) && !defined(PLASMA_EXTERNAL_RELEASE) |
|
bool PythonInterface::usePythonDebugger = false; |
|
plCyDebServer PythonInterface::debugServer; |
|
bool PythonInterface::requestedExit = false; |
|
#endif |
|
|
|
// stupid Windows.h and who started including that! |
|
#undef DrawText |
|
|
|
#if defined(HAVE_CYPYTHONIDE) && !defined(PLASMA_EXTERNAL_RELEASE) |
|
// Special includes for debugging |
|
#include <frameobject.h> |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// Our debugger callback class |
|
class DebuggerCallback: public plCyDebServer::IDebServerCallback |
|
{ |
|
private: |
|
plCyDebServer& fServer; |
|
|
|
PyFrameObject* fFrame; |
|
PyObject* fExceptionInfo; |
|
|
|
std::string IParseCurrentException(); // returns the current exception as a string representation, and clears it |
|
|
|
public: |
|
DebuggerCallback(plCyDebServer& server): fServer(server) {} |
|
|
|
virtual bool MsgReceive(const plCyDebMessage& msg); |
|
virtual std::string AdjustFilename(const std::string& filename); |
|
virtual bool CheckBreakpointCondition(const std::string& condition, std::string& error); |
|
|
|
virtual void InitializeBreak(); |
|
virtual std::vector<std::string> GenerateCallstack(); |
|
virtual std::vector<std::pair<std::string, std::string> > GenerateGlobalsList(); |
|
virtual std::vector<std::pair<std::string, std::string> > GenerateLocalsList(); |
|
virtual std::string EvaluateVariable(const std::string& varName); |
|
virtual void SetVariableValue(const std::string& varName, const std::string& newValue); |
|
|
|
void SetFrame(PyFrameObject* frame) {fFrame = frame;} |
|
void SetExceptionInfo(PyObject* exceptionInfo) {fExceptionInfo = exceptionInfo;} |
|
}; |
|
|
|
std::string DebuggerCallback::IParseCurrentException() |
|
{ |
|
std::string error = ""; |
|
|
|
if (PyErr_Occurred() == NULL) |
|
return error; // no error occurred |
|
|
|
PyObject* errType = NULL; |
|
PyObject* errVal = NULL; |
|
PyObject* errTraceback = NULL; |
|
PyErr_Fetch(&errType, &errVal, &errTraceback); // clears the error flag |
|
PyErr_NormalizeException(&errType, &errVal, &errTraceback); |
|
|
|
if (PyErr_GivenExceptionMatches(errType, PyExc_SyntaxError)) |
|
{ |
|
// we know how to parse out information from syntax errors |
|
PyObject* message; |
|
char* filename = NULL; |
|
int lineNumber = 0; |
|
int offset = 0; |
|
char* text = NULL; |
|
|
|
if (PyTuple_Check(errVal)) |
|
{ |
|
// nested tuple, parse out the error information |
|
PyArg_Parse(errVal, "(O(ziiz))", &message, &filename, &lineNumber, &offset, &text); |
|
error += PyString_AsString(message); |
|
if (text) |
|
error += text; |
|
} |
|
else |
|
{ |
|
// probably just the error class, retrieve the message and text directly |
|
PyObject* v; |
|
if ((v = PyObject_GetAttrString(errVal, "msg"))) |
|
{ |
|
error += PyString_AsString(v); |
|
Py_DECREF(v); |
|
} |
|
if ((v == PyObject_GetAttrString(errVal, "text"))) |
|
{ |
|
if (v != Py_None) |
|
error += PyString_AsString(v); |
|
Py_DECREF(v); |
|
} |
|
} |
|
} |
|
else if (PyClass_Check(errType)) |
|
{ |
|
// otherwise, just return the type of error that occurred |
|
PyClassObject* exc = (PyClassObject*)errType; |
|
PyObject* className = exc->cl_name; |
|
if (className) |
|
error += PyString_AsString(className); |
|
} |
|
else |
|
error = "Unknown Error"; |
|
|
|
// cleanup |
|
Py_XDECREF(errType); |
|
Py_XDECREF(errVal); |
|
Py_XDECREF(errTraceback); |
|
|
|
return error; |
|
} |
|
|
|
bool DebuggerCallback::MsgReceive(const plCyDebMessage& msg) |
|
{ |
|
switch (msg.GetMsgType()) |
|
{ |
|
case plCyDebMessage::kMsgExit: |
|
PythonInterface::DebuggerRequestedExit(true); |
|
break; |
|
} |
|
return false; // let default handling take over |
|
} |
|
|
|
std::string DebuggerCallback::AdjustFilename(const std::string& filename) |
|
{ |
|
// python doesn't deal with paths, so we strip out all path information |
|
std::string retVal = filename; |
|
std::string::size_type slashPos = filename.rfind('\\'); |
|
if (slashPos != std::string::npos) |
|
retVal = filename.substr(slashPos + 1); |
|
else // no back-slashes, look for forward ones |
|
{ |
|
slashPos = filename.rfind('/'); |
|
if (slashPos != std::string::npos) |
|
retVal = filename.substr(slashPos + 1); |
|
} |
|
return retVal; |
|
} |
|
|
|
bool DebuggerCallback::CheckBreakpointCondition(const std::string& condition, std::string& error) |
|
{ |
|
if (!fFrame) |
|
return true; // just break, we have no current frame? |
|
|
|
if (condition == "") |
|
return true; // empty condition, break (python doesn't like empty strings) |
|
|
|
// initialize locals, since InitializeBreak isn't called til we break |
|
PyFrame_FastToLocals(fFrame); |
|
|
|
// run the string in the current context |
|
PyObject* result = PyRun_String(const_cast<char*>(condition.c_str()), Py_eval_input, fFrame->f_globals, fFrame->f_locals); |
|
if (result) |
|
{ |
|
// is the result true? |
|
int retVal = PyObject_IsTrue(result); |
|
Py_DECREF(result); |
|
|
|
return (retVal == 1); |
|
} |
|
|
|
// error occurred, translate it and return |
|
error = IParseCurrentException(); |
|
return true; |
|
} |
|
|
|
void DebuggerCallback::InitializeBreak() |
|
{ |
|
// do a little initialization of our frame (ensuring we get all local data) |
|
PyFrame_FastToLocals(fFrame); |
|
} |
|
|
|
std::vector<std::string> DebuggerCallback::GenerateCallstack() |
|
{ |
|
std::vector<std::string> retVal; |
|
|
|
// we use the frame stored for us by the trace function |
|
PyFrameObject* curFrame = fFrame; |
|
while (curFrame) |
|
{ |
|
std::string filename = PyString_AsString(curFrame->f_code->co_filename); |
|
int lineNumber = PyCode_Addr2Line(curFrame->f_code, curFrame->f_lasti); // python uses base-1 numbering, we use base-0, but for display we want base-1 |
|
std::string functionName = PyString_AsString(curFrame->f_code->co_name); |
|
|
|
functionName += "("; |
|
if (curFrame->f_code->co_argcount) |
|
{ |
|
// we have arguments! |
|
int argCount = __min(PyTuple_Size(curFrame->f_code->co_varnames), curFrame->f_code->co_argcount); |
|
|
|
for (int curArg = 0; curArg < argCount; ++curArg) |
|
{ |
|
PyObject* argName = PyTuple_GetItem(curFrame->f_code->co_varnames, curArg); |
|
if (argName) |
|
{ |
|
std::string arg = PyString_AsString(argName); |
|
if (arg == "self") |
|
continue; // skip self, for readability |
|
|
|
functionName += arg; |
|
|
|
if (curFrame->f_locals) |
|
{ |
|
// grab value, if our locals dictionary exists |
|
PyObject* val = PyDict_GetItemString(curFrame->f_locals, arg.c_str()); |
|
if (val) |
|
{ |
|
functionName += "="; |
|
functionName += PyString_AsString(PyObject_Str(val)); |
|
} |
|
} |
|
} |
|
|
|
if (curArg < argCount - 1) |
|
functionName += ", "; |
|
} |
|
} |
|
functionName += ")"; |
|
|
|
// add it to the callstack |
|
retVal.push_back(fServer.ConstructCallstackLine(filename, lineNumber, functionName)); |
|
|
|
// and step back one frame |
|
curFrame = curFrame->f_back; |
|
} |
|
|
|
return retVal; |
|
} |
|
|
|
std::vector<std::pair<std::string, std::string> > DebuggerCallback::GenerateGlobalsList() |
|
{ |
|
std::vector<std::pair<std::string, std::string> > retVal; |
|
if (fFrame && fFrame->f_globals) |
|
{ |
|
int pos = 0; |
|
PyObject* key; |
|
PyObject* value; |
|
while (PyDict_Next(fFrame->f_globals, &pos, &key, &value)) |
|
{ |
|
// leave modules out of the globals display |
|
if (key && value && !PyModule_Check(value)) |
|
{ |
|
// leave out glue functions |
|
if (PyObject_Compare((PyObject*)&PyCFunction_Type, PyObject_Type(value)) == 0) |
|
continue; |
|
|
|
std::string keyStr = PyString_AsString(PyObject_Str(key)); |
|
if (keyStr == "__builtins__") |
|
continue; // skip builtins |
|
|
|
bool addQuotes = (PyString_Check(value) || PyUnicode_Check(value)); |
|
|
|
std::string valueStr = ""; |
|
if (addQuotes) |
|
valueStr += "\""; |
|
valueStr += PyString_AsString(PyObject_Str(value)); |
|
if (addQuotes) |
|
valueStr += "\""; |
|
|
|
// add it to the list of pairs |
|
retVal.push_back(std::pair<std::string, std::string>(keyStr, valueStr)); |
|
} |
|
} |
|
} |
|
return retVal; |
|
} |
|
|
|
std::vector<std::pair<std::string, std::string> > DebuggerCallback::GenerateLocalsList() |
|
{ |
|
std::vector<std::pair<std::string, std::string> > retVal; |
|
if (fFrame && fFrame->f_locals) |
|
{ |
|
int pos = 0; |
|
PyObject* key; |
|
PyObject* value; |
|
while (PyDict_Next(fFrame->f_locals, &pos, &key, &value)) |
|
{ |
|
// leave modules and instances out of the globals display |
|
if (key && value && !PyModule_Check(value) && !PyInstance_Check(value)) |
|
{ |
|
// leave out functions, classes, and types |
|
if (PyObject_Compare((PyObject*)&PyFunction_Type, PyObject_Type(value)) == 0) |
|
continue; |
|
if (PyObject_Compare((PyObject*)&PyClass_Type, PyObject_Type(value)) == 0) |
|
continue; |
|
if (PyObject_Compare((PyObject*)&PyType_Type, PyObject_Type(value)) == 0) |
|
continue; |
|
|
|
std::string keyStr = PyString_AsString(PyObject_Str(key)); |
|
if (keyStr == "__builtins__") |
|
continue; // skip builtins |
|
|
|
bool addQuotes = (PyString_Check(value) || PyUnicode_Check(value)); |
|
|
|
std::string valueStr = ""; |
|
if (addQuotes) |
|
valueStr += "\""; |
|
valueStr += PyString_AsString(PyObject_Str(value)); |
|
if (addQuotes) |
|
valueStr += "\""; |
|
|
|
// add it to the list of pairs |
|
retVal.push_back(std::pair<std::string, std::string>(keyStr, valueStr)); |
|
} |
|
} |
|
} |
|
return retVal; |
|
} |
|
|
|
std::string DebuggerCallback::EvaluateVariable(const std::string& varName) |
|
{ |
|
if (fFrame) |
|
{ |
|
PyObject* evalResult = PyRun_String(const_cast<char*>(varName.c_str()), Py_eval_input, fFrame->f_globals, fFrame->f_locals); |
|
std::string retVal = ""; |
|
if (evalResult) |
|
{ |
|
// convert the result to something readable |
|
PyObject* reprObj = PyObject_Repr(evalResult); |
|
if (reprObj) |
|
retVal = PyString_AsString(reprObj); |
|
else |
|
retVal = "<REPR FAIL>"; |
|
Py_XDECREF(reprObj); |
|
} |
|
else |
|
retVal = IParseCurrentException(); |
|
Py_XDECREF(evalResult); |
|
return retVal; |
|
} |
|
else |
|
return "<NO FRAME>"; |
|
} |
|
|
|
void DebuggerCallback::SetVariableValue(const std::string& varName, const std::string& newValue) |
|
{ |
|
std::string expression = varName + "=" + newValue; |
|
if (fFrame) |
|
{ |
|
PyObject* evalResult = PyRun_String(const_cast<char*>(expression.c_str()), Py_single_input, fFrame->f_globals, fFrame->f_locals); |
|
if (evalResult) |
|
PyFrame_LocalsToFast(fFrame, 0); // convert the locals that changed (if any) back to "fast" locals |
|
else |
|
PyErr_Print(); |
|
Py_XDECREF(evalResult); |
|
} |
|
} |
|
|
|
DebuggerCallback debServerCallback(*PythonInterface::PythonDebugger()); |
|
|
|
// python trace function, handles most of the work required for debugging |
|
static int PythonTraceCallback(PyObject*, PyFrameObject* frame, int what, PyObject* arg) |
|
{ |
|
// obj (first parameter) is always NULL for is (it's the parameter passed by the set trace function) |
|
|
|
// update the callback class' stored values |
|
debServerCallback.SetFrame(frame); |
|
debServerCallback.SetExceptionInfo(NULL); |
|
|
|
// translate the python what value to the debugger what value |
|
plCyDebServer::TraceWhat debuggerWhat; |
|
switch (what) |
|
{ |
|
case PyTrace_LINE: |
|
debuggerWhat = plCyDebServer::kTraceLine; |
|
break; |
|
|
|
case PyTrace_CALL: |
|
debuggerWhat = plCyDebServer::kTraceCall; |
|
break; |
|
|
|
case PyTrace_RETURN: |
|
debuggerWhat = plCyDebServer::kTraceReturn; |
|
break; |
|
|
|
case PyTrace_EXCEPTION: |
|
debuggerWhat = plCyDebServer::kTraceException; |
|
debServerCallback.SetExceptionInfo(arg); // save off the exception information |
|
break; |
|
|
|
default: |
|
assert(!"Invalid what for python trace function"); |
|
return 0; // pretty much ignore if they pass us a bad value |
|
} |
|
|
|
std::string filename = PyString_AsString(frame->f_code->co_filename); |
|
int line = PyCode_Addr2Line(frame->f_code, frame->f_lasti) - 1; // python uses base-1 numbering, we use base-0 |
|
|
|
// now handle the trace call |
|
PythonInterface::PythonDebugger()->Trace(debuggerWhat, filename, line, frame->f_tstate->recursion_depth); |
|
|
|
return 0; |
|
} |
|
#endif // PLASMA_EXTERNAL_RELEASE |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// A small class that is bound to python so we can redirect stdout |
|
|
|
class pyOutputRedirector |
|
{ |
|
private: |
|
std::string fData; |
|
static bool fTypeCreated; |
|
|
|
protected: |
|
pyOutputRedirector() {} |
|
|
|
public: |
|
// required functions for PyObject interoperability |
|
PYTHON_CLASS_NEW_FRIEND(ptOutputRedirector); |
|
PYTHON_CLASS_NEW_DEFINITION; |
|
PYTHON_CLASS_CHECK_DEFINITION; // returns true if the PyObject is a pyOutputRedirector object |
|
PYTHON_CLASS_CONVERT_FROM_DEFINITION(pyOutputRedirector); // converts a PyObject to a pyOutputRedirector (throws error if not correct type) |
|
|
|
void Write(std::string data) {fData += data;} |
|
void Write(std::wstring data) |
|
{ |
|
char* strData = hsWStringToString(data.c_str()); |
|
Write(strData); |
|
delete [] strData; |
|
} |
|
|
|
// accessor functions for the PyObject* |
|
|
|
// returns the current data stored |
|
static std::string GetData(PyObject *redirector) |
|
{ |
|
if (!pyOutputRedirector::Check(redirector)) |
|
return ""; // it's not a redirector object |
|
pyOutputRedirector *obj = pyOutputRedirector::ConvertFrom(redirector); |
|
return obj->fData; |
|
} |
|
|
|
// clears the internal buffer out |
|
static void ClearData(PyObject *redirector) |
|
{ |
|
if (!pyOutputRedirector::Check(redirector)) |
|
return; // it's not a redirector object |
|
pyOutputRedirector *obj = pyOutputRedirector::ConvertFrom(redirector); |
|
obj->fData = ""; |
|
} |
|
}; |
|
|
|
bool pyOutputRedirector::fTypeCreated = false; |
|
|
|
// Now for the glue for the redirector |
|
PYTHON_CLASS_DEFINITION(ptOutputRedirector, pyOutputRedirector); |
|
|
|
PYTHON_DEFAULT_NEW_DEFINITION(ptOutputRedirector, pyOutputRedirector) |
|
PYTHON_DEFAULT_DEALLOC_DEFINITION(ptOutputRedirector) |
|
|
|
PYTHON_INIT_DEFINITION(ptOutputRedirector, args, keywords) |
|
{ |
|
PYTHON_RETURN_INIT_OK; |
|
} |
|
|
|
PYTHON_METHOD_DEFINITION(ptOutputRedirector, write, args) |
|
{ |
|
PyObject* textObj; |
|
if (!PyArg_ParseTuple(args, "O", &textObj)) |
|
{ |
|
PyErr_SetString(PyExc_TypeError, "write expects a string or unicode string"); |
|
PYTHON_RETURN_ERROR; |
|
} |
|
if (PyUnicode_Check(textObj)) |
|
{ |
|
int strLen = PyUnicode_GetSize(textObj); |
|
wchar_t* text = new wchar_t[strLen + 1]; |
|
PyUnicode_AsWideChar((PyUnicodeObject*)textObj, text, strLen); |
|
text[strLen] = L'\0'; |
|
self->fThis->Write(text); |
|
delete [] text; |
|
PYTHON_RETURN_NONE; |
|
} |
|
else if (PyString_Check(textObj)) |
|
{ |
|
char* text = PyString_AsString(textObj); |
|
self->fThis->Write(text); |
|
PYTHON_RETURN_NONE; |
|
} |
|
PyErr_SetString(PyExc_TypeError, "write expects a string or unicode string"); |
|
PYTHON_RETURN_ERROR; |
|
} |
|
|
|
PYTHON_START_METHODS_TABLE(ptOutputRedirector) |
|
PYTHON_METHOD(ptOutputRedirector, write, "Adds text to the output object"), |
|
PYTHON_END_METHODS_TABLE; |
|
|
|
// Type structure definition |
|
PLASMA_DEFAULT_TYPE(ptOutputRedirector, "A class that is used to redirect stdout and stderr"); |
|
|
|
// required functions for PyObject interoperability |
|
PyObject *pyOutputRedirector::New() |
|
{ |
|
if (!fTypeCreated) |
|
{ |
|
if (PyType_Ready(&ptOutputRedirector_type) < 0) |
|
return NULL; |
|
fTypeCreated = true; |
|
} |
|
ptOutputRedirector *newObj = (ptOutputRedirector*)ptOutputRedirector_type.tp_new(&ptOutputRedirector_type, NULL, NULL); |
|
return (PyObject*)newObj; |
|
} |
|
|
|
PYTHON_CLASS_CHECK_IMPL(ptOutputRedirector, pyOutputRedirector) |
|
PYTHON_CLASS_CONVERT_FROM_IMPL(ptOutputRedirector, pyOutputRedirector) |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// A small class that is bound to python so we can redirect stderr |
|
|
|
class pyErrorRedirector |
|
{ |
|
private: |
|
static bool fTypeCreated; |
|
|
|
std::string fData; |
|
bool fLog; |
|
|
|
protected: |
|
pyErrorRedirector() : fLog(true) {} |
|
|
|
public: |
|
// required functions for PyObject interoperability |
|
PYTHON_CLASS_NEW_FRIEND(ptErrorRedirector); |
|
PYTHON_CLASS_NEW_DEFINITION; |
|
PYTHON_CLASS_CHECK_DEFINITION; // returns true if the PyObject is a pyOutputRedirector object |
|
PYTHON_CLASS_CONVERT_FROM_DEFINITION(pyErrorRedirector); // converts a PyObject to a pyOutputRedirector (throws error if not correct type) |
|
|
|
void SetLogging(bool log) |
|
{ |
|
fLog = log; |
|
} |
|
|
|
void Write(std::string data) |
|
{ |
|
PyObject* stdOut = PythonInterface::GetStdOut(); |
|
|
|
if (stdOut && pyOutputRedirector::Check(stdOut)) |
|
{ |
|
pyOutputRedirector *obj = pyOutputRedirector::ConvertFrom(stdOut); |
|
obj->Write(data); |
|
} |
|
|
|
if (fLog) |
|
fData += data; |
|
} |
|
|
|
void Write(std::wstring data) |
|
{ |
|
char* strData = hsWStringToString(data.c_str()); |
|
Write(strData); |
|
delete [] strData; |
|
} |
|
|
|
void ExceptHook(PyObject* except, PyObject* val, PyObject* tb) |
|
{ |
|
PyErr_Display(except, val, tb); |
|
|
|
// Send to the log server |
|
wchar_t* wdata = hsStringToWString(fData.c_str()); |
|
NetCliAuthLogPythonTraceback(wdata); |
|
delete [] wdata; |
|
|
|
if (fLog) |
|
fData.clear(); |
|
} |
|
}; |
|
|
|
bool pyErrorRedirector::fTypeCreated = false; |
|
|
|
// Now for the glue for the redirector |
|
PYTHON_CLASS_DEFINITION(ptErrorRedirector, pyErrorRedirector); |
|
|
|
PYTHON_DEFAULT_NEW_DEFINITION(ptErrorRedirector, pyErrorRedirector) |
|
PYTHON_DEFAULT_DEALLOC_DEFINITION(ptErrorRedirector) |
|
|
|
PYTHON_INIT_DEFINITION(ptErrorRedirector, args, keywords) |
|
{ |
|
PYTHON_RETURN_INIT_OK; |
|
} |
|
|
|
PYTHON_METHOD_DEFINITION(ptErrorRedirector, write, args) |
|
{ |
|
PyObject* textObj; |
|
if (!PyArg_ParseTuple(args, "O", &textObj)) |
|
{ |
|
PyErr_SetString(PyExc_TypeError, "write expects a string or unicode string"); |
|
PYTHON_RETURN_ERROR; |
|
} |
|
if (PyUnicode_Check(textObj)) |
|
{ |
|
int strLen = PyUnicode_GetSize(textObj); |
|
wchar_t* text = new wchar_t[strLen + 1]; |
|
PyUnicode_AsWideChar((PyUnicodeObject*)textObj, text, strLen); |
|
text[strLen] = L'\0'; |
|
self->fThis->Write(text); |
|
delete [] text; |
|
PYTHON_RETURN_NONE; |
|
} |
|
else if (PyString_Check(textObj)) |
|
{ |
|
char* text = PyString_AsString(textObj); |
|
self->fThis->Write(text); |
|
PYTHON_RETURN_NONE; |
|
} |
|
PyErr_SetString(PyExc_TypeError, "write expects a string or unicode string"); |
|
PYTHON_RETURN_ERROR; |
|
} |
|
|
|
PYTHON_METHOD_DEFINITION(ptErrorRedirector, excepthook, args) |
|
{ |
|
PyObject *exc, *value, *tb; |
|
if (!PyArg_ParseTuple(args, "OOO", &exc, &value, &tb)) |
|
PYTHON_RETURN_ERROR; |
|
|
|
self->fThis->ExceptHook(exc, value, tb); |
|
|
|
PYTHON_RETURN_NONE; |
|
} |
|
|
|
PYTHON_START_METHODS_TABLE(ptErrorRedirector) |
|
PYTHON_METHOD(ptErrorRedirector, write, "Adds text to the output object"), |
|
PYTHON_METHOD(ptErrorRedirector, excepthook, "Handles exceptions"), |
|
PYTHON_END_METHODS_TABLE; |
|
|
|
// Type structure definition |
|
PLASMA_DEFAULT_TYPE(ptErrorRedirector, "A class that is used to redirect stdout and stderr"); |
|
|
|
// required functions for PyObject interoperability |
|
PyObject *pyErrorRedirector::New() |
|
{ |
|
if (!fTypeCreated) |
|
{ |
|
if (PyType_Ready(&ptErrorRedirector_type) < 0) |
|
return NULL; |
|
fTypeCreated = true; |
|
} |
|
ptErrorRedirector *newObj = (ptErrorRedirector*)ptErrorRedirector_type.tp_new(&ptErrorRedirector_type, NULL, NULL); |
|
return (PyObject*)newObj; |
|
} |
|
|
|
PYTHON_CLASS_CHECK_IMPL(ptErrorRedirector, pyErrorRedirector) |
|
PYTHON_CLASS_CONVERT_FROM_IMPL(ptErrorRedirector, pyErrorRedirector) |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// PEP 302 Import Hook |
|
///////////////////////////////////////////////////////////////////////////// |
|
#ifndef BUILDING_PYPLASMA |
|
struct ptImportHook |
|
{ |
|
PyObject_HEAD |
|
}; |
|
|
|
// First three functions are just so I can be lazy |
|
// and use the already existing macros to do my dirty |
|
// work. I'm seriously lazy. |
|
|
|
static PyObject* ptImportHook_new(PyTypeObject* type, PyObject* args, PyObject*) |
|
{ |
|
ptImportHook* self = (ptImportHook*)type->tp_alloc(type, 0); |
|
return (PyObject*)self; |
|
} |
|
|
|
PYTHON_NO_INIT_DEFINITION(ptImportHook) |
|
|
|
static void ptImportHook_dealloc(ptImportHook *self) |
|
{ |
|
self->ob_type->tp_free((PyObject*)self); |
|
} |
|
|
|
PYTHON_METHOD_DEFINITION(ptImportHook, find_module, args) |
|
{ |
|
char* module_name; |
|
PyObject* module_path; |
|
|
|
if (!PyArg_ParseTuple(args, "s|O", &module_name, &module_path)) |
|
{ |
|
PyErr_SetString(PyExc_TypeError, "find_module expects string, string"); |
|
PYTHON_RETURN_ERROR; |
|
} |
|
|
|
// If this is set, we can't do it. |
|
if (PyString_Check(module_path)) |
|
PYTHON_RETURN_NONE; |
|
|
|
std::string package_module_name = module_name; |
|
package_module_name += ".__init__"; |
|
if (PythonPack::IsItPythonPacked(module_name)) |
|
{ |
|
Py_INCREF(self); |
|
return (PyObject*)self; |
|
} else if (PythonPack::IsItPythonPacked(package_module_name.c_str())) |
|
{ |
|
Py_INCREF(self); |
|
return (PyObject*)self; |
|
} |
|
else |
|
PYTHON_RETURN_NONE; |
|
} |
|
|
|
PyObject *ptImportHook_load_module_detail(ptImportHook *self, char* module_name, char* packed_name, bool isPackage, bool& found) |
|
{ |
|
// We want to check sys.modules for the module first |
|
// If it's not in there, we have to load the module |
|
// and add it to the sys.modules dict for future reference, |
|
// otherwise reload() will not work properly. |
|
PyObject* result = nil; |
|
PyObject* modules = PyImport_GetModuleDict(); |
|
hsAssert(PyDict_Check(modules), "sys.modules is not a dict"); |
|
|
|
if (result = PyDict_GetItemString(modules, module_name)) |
|
{ |
|
if (!PyModule_Check(result)) |
|
{ |
|
hsAssert(false, "PEP 302 hook found module in sys.modules, but it isn't a module! O.o"); |
|
result = nil; |
|
PyErr_SetString(PyExc_TypeError, "module in sys.modules isn't a module"); |
|
} |
|
} |
|
else |
|
{ |
|
if (PyObject* pyc = PythonPack::OpenPythonPacked(packed_name)) |
|
{ |
|
result = PyImport_AddModule(module_name); |
|
if(!result) |
|
return nil; |
|
PyObject* d = PyModule_GetDict(result); |
|
PyDict_SetItemString(d, "__builtins__", PyEval_GetBuiltins()); |
|
PyObject *file = PyString_FromString(packed_name); |
|
PyModule_AddObject(result, "__file__", file); |
|
PyDict_SetItemString(d, "__loader__", (PyObject*)self); |
|
if(isPackage) { |
|
PyObject *path = PyString_FromString(module_name); |
|
PyObject *l = PyList_New(1); |
|
PyList_SetItem(l, 0, path); |
|
PyDict_SetItemString(d, "__path__", l); |
|
Py_DECREF(l); |
|
} |
|
PyObject* v = PyEval_EvalCode((PyCodeObject *)pyc, d, d); |
|
if(!v) |
|
{ |
|
PyDict_DelItemString(modules, module_name); |
|
return nil; |
|
} |
|
Py_INCREF(result); |
|
} |
|
else { |
|
found = false; |
|
PyErr_SetString(PyExc_ImportError, "module not found in python.pak"); |
|
} |
|
} |
|
|
|
return result; |
|
} |
|
|
|
PYTHON_METHOD_DEFINITION(ptImportHook, load_module, args) |
|
{ |
|
char* module_name; |
|
if (!PyArg_ParseTuple(args, "s", &module_name)) |
|
{ |
|
PyErr_SetString(PyExc_TypeError, "load_module expects string"); |
|
PYTHON_RETURN_ERROR; |
|
} |
|
bool found = true; |
|
PyObject *result = ptImportHook_load_module_detail(self, module_name, module_name, false, found); |
|
if (!found) |
|
{ |
|
PyErr_Clear(); |
|
std::string package_module_name = module_name; |
|
package_module_name += ".__init__"; |
|
result = ptImportHook_load_module_detail(self, module_name, (char*)package_module_name.c_str(), true, found); |
|
} |
|
return result; |
|
} |
|
|
|
PYTHON_START_METHODS_TABLE(ptImportHook) |
|
PYTHON_METHOD(ptImportHook, find_module, "Params: module_name,package_path\nChecks to see if a given module exists (NOTE: package_path is not used!)"), |
|
PYTHON_METHOD(ptImportHook, load_module, "Params: module_name \\nReturns the module given by module_name, if it exists in python.pak"), |
|
PYTHON_END_METHODS_TABLE; |
|
|
|
PYTHON_TYPE_START(ptImportHook) |
|
0, |
|
"Plasma.ptImportHook", |
|
sizeof(ptImportHook), /* tp_basicsize */ |
|
0, /* tp_itemsize */ |
|
(destructor)ptImportHook_dealloc, /* tp_dealloc */ |
|
0, /* tp_print */ |
|
0, /* tp_getattr */ |
|
0, /* tp_setattr */ |
|
0, /* tp_compare */ |
|
0, /* tp_repr */ |
|
0, /* tp_as_number */ |
|
0, /* tp_as_sequence */ |
|
0, /* tp_as_mapping */ |
|
0, /* tp_hash */ |
|
0, /* tp_call */ |
|
0, /* tp_str */ |
|
0, /* tp_getattro */ |
|
0, /* tp_setattro */ |
|
0, /* tp_as_buffer */ |
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
|
"PEP 302 Import Hook", /* tp_doc */ |
|
0, /* tp_traverse */ |
|
0, /* tp_clear */ |
|
0, /* tp_richcompare */ |
|
0, /* tp_weaklistoffset */ |
|
0, /* tp_iter */ |
|
0, /* tp_iternext */ |
|
PYTHON_DEFAULT_METHODS_TABLE(ptImportHook), /* tp_methods */ |
|
0, /* tp_members */ |
|
0, /* tp_getset */ |
|
0, /* tp_base */ |
|
0, /* tp_dict */ |
|
0, /* tp_descr_get */ |
|
0, /* tp_descr_set */ |
|
0, /* tp_dictoffset */ |
|
PYTHON_DEFAULT_INIT(ptImportHook), /* tp_init */ |
|
0, /* tp_alloc */ |
|
ptImportHook_new /* tp_new */ |
|
PYTHON_TYPE_END; |
|
|
|
void ptImportHook_AddPlasmaClasses(PyObject* m) |
|
{ |
|
PYTHON_CLASS_IMPORT_START(m); |
|
PYTHON_CLASS_IMPORT(m, ptImportHook); |
|
PYTHON_CLASS_IMPORT_END(m); |
|
} |
|
#endif // BUILDING_PYPLASMA |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : initPython |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : Initialize the Python dll |
|
// |
|
void PythonInterface::initPython() |
|
{ |
|
// if haven't been initialized then do it |
|
if ( FirstTimeInit && Py_IsInitialized() == 0 ) |
|
{ |
|
FirstTimeInit = false; |
|
// initialize the Python stuff |
|
// let Python do some initialization... |
|
Py_SetProgramName("plasma"); |
|
Py_NoSiteFlag = 1; |
|
Py_IgnoreEnvironmentFlag = 1; |
|
Py_Initialize(); |
|
|
|
#if defined(HAVE_CYPYTHONIDE) && !defined(PLASMA_EXTERNAL_RELEASE) |
|
if (usePythonDebugger) |
|
{ |
|
debugServer.SetCallbackClass(&debServerCallback); |
|
debugServer.Init(); |
|
PyEval_SetTrace((Py_tracefunc)PythonTraceCallback, NULL); |
|
} |
|
#endif |
|
|
|
if (!dbgLog) |
|
{ |
|
dbgLog = plStatusLogMgr::GetInstance().CreateStatusLog( 30, "Python.log", |
|
plStatusLog::kFilledBackground | plStatusLog::kAlignToTop | plStatusLog::kTimestamp ); |
|
} |
|
|
|
// create the output redirector for the stdout and stderr file |
|
stdOut = pyOutputRedirector::New(); |
|
stdErr = pyErrorRedirector::New(); |
|
|
|
// if we need the builtins then find the builtin module |
|
PyObject* sysmod = PyImport_ImportModule("sys"); |
|
// then add the builtin dictionary to our module's dictionary |
|
// get the sys's dictionary to find the stdout and stderr |
|
PyObject* sys_dict = PyModule_GetDict(sysmod); |
|
Py_INCREF(sys_dict); |
|
if (stdOut != nil) |
|
{ |
|
if (PyDict_SetItemString(sys_dict,"stdout", stdOut)) |
|
dbgLog->AddLine("Could not redirect stdout, Python output may not appear in the log\n"); |
|
} |
|
else |
|
dbgLog->AddLine("Could not create python redirector, Python output will not appear in the log\n"); |
|
|
|
if (stdErr != nil) |
|
{ |
|
if (!PyDict_SetItemString(sys_dict,"stderr", stdErr)) |
|
{ |
|
bool dontLog = false; |
|
|
|
// Find the excepthook |
|
PyObject* stdErrExceptHook = PyObject_GetAttrString(stdErr, "excepthook"); |
|
if (stdErrExceptHook) |
|
{ |
|
if (!PyCallable_Check(stdErrExceptHook) || PyDict_SetItemString(sys_dict,"excepthook", stdErrExceptHook)) |
|
{ |
|
dbgLog->AddLine("Could not redirect excepthook, Python error output will not get to the log server\n"); |
|
dontLog = true; |
|
} |
|
Py_DECREF(stdErrExceptHook); |
|
} |
|
else |
|
{ |
|
dbgLog->AddLine("Could not find stdErr excepthook, Python error output will not get to the log server\n"); |
|
dontLog = true; |
|
} |
|
|
|
if (dontLog) |
|
{ |
|
if (pyErrorRedirector::Check(stdErr)) |
|
{ |
|
pyErrorRedirector* redir = pyErrorRedirector::ConvertFrom(stdErr); |
|
redir->SetLogging(false); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
dbgLog->AddLine("Could not redirect stderr, Python error output may not appear in the log or on the log server\n"); |
|
} |
|
} |
|
else |
|
{ |
|
dbgLog->AddLine("Could not create python redirector, Python error output will not appear in the log\n"); |
|
} |
|
|
|
// NOTE: we will reset the path to not include paths |
|
// that Python may have found in the registry |
|
PyObject* path_list = PyList_New(3); |
|
if (PyList_SetItem(path_list, 0, PyString_FromString(".\\python"))) |
|
{ |
|
Py_DECREF(sys_dict); |
|
Py_DECREF(path_list); |
|
dbgLog->AddLine("Error while creating python path:\n"); |
|
getOutputAndReset(); |
|
return; |
|
} |
|
// make sure that our plasma libraries are gotten before the system ones |
|
if (PyList_SetItem(path_list, 1, PyString_FromString(".\\python\\plasma"))) |
|
{ |
|
Py_DECREF(sys_dict); |
|
Py_DECREF(path_list); |
|
dbgLog->AddLine("Error while creating python path:\n"); |
|
getOutputAndReset(); |
|
return; |
|
} |
|
if (PyList_SetItem(path_list, 2, PyString_FromString(".\\python\\system"))) |
|
{ |
|
Py_DECREF(sys_dict); |
|
Py_DECREF(path_list); |
|
dbgLog->AddLine("Error while creating python path:\n"); |
|
getOutputAndReset(); |
|
return; |
|
} |
|
|
|
// set the path to be this one |
|
if (PyDict_SetItemString(sys_dict,"path",path_list)) |
|
{ |
|
Py_DECREF(sys_dict); |
|
Py_DECREF(path_list); |
|
dbgLog->AddLine("Error while setting python path:\n"); |
|
getOutputAndReset(); |
|
return; |
|
} |
|
|
|
Py_DECREF(path_list); |
|
|
|
std::vector<PyMethodDef> methods; // this is temporary, for easy addition of new methods |
|
AddPlasmaMethods(methods); |
|
|
|
// now copy the data to our real method definition structure |
|
plasmaMethods = new PyMethodDef[methods.size() + 1]; |
|
for (int curMethod = 0; curMethod < methods.size(); curMethod++) |
|
plasmaMethods[curMethod] = methods[curMethod]; |
|
PyMethodDef terminator = {NULL}; |
|
plasmaMethods[methods.size()] = terminator; // add the terminator |
|
|
|
// now set up the module with the method data |
|
plasmaMod = Py_InitModule("Plasma", plasmaMethods); |
|
if (plasmaMod == NULL) |
|
{ |
|
dbgLog->AddLine("Could not setup the Plasma module\n"); |
|
return; |
|
} |
|
if (PyErr_Occurred()) |
|
{ |
|
dbgLog->AddLine("Python error while setting up Plasma:\n"); |
|
getOutputAndReset(); |
|
} |
|
Py_INCREF(plasmaMod); // make sure python doesn't get rid of it |
|
|
|
AddPlasmaClasses(); // now add the classes to the module |
|
if (PyErr_Occurred()) |
|
{ |
|
dbgLog->AddLine("Python error while adding classes to Plasma:\n"); |
|
std::string error; |
|
getOutputAndReset(&error); |
|
} |
|
|
|
#ifndef BUILDING_PYPLASMA |
|
// Begin PEP 302 Import Hook stuff |
|
// We need to create a ptImportHook object |
|
ptImportHook* hook = PyObject_New(ptImportHook, &ptImportHook_type); |
|
PyObject* metapath = PyDict_GetItemString(sys_dict, "meta_path"); |
|
Py_INCREF(metapath); |
|
|
|
// Since PEP 302 is insane, let's be sure things are the way |
|
// that we expect them to be. Silent failures != cool. |
|
hsAssert(metapath != nil, "PEP 302: sys.__dict__['meta_path'] missing!"); |
|
hsAssert(PyList_Check(metapath), "PEP 302: sys.__dict__['meta_path'] is not a list!"); |
|
|
|
// Now that we have meta_path, add our hook to the list |
|
PyList_Append(metapath, (PyObject*)hook); |
|
Py_DECREF(metapath); |
|
// And we're done! |
|
#endif // BUILDING_PYPLASMA |
|
|
|
Py_DECREF(sys_dict); |
|
|
|
// initialize the PlasmaConstants module |
|
PyMethodDef noMethods = {NULL}; |
|
plasmaConstantsMod = Py_InitModule("PlasmaConstants", &noMethods); // it has no methods, just values |
|
if (plasmaConstantsMod == NULL) |
|
{ |
|
dbgLog->AddLine("Could not setup the PlasmaConstants module\n"); |
|
return; |
|
} |
|
if (PyErr_Occurred()) |
|
{ |
|
dbgLog->AddLine("Python error while setting up PlasmaConstants:\n"); |
|
std::string error; |
|
getOutputAndReset(&error); |
|
} |
|
Py_INCREF(plasmaConstantsMod); |
|
|
|
AddPlasmaConstantsClasses(); |
|
|
|
if (PyErr_Occurred()) |
|
{ |
|
dbgLog->AddLine("Python error while adding classes to PlasmaConstants:\n"); |
|
std::string error; |
|
getOutputAndReset(&error); |
|
} |
|
|
|
// initialize the PlasmaNetConstants module |
|
plasmaNetConstantsMod = Py_InitModule("PlasmaNetConstants", &noMethods); // it has no methods, just values |
|
if (plasmaNetConstantsMod == NULL) |
|
{ |
|
dbgLog->AddLine("Could not setup the PlasmaNetConstants module\n"); |
|
return; |
|
} |
|
if (PyErr_Occurred()) |
|
{ |
|
dbgLog->AddLine("Python error while setting up PlasmaNetConstants:\n"); |
|
std::string error; |
|
getOutputAndReset(&error); |
|
} |
|
Py_INCREF(plasmaNetConstantsMod); |
|
|
|
AddPlasmaNetConstantsClasses(); |
|
|
|
if (PyErr_Occurred()) |
|
{ |
|
dbgLog->AddLine("Python error while adding classes to PlasmaNetConstants:\n"); |
|
std::string error; |
|
getOutputAndReset(&error); |
|
} |
|
|
|
// initialize the PlasmaVaultConstants module |
|
plasmaVaultConstantsMod = Py_InitModule("PlasmaVaultConstants", &noMethods); // it has no methods, just values |
|
if (plasmaVaultConstantsMod == NULL) |
|
{ |
|
dbgLog->AddLine("Could not setup the PlasmaVaultConstants module\n"); |
|
return; |
|
} |
|
if (PyErr_Occurred()) |
|
{ |
|
dbgLog->AddLine("Python error while setting up PlasmaVaultConstants:\n"); |
|
std::string error; |
|
getOutputAndReset(&error); |
|
} |
|
Py_INCREF(plasmaVaultConstantsMod); |
|
|
|
AddPlasmaVaultConstantsClasses(); |
|
|
|
if (PyErr_Occurred()) |
|
{ |
|
dbgLog->AddLine("Python error while adding classes to PlasmaVaultConstants:\n"); |
|
std::string error; |
|
getOutputAndReset(&error); |
|
} |
|
|
|
// setup the global methods for the PlasmaGame module |
|
methods.clear(); |
|
AddPlasmaGameMethods(methods); |
|
|
|
// now copy the data to our real method definition structure |
|
plasmaGameMethods = new PyMethodDef[methods.size() + 1]; |
|
for (int curMethod = 0; curMethod < methods.size(); curMethod++) |
|
plasmaGameMethods[curMethod] = methods[curMethod]; |
|
plasmaGameMethods[methods.size()] = terminator; // add the terminator |
|
|
|
// initialize the PlasmaGame module |
|
plasmaGameMod = Py_InitModule("PlasmaGame", plasmaGameMethods); |
|
if (plasmaGameMod == NULL) |
|
{ |
|
dbgLog->AddLine("Could not setup the PlasmaGame module\n"); |
|
return; |
|
} |
|
if (PyErr_Occurred()) |
|
{ |
|
dbgLog->AddLine("Python error while setting up PlasmaGame:\n"); |
|
std::string error; |
|
getOutputAndReset(&error); |
|
} |
|
Py_INCREF(plasmaGameMod); |
|
|
|
AddPlasmaGameClasses(); |
|
|
|
if (PyErr_Occurred()) |
|
{ |
|
dbgLog->AddLine("Python error while adding classes to PlasmaGame:\n"); |
|
std::string error; |
|
getOutputAndReset(&error); |
|
} |
|
|
|
// initialize the PlasmaGameConstants module |
|
plasmaGameConstantsMod = Py_InitModule("PlasmaGameConstants", &noMethods); // it has no methods, just values |
|
if (plasmaGameConstantsMod == NULL) |
|
{ |
|
dbgLog->AddLine("Could not setup the PlasmaGameConstants module\n"); |
|
return; |
|
} |
|
if (PyErr_Occurred()) |
|
{ |
|
dbgLog->AddLine("Python error while setting up PlasmaGameConstants:\n"); |
|
std::string error; |
|
getOutputAndReset(&error); |
|
} |
|
Py_INCREF(plasmaGameConstantsMod); |
|
|
|
AddPlasmaGameConstantsClasses(); |
|
|
|
if (PyErr_Occurred()) |
|
{ |
|
dbgLog->AddLine("Python error while adding classes to PlasmaGameConstants:\n"); |
|
std::string error; |
|
getOutputAndReset(&error); |
|
} |
|
} |
|
initialized++; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : initDebugInterface |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : Initialize the Python to Plasma |
|
// |
|
void PythonInterface::initDebugInterface() |
|
{ |
|
if ( !debug_initialized ) |
|
{ |
|
// bring up the debug window |
|
dbgMod = PyImport_ImportModule("cydebug"); |
|
// was there a debug module? |
|
if ( dbgMod != nil ) |
|
{ |
|
PyObject *dict; |
|
// get the dictionary for this module |
|
dict = PyModule_GetDict(dbgMod); |
|
dbgOut = PyDict_GetItemString(dict, "writeout"); |
|
dbgSlice = PyDict_GetItemString(dict, "timeslice"); |
|
} |
|
} |
|
debug_initialized = true; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : AddPlasmaMethods |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : Add global methods to the Plasma module |
|
// |
|
void PythonInterface::AddPlasmaMethods(std::vector<PyMethodDef> &methods) |
|
{ |
|
cyMisc::AddPlasmaMethods(methods); |
|
cyAvatar::AddPlasmaMethods(methods); |
|
cyAccountManagement::AddPlasmaMethods(methods); |
|
|
|
pyDrawControl::AddPlasmaMethods(methods); |
|
pyGUIDialog::AddPlasmaMethods(methods); |
|
pyImage::AddPlasmaMethods(methods); |
|
pyJournalBook::AddPlasmaMethods(methods); |
|
pySDLModifier::AddPlasmaMethods(methods); |
|
pySpawnPointInfo::AddPlasmaMethods(methods); |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : AddPlasmaClasses |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : Add classes to the Plasma module |
|
// |
|
void PythonInterface::AddPlasmaClasses() |
|
{ |
|
pyKey::AddPlasmaClasses(plasmaMod); |
|
pySceneObject::AddPlasmaClasses(plasmaMod); |
|
|
|
pyAgeInfoStruct::AddPlasmaClasses(plasmaMod); |
|
pyAgeInfoStructRef::AddPlasmaClasses(plasmaMod); |
|
pyAgeLinkStruct::AddPlasmaClasses(plasmaMod); |
|
pyAgeLinkStructRef::AddPlasmaClasses(plasmaMod); |
|
pySpawnPointInfo::AddPlasmaClasses(plasmaMod); |
|
pySpawnPointInfoRef::AddPlasmaClasses(plasmaMod); |
|
|
|
pyColor::AddPlasmaClasses(plasmaMod); |
|
pyMatrix44::AddPlasmaClasses(plasmaMod); |
|
pyPoint3::AddPlasmaClasses(plasmaMod); |
|
pyVector3::AddPlasmaClasses(plasmaMod); |
|
|
|
cyAnimation::AddPlasmaClasses(plasmaMod); |
|
cyAvatar::AddPlasmaClasses(plasmaMod); |
|
cyCamera::AddPlasmaClasses(plasmaMod); |
|
cyDraw::AddPlasmaClasses(plasmaMod); |
|
cyInputInterface::AddPlasmaClasses(plasmaMod); |
|
cyParticleSys::AddPlasmaClasses(plasmaMod); |
|
cyPhysics::AddPlasmaClasses(plasmaMod); |
|
|
|
pyAudioControl::AddPlasmaClasses(plasmaMod); |
|
pyCluster::AddPlasmaClasses(plasmaMod); |
|
pyDniCoordinates::AddPlasmaClasses(plasmaMod); |
|
pyDniInfoSource::AddPlasmaClasses(plasmaMod); |
|
pyDynamicText::AddPlasmaClasses(plasmaMod); |
|
pyImage::AddPlasmaClasses(plasmaMod); |
|
pyJournalBook::AddPlasmaClasses(plasmaMod); |
|
pyKeyMap::AddPlasmaClasses(plasmaMod); |
|
pyMarkerMgr::AddPlasmaClasses(plasmaMod); |
|
pyMoviePlayer::AddPlasmaClasses(plasmaMod); |
|
pyNetLinkingMgr::AddPlasmaClasses(plasmaMod); |
|
pyNotify::AddPlasmaClasses(plasmaMod); |
|
pyPlayer::AddPlasmaClasses(plasmaMod); |
|
pyStatusLog::AddPlasmaClasses(plasmaMod); |
|
pyStream::AddPlasmaClasses(plasmaMod); |
|
pySwimCurrentInterface::AddPlasmaClasses(plasmaMod); |
|
pyWaveSet::AddPlasmaClasses(plasmaMod); |
|
|
|
// SDL |
|
pySDLModifier::AddPlasmaClasses(plasmaMod); |
|
pySDLStateDataRecord::AddPlasmaClasses(plasmaMod); |
|
pySimpleStateVariable::AddPlasmaClasses(plasmaMod); |
|
|
|
// GUI objects |
|
pyGUIDialog::AddPlasmaClasses(plasmaMod); |
|
pyGUISkin::AddPlasmaClasses(plasmaMod); |
|
pyGUIPopUpMenu::AddPlasmaClasses(plasmaMod); |
|
// GUI base classes |
|
pyGUIControl::AddPlasmaClasses(plasmaMod); |
|
pyGUIControlValue::AddPlasmaClasses(plasmaMod); |
|
// GUI derived classes |
|
pyGUIControlButton::AddPlasmaClasses(plasmaMod); |
|
pyGUIControlCheckBox::AddPlasmaClasses(plasmaMod); |
|
pyGUIControlClickMap::AddPlasmaClasses(plasmaMod); |
|
pyGUIControlDragBar::AddPlasmaClasses(plasmaMod); |
|
pyGUIControlDraggable::AddPlasmaClasses(plasmaMod); |
|
pyGUIControlDynamicText::AddPlasmaClasses(plasmaMod); |
|
pyGUIControlEditBox::AddPlasmaClasses(plasmaMod); |
|
pyGUIControlKnob::AddPlasmaClasses(plasmaMod); |
|
pyGUIControlListBox::AddPlasmaClasses(plasmaMod); |
|
pyGUIControlMultiLineEdit::AddPlasmaClasses(plasmaMod); |
|
pyGUIControlProgress::AddPlasmaClasses(plasmaMod); |
|
pyGUIControlRadioGroup::AddPlasmaClasses(plasmaMod); |
|
pyGUIControlTextBox::AddPlasmaClasses(plasmaMod); |
|
pyGUIControlUpDownPair::AddPlasmaClasses(plasmaMod); |
|
|
|
// Vault objects |
|
pyAgeVault::AddPlasmaClasses(plasmaMod); |
|
pyVault::AddPlasmaClasses(plasmaMod); |
|
// Vault node base classes |
|
pyVaultNode::AddPlasmaClasses(plasmaMod); |
|
pyVaultNodeRef::AddPlasmaClasses(plasmaMod); |
|
pyVaultFolderNode::AddPlasmaClasses(plasmaMod); |
|
// Vault node derived classes |
|
pyVaultAgeInfoListNode::AddPlasmaClasses(plasmaMod); |
|
pyVaultAgeInfoNode::AddPlasmaClasses(plasmaMod); |
|
pyVaultAgeLinkNode::AddPlasmaClasses(plasmaMod); |
|
pyVaultChronicleNode::AddPlasmaClasses(plasmaMod); |
|
pyVaultImageNode::AddPlasmaClasses(plasmaMod); |
|
pyVaultMarkerGameNode::AddPlasmaClasses(plasmaMod); |
|
pyVaultPlayerInfoListNode::AddPlasmaClasses(plasmaMod); |
|
pyVaultPlayerInfoNode::AddPlasmaClasses(plasmaMod); |
|
pyVaultSDLNode::AddPlasmaClasses(plasmaMod); |
|
pyVaultSystemNode::AddPlasmaClasses(plasmaMod); |
|
pyVaultTextNoteNode::AddPlasmaClasses(plasmaMod); |
|
|
|
// Shaders |
|
pyGrassShader::AddPlasmaClasses(plasmaMod); |
|
|
|
// AI |
|
pyCritterBrain::AddPlasmaClasses(plasmaMod); |
|
|
|
// Game Scores |
|
pyGameScore::AddPlasmaClasses(plasmaMod); |
|
pyGameScoreMsg::AddPlasmaClasses(plasmaMod); |
|
pyGameScoreListMsg::AddPlasmaClasses(plasmaMod); |
|
pyGameScoreTransferMsg::AddPlasmaClasses(plasmaMod); |
|
pyGameScoreUpdateMsg::AddPlasmaClasses(plasmaMod); |
|
|
|
// Stupid thing |
|
ptImportHook_AddPlasmaClasses(plasmaMod); |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : AddPlasmaConstantsClasses |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : Initialize the PlasmaConstants module |
|
// |
|
void PythonInterface::AddPlasmaConstantsClasses() |
|
{ |
|
pyEnum::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
|
|
cyAvatar::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
cyMisc::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
cyAccountManagement::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
|
|
//pyDrawControl::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
pyDynamicText::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
pyGameScore::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
pyGUIControlButton::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
pyGUIControlMultiLineEdit::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
pyJournalBook::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
pyMarkerMgr::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
pyMoviePlayer::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
pyNotify::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
pySDL::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
pyStatusLog::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
|
|
pyAIMsg::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
|
|
// TODO: put these constants here. remove them from below. |
|
//pyNetLinkingMgr::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
//pyVault::AddPlasmaConstantsClasses(plasmaConstantsMod); |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : AddPlasmaNetConstantsClasses |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : Initialize the PlasmaNetConstants module |
|
// |
|
void PythonInterface::AddPlasmaNetConstantsClasses() |
|
{ |
|
pyNetLinkingMgr::AddPlasmaConstantsClasses(plasmaNetConstantsMod); |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : AddPlasmaVaultConstantsClasses |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : Initialize the PlasmaVaultConstants module |
|
// |
|
void PythonInterface::AddPlasmaVaultConstantsClasses() |
|
{ |
|
pyVault::AddPlasmaConstantsClasses(plasmaVaultConstantsMod); |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : AddPlasmaGameMethods |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : Add global methods to the PlasmaGame module |
|
// |
|
void PythonInterface::AddPlasmaGameMethods(std::vector<PyMethodDef> &methods) |
|
{ |
|
// General |
|
pyGameCli::AddPlasmaMethods(methods); |
|
|
|
// TicTacToe game |
|
pyTTTGame::AddPlasmaMethods(methods); |
|
|
|
// Heek game |
|
pyHeekGame::AddPlasmaMethods(methods); |
|
|
|
// Marker game |
|
pyMarkerGame::AddPlasmaMethods(methods); |
|
|
|
// Blue Spiral game |
|
pyBlueSpiralGame::AddPlasmaMethods(methods); |
|
|
|
// Climbing Wall game |
|
pyClimbingWallGame::AddPlasmaMethods(methods); |
|
|
|
// Variable Sync game |
|
pyVarSyncGame::AddPlasmaMethods(methods); |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : AddPlasmaGameClasses |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : Initialize the PlasmaGame module |
|
// |
|
void PythonInterface::AddPlasmaGameClasses() |
|
{ |
|
// General |
|
pyGameMgrMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyGameMgrInviteReceivedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyGameMgrInviteRevokedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyGameCliMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyGameCliPlayerJoinedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyGameCliPlayerLeftMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyGameCliInviteFailedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyGameCliOwnerChangeMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyGameCli::AddPlasmaClasses(plasmaGameMod); |
|
|
|
// TicTacToe game |
|
pyTTTMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyTTTGameStartedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyTTTGameOverMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyTTTMoveMadeMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyTTTGame::AddPlasmaClasses(plasmaGameMod); |
|
|
|
// Heek game |
|
pyHeekMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyHeekPlayGameMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyHeekGoodbyeMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyHeekWelcomeMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyHeekDropMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyHeekSetupMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyHeekLightStateMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyHeekInterfaceStateMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyHeekCountdownStateMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyHeekWinLoseMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyHeekGameWinMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyHeekPointUpdateMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyHeekGame::AddPlasmaClasses(plasmaGameMod); |
|
|
|
// Marker game |
|
pyMarkerMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerTemplateCreatedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerTeamAssignedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerGameTypeMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerGameStartedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerGamePausedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerGameResetMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerGameOverMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerGameNameChangedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerTimeLimitChangedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerGameDeletedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerMarkerAddedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerMarkerDeletedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerMarkerNameChangedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerMarkerCapturedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyMarkerGame::AddPlasmaClasses(plasmaGameMod); |
|
|
|
// Blue Spiral game |
|
pyBlueSpiralMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyBlueSpiralClothOrderMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyBlueSpiralSuccessfulHitMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyBlueSpiralGameWonMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyBlueSpiralGameOverMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyBlueSpiralGameStartedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyBlueSpiralGame::AddPlasmaClasses(plasmaGameMod); |
|
|
|
// Climbing Wall game |
|
pyClimbingWallMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyClimbingWallNumBlockersChangedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyClimbingWallReadyMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyClimbingWallBlockersChangedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyClimbingWallPlayerEnteredMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyClimbingWallSuitMachineLockedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyClimbingWallGameOverMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyClimbingWallGame::AddPlasmaClasses(plasmaGameMod); |
|
|
|
// Variable Sync game |
|
pyVarSyncMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyVarSyncStringVarChangedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyVarSyncNumericVarChangedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyVarSyncAllVarsSentMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyVarSyncStringVarCreatedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyVarSyncNumericVarCreatedMsg::AddPlasmaClasses(plasmaGameMod); |
|
pyVarSyncGame::AddPlasmaClasses(plasmaGameMod); |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : AddPlasmaGameConstantsClasses |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : Initialize the PlasmaGameConstants module |
|
// |
|
void PythonInterface::AddPlasmaGameConstantsClasses() |
|
{ |
|
// General |
|
pyGameMgrMsg::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
pyGameCliMsg::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
pyGameCliInviteFailedMsg::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
|
|
// TicTacToe game |
|
pyTTTMsg::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
pyTTTGame::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
|
|
// Heek game |
|
pyHeekMsg::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
pyHeekLightStateMsg::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
pyHeekCountdownStateMsg::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
pyHeekGame::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
|
|
// Marker game |
|
pyMarkerMsg::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
pyMarkerGame::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
|
|
// Blue Spiral game |
|
pyBlueSpiralMsg::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
|
|
// Climbing Wall game |
|
pyClimbingWallMsg::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
pyClimbingWallGame::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
|
|
// Variable Sync game |
|
pyVarSyncMsg::AddPlasmaConstantsClasses(plasmaGameConstantsMod); |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : finiPython |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : Finalize the Python dll, ie. get ready to shut down |
|
// |
|
void PythonInterface::finiPython() |
|
{ |
|
// decrement the number of initializations, on last one do the finalization |
|
initialized--; |
|
if ( initialized < 1 && Py_IsInitialized() != 0 && IsInShutdown ) |
|
{ |
|
#if defined(HAVE_CYPYTHONIDE) && !defined(PLASMA_EXTERNAL_RELEASE) |
|
if (usePythonDebugger) |
|
debugServer.Disconnect(); |
|
#endif |
|
// remove debug module if used |
|
if ( dbgMod ) |
|
{ |
|
Py_DECREF(dbgMod); |
|
dbgMod = nil; |
|
} |
|
|
|
if ( stdOut ) |
|
{ |
|
Py_DECREF(stdOut); |
|
stdOut = nil; |
|
} |
|
|
|
if ( stdErr ) |
|
{ |
|
Py_DECREF(stdErr); |
|
stdErr = nil; |
|
} |
|
|
|
if ( plasmaMod ) |
|
{ |
|
Py_DECREF(plasmaMod); // get rid of our reference |
|
plasmaMod = nil; |
|
} |
|
|
|
if ( plasmaConstantsMod ) |
|
{ |
|
Py_DECREF(plasmaConstantsMod); |
|
plasmaConstantsMod = nil; |
|
} |
|
|
|
if ( plasmaNetConstantsMod ) |
|
{ |
|
Py_DECREF(plasmaNetConstantsMod); |
|
plasmaNetConstantsMod = nil; |
|
} |
|
|
|
if ( plasmaVaultConstantsMod ) |
|
{ |
|
Py_DECREF(plasmaVaultConstantsMod); |
|
plasmaVaultConstantsMod = nil; |
|
} |
|
|
|
if ( plasmaGameMod ) |
|
{ |
|
Py_DECREF(plasmaGameMod); |
|
plasmaGameMod = nil; |
|
} |
|
|
|
if ( plasmaGameConstantsMod ) |
|
{ |
|
Py_DECREF(plasmaGameConstantsMod); |
|
plasmaGameConstantsMod = nil; |
|
} |
|
|
|
// let Python clean up after itself |
|
Py_Finalize(); |
|
|
|
if (plasmaMethods) |
|
{ |
|
delete [] plasmaMethods; |
|
plasmaMethods = nil; |
|
} |
|
|
|
if (plasmaGameMethods) |
|
{ |
|
delete [] plasmaGameMethods; |
|
plasmaGameMethods = nil; |
|
} |
|
|
|
// close done the log file, if we created one |
|
if ( dbgLog != nil ) |
|
{ |
|
delete dbgLog; |
|
dbgLog = nil; |
|
} |
|
|
|
initialized = 0; |
|
} |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : debugTimeSlice |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : give the debug window a time slice |
|
// |
|
void PythonInterface::debugTimeSlice() |
|
{ |
|
// check to see if the debug python module is loaded |
|
if ( dbgSlice != nil ) |
|
{ |
|
// then send it the new text |
|
PyObject* retVal = PyObject_CallFunction(dbgSlice,nil); |
|
if ( retVal == nil ) |
|
{ |
|
// for some reason this function didn't, remember that and not call it again |
|
dbgSlice = nil; |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
PyErr_Print(); // make sure the error is printed |
|
PyErr_Clear(); // clear the error |
|
} |
|
Py_XDECREF(retVal); |
|
} |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : GetStdOut |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : get the stdOut python object |
|
// |
|
PyObject* PythonInterface::GetStdOut() |
|
{ |
|
return stdOut; |
|
} |
|
|
|
PyObject* PythonInterface::GetStdErr() |
|
{ |
|
return stdErr; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : getOutputAndReset |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : get the Output to the error file to be displayed |
|
// |
|
int PythonInterface::getOutputAndReset(std::string *output) |
|
{ |
|
if (stdOut != nil) |
|
{ |
|
std::string strVal = pyOutputRedirector::GetData(stdOut); |
|
int size = strVal.length(); |
|
dbgLog->AddLine(strVal.c_str()); |
|
|
|
// reset the file back to zero |
|
pyOutputRedirector::ClearData(stdOut); |
|
|
|
// tell python debugger |
|
#if defined(HAVE_CYPYTHONIDE) && !defined(PLASMA_EXTERNAL_RELEASE) |
|
if (UsePythonDebugger()) |
|
PythonInterface::PythonDebugger()->StdOut(strVal); |
|
#endif |
|
|
|
// check to see if the debug python module is loaded |
|
if ( dbgOut != nil ) |
|
{ |
|
// then send it the new text |
|
PyObject* retVal = PyObject_CallFunction(dbgOut,"s",strVal.c_str()); |
|
if ( retVal == nil ) |
|
{ |
|
// for some reason this function didn't, remember that and not call it again |
|
dbgOut = nil; |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
PyErr_Print(); // make sure the error is printed |
|
PyErr_Clear(); // clear the error |
|
} |
|
Py_XDECREF(retVal); |
|
} |
|
|
|
if (output) |
|
(*output) = strVal; |
|
return size; |
|
} |
|
return 0; |
|
} |
|
|
|
void PythonInterface::WriteToLog(const char* text) |
|
{ |
|
dbgLog->AddLine(text); |
|
} |
|
|
|
void PythonInterface::WriteToStdErr(const char* text) |
|
{ |
|
PyObject* stdErr = PythonInterface::GetStdErr(); |
|
if (stdErr && pyErrorRedirector::Check(stdErr)) |
|
{ |
|
pyErrorRedirector *obj = pyErrorRedirector::ConvertFrom(stdErr); |
|
obj->Write(text); |
|
} |
|
} |
|
|
|
PyObject* PythonInterface::ImportModule(const char* module) |
|
{ |
|
PyObject* result = nil; |
|
PyObject* name = PyString_FromString(module); |
|
|
|
if (name != nil) |
|
{ |
|
result = PyImport_Import(name); |
|
Py_DECREF(name); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : FindModule |
|
// PARAMETERS : module - module name to find |
|
// |
|
// PURPOSE : Find module. If it doesn't exist then don't create, return nil. |
|
// |
|
PyObject* PythonInterface::FindModule(const char* module) |
|
{ |
|
PyObject *m; |
|
// first we must get rid of any old modules of the same name, we'll replace it |
|
PyObject *modules = PyImport_GetModuleDict(); |
|
if ((m = PyDict_GetItemString(modules, module)) != NULL && PyModule_Check(m)) |
|
// just return what we found |
|
return m; |
|
|
|
// couldn't find the module, return None (sorta) |
|
return nil; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : IsModuleNameUnique |
|
// PARAMETERS : module - module name to create |
|
// |
|
// PURPOSE : Test to see if the module name is unique |
|
// |
|
// Returns : True if unique , otherwise returns False |
|
// |
|
bool PythonInterface::IsModuleNameUnique(char* module) |
|
{ |
|
PyObject *m; |
|
// first we must get rid of any old modules of the same name, we'll replace it |
|
PyObject *modules = PyImport_GetModuleDict(); |
|
if ((m = PyDict_GetItemString(modules, module)) != NULL && PyModule_Check(m)) |
|
{ |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : CreateModule |
|
// PARAMETERS : module - module name to create |
|
// |
|
// PURPOSE : create a new module with built-ins |
|
// |
|
PyObject* PythonInterface::CreateModule(const char* module) |
|
{ |
|
PyObject *m, *d; |
|
// first we must get rid of any old modules of the same name, we'll replace it |
|
PyObject *modules = PyImport_GetModuleDict(); |
|
if ((m = PyDict_GetItemString(modules, module)) != NULL && PyModule_Check(m)) |
|
{ |
|
// clear it |
|
char message[256]; |
|
sprintf(message,"ERROR! Creating a python module of the same name - %s",module); |
|
hsAssert(false,message); |
|
_PyModule_Clear(m); |
|
} |
|
|
|
// create the module |
|
m = PyImport_AddModule(module); |
|
if (m == NULL) |
|
return nil; |
|
d = PyModule_GetDict(m); |
|
// add in the built-ins |
|
// first make sure that we don't already have the builtins |
|
if (PyDict_GetItemString(d, "__builtins__") == NULL) |
|
{ |
|
// if we need the builtins then find the builtin module |
|
PyObject *bimod = PyImport_ImportModule("__builtin__"); |
|
// then add the builtin dicitionary to our module's dictionary |
|
if (bimod == NULL || PyDict_SetItemString(d, "__builtins__", bimod) != 0) |
|
return nil; |
|
Py_DECREF(bimod); |
|
} |
|
return m; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : GetPlasmaItem |
|
// PARAMETERS : item - what item in the plasma module to get |
|
// |
|
// PURPOSE : get an item (probably a function) from the Plasma module |
|
// |
|
PyObject* PythonInterface::GetPlasmaItem(char* item) |
|
{ |
|
if ( plasmaMod ) |
|
{ |
|
PyObject* d = PyModule_GetDict(plasmaMod); |
|
return PyDict_GetItemString(d, item); |
|
} |
|
return nil; |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : GetModuleItem |
|
// PARAMETERS : item - what item in the plasma module to get |
|
// |
|
// PURPOSE : get an item (probably a function) from a specific module |
|
// |
|
PyObject* PythonInterface::GetModuleItem(char* item, PyObject* module) |
|
{ |
|
if ( module ) |
|
{ |
|
PyObject* d = PyModule_GetDict(module); |
|
return PyDict_GetItemString(d, item); |
|
} |
|
|
|
return nil; |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : CheckModuleForFunctions |
|
// PARAMETERS : module - module to check for |
|
// |
|
// PURPOSE : checks to see if a specific function is defined in this module |
|
// |
|
void PythonInterface::CheckModuleForFunctions(PyObject* module, char** funcNames, PyObject** funcTable) |
|
{ |
|
PyObject *dict; |
|
// get the dictionary for this module |
|
dict = PyModule_GetDict(module); |
|
// start looking for the functions |
|
int i=0; |
|
while ( funcNames[i] != nil ) |
|
{ |
|
PyObject* func = PyDict_GetItemString(dict, funcNames[i]); |
|
if ( func != NULL && PyCallable_Check(func)>0 ) |
|
{ |
|
// if it is defined then mark the funcTable |
|
funcTable[i] = func; |
|
} |
|
else // else we couldn't find the funtion |
|
{ |
|
funcTable[i] = nil; |
|
} |
|
i++; |
|
} |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : CheckInstanceForFunctions |
|
// PARAMETERS : instance - instance of a class to check |
|
// |
|
// PURPOSE : checks to see if a specific function is defined in this instance of a class |
|
// : and will fill out the funcTable with object instances of where the funciton is |
|
// |
|
void PythonInterface::CheckInstanceForFunctions(PyObject* instance, char** funcNames, PyObject** funcTable) |
|
{ |
|
// start looking for the functions |
|
int i=0; |
|
while ( funcNames[i] != nil ) |
|
{ |
|
PyObject* func = PyObject_GetAttrString(instance, funcNames[i]); |
|
if ( func != NULL ) |
|
{ |
|
if ( PyCallable_Check(func)>0 ) |
|
{ |
|
// if it is defined then mark the funcTable |
|
funcTable[i] = instance; |
|
} |
|
Py_DECREF(func); |
|
} |
|
i++; |
|
} |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : CompileString |
|
// PARAMETERS : command - string of commands to execute in the... |
|
// : filename - filename to say where to code came from |
|
// |
|
// PURPOSE : run a python string in a specific module name |
|
// |
|
PyObject* PythonInterface::CompileString(char *command, char* filename) |
|
{ |
|
PyObject* pycode = Py_CompileString(command, filename, Py_file_input); |
|
return pycode; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : DumpObject |
|
// PARAMETERS : pyobject - string of commands to execute in the... |
|
// |
|
// PURPOSE : marshals an object into a char string |
|
// |
|
bool PythonInterface::DumpObject(PyObject* pyobj, char** pickle, int32_t* size) |
|
{ |
|
PyObject *s; // the python string object where the marsalled object wil go |
|
// convert object to a marshalled string python object |
|
#if (PY_MAJOR_VERSION == 2) && (PY_MINOR_VERSION < 4) |
|
s = PyMarshal_WriteObjectToString(pyobj); |
|
#else |
|
s = PyMarshal_WriteObjectToString(pyobj, Py_MARSHAL_VERSION); |
|
#endif |
|
|
|
// did it actually do it? |
|
if ( s != NULL ) |
|
{ |
|
// yes, then get the size and the string address |
|
*size = PyString_Size(s); |
|
*pickle = PyString_AsString(s); |
|
return true; |
|
} |
|
else // otherwise, there was an error |
|
{ |
|
// Yikes! errors! |
|
PyErr_Print(); // FUTURE: we may have to get the string to display in max...later |
|
return false; |
|
} |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : LoadObject |
|
// PARAMETERS : pickle - the pickled object in char string form |
|
// : size - size of the guts to load into an object |
|
// |
|
// PURPOSE : Load a python object from a pickled object |
|
// |
|
PyObject* PythonInterface::LoadObject(char* pickle, int32_t size) |
|
{ |
|
return PyMarshal_ReadObjectFromString(pickle, size); |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : RunStringInteractive |
|
// PARAMETERS : command - string of commands to execute in the... |
|
// : module - module name to run 'command' in |
|
// |
|
// PURPOSE : run a python string in a specific module name |
|
// |
|
// RETURNS : pointer to PyObject that is the result of the command |
|
// |
|
bool PythonInterface::RunStringInteractive(char *command, PyObject* module) |
|
{ |
|
PyObject *d, *v; |
|
// make sure that we're given a good module... or at least one with an address |
|
if ( !module ) |
|
{ |
|
// if no module was given then use just use the main module |
|
module = PyImport_AddModule("__main__"); |
|
if (module == NULL) |
|
return false; |
|
} |
|
// get the dictionaries for this module |
|
d = PyModule_GetDict(module); |
|
// run the string |
|
v = PyRun_String(command, Py_single_input, d, d); |
|
// check for errors and print them |
|
if (v == NULL) |
|
{ |
|
// Yikes! errors! |
|
PyErr_Print(); |
|
return false; |
|
} |
|
Py_DECREF(v); |
|
if (Py_FlushLine()) |
|
PyErr_Clear(); |
|
return true; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : RunString |
|
// PARAMETERS : command - string of commands to execute in the... |
|
// : module - module name to run 'command' in |
|
// |
|
// PURPOSE : run a python string in a specific module name |
|
// |
|
bool PythonInterface::RunString(char *command, PyObject* module) |
|
{ |
|
PyObject *d, *v; |
|
// make sure that we're given a good module... or at least one with an address |
|
if ( !module ) |
|
{ |
|
// if no module was given then use just use the main module |
|
module = PyImport_AddModule("__main__"); |
|
if (module == NULL) |
|
return false; |
|
} |
|
// get the dictionaries for this module |
|
d = PyModule_GetDict(module); |
|
// run the string |
|
v = PyRun_String(command, Py_file_input, d, d); |
|
// check for errors and print them |
|
if (v == NULL) |
|
{ |
|
// Yikes! errors! |
|
PyErr_Print(); |
|
return false; |
|
} |
|
Py_DECREF(v); |
|
if (Py_FlushLine()) |
|
PyErr_Clear(); |
|
return true; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : RunPYC |
|
// PARAMETERS : code - compiled code |
|
// : module - module name to run the code in |
|
// |
|
// PURPOSE : run a compiled python code in a specific module name |
|
// |
|
bool PythonInterface::RunPYC(PyObject* code, PyObject* module) |
|
{ |
|
PyObject *d, *v; |
|
// make sure that we're given a good module... or at least one with an address |
|
if ( !module ) |
|
{ |
|
// if no module was given then use just use the main module |
|
module = PyImport_AddModule("__main__"); |
|
if (module == NULL) |
|
return false; |
|
} |
|
// get the dictionaries for this module |
|
d = PyModule_GetDict(module); |
|
// run the string |
|
v = PyEval_EvalCode((PyCodeObject*)code, d, d); |
|
// check for errors and print them |
|
if (v == NULL) |
|
{ |
|
// Yikes! errors! |
|
PyErr_Print(); |
|
return false; |
|
} |
|
Py_DECREF(v); |
|
if (Py_FlushLine()) |
|
PyErr_Clear(); |
|
return true; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : RunFunction |
|
// PARAMETERS : module - module name to run 'name' in |
|
// : name - name of function |
|
// : args - tuple with arguments |
|
// |
|
// |
|
PyObject* PythonInterface::RunFunction(PyObject* module, const char* name, PyObject* args) |
|
{ |
|
if (module == NULL) |
|
return NULL; |
|
|
|
PyObject* function = PyObject_GetAttrString(module, name); |
|
|
|
PyObject* result = NULL; |
|
if (function != nil) |
|
{ |
|
result = PyObject_Call(function, args, NULL); |
|
Py_DECREF(function); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
PyObject* PythonInterface::ParseArgs(const char* args) |
|
{ |
|
PyObject* result = NULL; |
|
PyObject* scope = PyDict_New(); |
|
if (scope) |
|
{ |
|
//- Py_eval_input makes this function accept only single expresion (not statement) |
|
//- When using empty scope, functions and classes like 'file' or '__import__' are not visible |
|
result = PyRun_String(args, Py_eval_input, scope, NULL); |
|
Py_DECREF(scope); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
bool PythonInterface::RunFunctionSafe(const char* module, const char* function, const char* args) |
|
{ |
|
PyObject* moduleObj = ImportModule(module); |
|
bool result = false; |
|
if (moduleObj) |
|
{ |
|
PyObject* argsObj = ParseArgs(args); |
|
if (argsObj) |
|
{ |
|
PyObject* callResult = RunFunction(moduleObj, function, argsObj); |
|
if (callResult) |
|
{ |
|
result = true; |
|
Py_DECREF(callResult); |
|
} |
|
|
|
Py_DECREF(argsObj); |
|
} |
|
Py_DECREF(moduleObj); |
|
} |
|
|
|
if (!result) |
|
{ |
|
PyErr_Print(); |
|
|
|
if (Py_FlushLine()) |
|
PyErr_Clear(); |
|
} |
|
|
|
return result; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : GetpyKeyFromPython |
|
// PARAMETERS : pkey - python object that is a pyKey (ptKey) class |
|
// |
|
// PURPOSE : turn a PyObject* into a pyKey* |
|
// |
|
pyKey* PythonInterface::GetpyKeyFromPython(PyObject* pkey) |
|
{ |
|
if (!pyKey::Check(pkey)) |
|
return nil; |
|
return pyKey::ConvertFrom(pkey); |
|
}
|
|
|