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.
2976 lines
99 KiB
2976 lines
99 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==*/ |
|
////////////////////////////////////////////////////////////////////// |
|
// |
|
// plPythonFileMod - the 'special' Python File modifier. |
|
// |
|
// This modifier will handle the interface to python code that has been file-ized. |
|
// |
|
////////////////////////////////////////////////////////////////////////// |
|
|
|
#include "hsTypes.h" |
|
#include "hsStream.h" |
|
#include "plgDispatch.h" |
|
#include "hsResMgr.h" |
|
#include "../plResMgr/plKeyFinder.h" |
|
#include "../pnKeyedObject/plKeyImp.h" |
|
#include "../pnKeyedObject/plUoid.h" |
|
|
|
#include "../pnSceneObject/plSceneObject.h" |
|
#include "../pnSceneObject/plCoordinateInterface.h" |
|
#include "../pnKeyedObject/plKey.h" |
|
#include "../pnMessage/plTimeMsg.h" |
|
#include "../pnMessage/plCmdIfaceModMsg.h" |
|
#include "../plMessage/plInputEventMsg.h" |
|
#include "../plModifier/plLogicModifier.h" |
|
#include "../pfMessage/pfGUINotifyMsg.h" |
|
#include "../plMessage/plRoomLoadNotifyMsg.h" |
|
#include "../pfMessage/plClothingMsg.h" |
|
#include "../pfMessage/pfKIMsg.h" |
|
#include "../plMessage/plMemberUpdateMsg.h" |
|
#include "../plMessage/plAgeLoadedMsg.h" |
|
#include "../pnMessage/plRemoteAvatarInfoMsg.h" |
|
#include "../pnMessage/plPlayerPageMsg.h" |
|
#include "../plNetClient/plNetClientMgr.h" |
|
#include "../plNetTransport/plNetTransportMember.h" |
|
#include "../pnMessage/plSDLNotificationMsg.h" |
|
#include "../plMessage/plNetOwnershipMsg.h" |
|
#include "../plSDL/plSDL.h" |
|
#include "../plVault/plVault.h" |
|
#include "../plMessage/plCCRMsg.h" |
|
#include "../plMessage/plVaultNotifyMsg.h" |
|
#include "../plInputCore/plInputInterfaceMgr.h" |
|
#include "../plInputCore/plInputDevice.h" |
|
#include "../pfMessage/pfMarkerMsg.h" |
|
#include "../pfMessage/pfBackdoorMsg.h" |
|
#include "../plMessage/plAvatarMsg.h" |
|
#include "../plMessage/plLOSHitMsg.h" |
|
#include "../plMessage/plRenderMsg.h" |
|
#include "../pfMessage/pfMovieEventMsg.h" |
|
#include "../plMessage/plClimbEventMsg.h" |
|
#include "../plMessage/plCaptureRenderMsg.h" |
|
#include "../plGImage/plMipmap.h" |
|
#include "../plMessage/plAccountUpdateMsg.h" |
|
#include "../plAgeLoader/plAgeLoader.h" |
|
#include "../pfGameMgr/pfGameMgr.h" |
|
#include "../plMessage/plAIMsg.h" |
|
#include "../plAvatar/plAvBrainCritter.h" |
|
#include "../plMessage/plSubtitleMsg.h" |
|
|
|
#include "plProfile.h" |
|
|
|
#include "plPythonFileMod.h" |
|
#include "cyPythonInterface.h" |
|
#include "pyKey.h" |
|
#include "cyDraw.h" |
|
#include "cyPhysics.h" |
|
#include "pySceneObject.h" |
|
#include "cyMisc.h" |
|
#include "cyCamera.h" |
|
#include "pyNotify.h" |
|
#include "cyAvatar.h" |
|
#include "pyGeometry3.h" |
|
#include "pyVault.h" |
|
#include "pyVaultNode.h" |
|
#include "pyVaultNodeRef.h" |
|
#include "pyVaultAgeLinkNode.h" |
|
#include "pyPlayer.h" |
|
#include "pyNetLinkingMgr.h" |
|
#include "pyAgeInfoStruct.h" |
|
#include "pyAgeLinkStruct.h" |
|
#include "pyImage.h" |
|
#include "pyCritterBrain.h" |
|
|
|
// GUI Control: |
|
#include "pyGUIDialog.h" |
|
#include "pyGUIControlButton.h" |
|
#include "pyGUIControlCheckBox.h" |
|
#include "pyGUIControlEditBox.h" |
|
#include "pyGUIControlListBox.h" |
|
#include "pyGUIControlRadioGroup.h" |
|
#include "pyGUIControlTextBox.h" |
|
#include "pyGUIControlValue.h" |
|
#include "pyGUIControlDynamicText.h" |
|
#include "pyGUIControlMultiLineEdit.h" |
|
#include "pyGUIPopUpMenu.h" |
|
#include "pyGUIControlClickMap.h" |
|
|
|
// Game manager |
|
#include "Games/pyGameMgrMsg.h" |
|
#include "Games/pyGameCliMsg.h" |
|
|
|
#include <locale> |
|
|
|
#include "plPythonSDLModifier.h" |
|
|
|
#include "../plMessage/plTimerCallbackMsg.h" |
|
|
|
plProfile_CreateTimer("Update", "Python", PythonUpdate); |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// fFunctionNames - the actual names of the functions for On[event] types |
|
// |
|
char* plPythonFileMod::fFunctionNames[] = |
|
{ |
|
{ "OnFirstUpdate" }, // kfunc_FirstUpdate |
|
{ "OnUpdate" }, // kfunc_Update |
|
{ "OnNotify" }, // kfunc_Notify |
|
{ "OnTimer" }, // kfunc_AtTimer |
|
{ "OnControlKeyEvent" }, // kfunc_OnKeyEvent |
|
{ "Load" }, // kfunc_Load |
|
{ "Save" }, // kfunc_Save |
|
{ "OnGUINotify" }, // kfunc_GUINotify |
|
{ "OnPageLoad" }, // kfunc_PageLoad |
|
{ "OnClothingUpdate" }, // kfunc_ClothingUpdate |
|
{ "OnKIMsg" }, // kfunc_KIMsg, |
|
{ "OnMemberUpdate" }, // kfunc_MemberUpdate, |
|
{ "OnRemoteAvatarInfo" }, // kfunc_RemoteAvatarInfo, |
|
{ "OnRTChat" }, // kfunc_RTChat, |
|
{ "OnVaultEvent" }, // kfunc_VaultEvent, |
|
{ "AvatarPage" }, // kfunc_AvatarPage, |
|
{ "OnSDLNotify" }, // kfunc_SDLNotify |
|
{ "OnOwnershipChanged" }, // kfunc_OwnershipNotify |
|
{ "OnAgeVaultEvent" }, // kfunc_AgeVaultEvent |
|
{ "OnInit" }, // kfunc_Init, |
|
{ "OnCCRMsg" }, // kfunc_OnCCRMsg, |
|
{ "OnServerInitComplete" }, // kfunc_OnServerInitComplete |
|
{ "OnVaultNotify" }, // kfunc_OnVaultNotify |
|
{ "OnDefaultKeyCaught" }, // kfunc_OnDefaultKeyCaught |
|
{ "OnMarkerMsg" }, // kfunc_OnMarkerMsg, |
|
{ "OnBackdoorMsg" }, // kfunc_OnBackdoorMsg, |
|
{ "OnBehaviorNotify" }, // kfunc_OnBehaviorNotify, |
|
{ "OnLOSNotify" }, // kfunc_OnLOSNotify, |
|
{ "BeginAgeUnLoad" }, // kfunc_OnBeginAgeLoad, |
|
{ "OnMovieEvent" }, // kfunc_OnMovieEvent, |
|
{ "OnScreenCaptureDone" }, // kfunc_OnScreenCaptureDone, |
|
{ "OnClimbingBlockerEvent"},// kFunc_OnClimbingBlockerEvent, |
|
{ "OnAvatarSpawn"}, // kFunc_OnAvatarSpawn |
|
{ "OnAccountUpdate"}, // kFunc_OnAccountUpdate |
|
{ "gotPublicAgeList"}, // kfunc_gotPublicAgeList |
|
{ "OnGameMgrMsg" }, // kfunc_OnGameMgrMsg |
|
{ "OnGameCliMsg" }, // kfunc_OnGameCliMsg |
|
{ "OnAIMsg" }, // kfunc_OnAIMsg |
|
{ "OnSubtitleMsg" }, // kfunc_OnSubtitleMsg |
|
{ nil } |
|
}; |
|
|
|
//// Callback From the Vault Events ////////////////////////////////////////////// |
|
class PythonVaultCallback : public VaultCallback |
|
{ |
|
protected: |
|
plPythonFileMod* fPyFileMod; |
|
int fFunctionIdx; |
|
|
|
public: |
|
PythonVaultCallback( plPythonFileMod *pymod, int fidx ) |
|
{ |
|
fPyFileMod = pymod; |
|
fFunctionIdx = fidx; |
|
} |
|
|
|
void AddedChildNode ( RelVaultNode * parentNode, RelVaultNode * childNode ) |
|
{ |
|
// is there an 'OnVaultEvent' defined? |
|
if ( fPyFileMod && fPyFileMod->fPyFunctionInstances[fFunctionIdx] != nil ) |
|
{ |
|
PyObject* ptuple = PyTuple_New(1); |
|
PyTuple_SetItem(ptuple, 0, pyVaultNodeRef::New(parentNode, childNode)); |
|
// call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFileMod->fPyFunctionInstances[fFunctionIdx], |
|
fPyFileMod->fFunctionNames[fFunctionIdx], |
|
"lO",pyVault::kVaultNodeRefAdded,ptuple); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFileMod->fPyFunctionInstances[fFunctionIdx] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
fPyFileMod->ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(ptuple); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
fPyFileMod->DisplayPythonOutput(); |
|
} |
|
} |
|
|
|
void RemovingChildNode ( RelVaultNode * parentNode, RelVaultNode * childNode ) |
|
{ |
|
// is there an 'OnVaultEvent' defined? |
|
if ( fPyFileMod && fPyFileMod->fPyFunctionInstances[fFunctionIdx] != nil ) |
|
{ |
|
PyObject* ptuple = PyTuple_New(1); |
|
PyTuple_SetItem(ptuple, 0, pyVaultNodeRef::New(parentNode, childNode)); |
|
// call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFileMod->fPyFunctionInstances[fFunctionIdx], |
|
fPyFileMod->fFunctionNames[fFunctionIdx], |
|
"lO",pyVault::kVaultRemovingNodeRef,ptuple); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFileMod->fPyFunctionInstances[fFunctionIdx] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
fPyFileMod->ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(ptuple); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
fPyFileMod->DisplayPythonOutput(); |
|
} |
|
} |
|
|
|
void ChangedNode ( RelVaultNode * changedNode ) |
|
{ |
|
// is there an 'OnVaultEvent' defined? |
|
if ( fPyFileMod && fPyFileMod->fPyFunctionInstances[fFunctionIdx] != nil ) |
|
{ |
|
PyObject* ptuple = PyTuple_New(1); |
|
PyTuple_SetItem(ptuple, 0, pyVaultNode::New(changedNode)); |
|
// call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFileMod->fPyFunctionInstances[fFunctionIdx], |
|
fPyFileMod->fFunctionNames[fFunctionIdx], |
|
"lO",pyVault::kVaultNodeSaved,ptuple); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFileMod->fPyFunctionInstances[fFunctionIdx] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
fPyFileMod->ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(ptuple); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
fPyFileMod->DisplayPythonOutput(); |
|
} |
|
} |
|
}; |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Class : pfPythonKeyCatcher |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : Small wrapper class to catch discarded key events and pass |
|
// them to a plPythonFileMod |
|
// |
|
|
|
class pfPythonKeyCatcher : public plDefaultKeyCatcher |
|
{ |
|
plPythonFileMod *fMod; |
|
|
|
public: |
|
pfPythonKeyCatcher( plPythonFileMod *mod ) : fMod( mod ) {} |
|
|
|
virtual void HandleKeyEvent( plKeyEventMsg *event ) |
|
{ |
|
fMod->HandleDiscardedKey( event ); |
|
} |
|
}; |
|
|
|
hsBool plPythonFileMod::fAtConvertTime = false; |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : plPythonFileMod and ~plPythonFileMod |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : Constructor and destructor |
|
// |
|
plPythonFileMod::plPythonFileMod() |
|
{ |
|
fPythonFile = nil; |
|
fModuleName = nil; |
|
fModule = nil; |
|
fLocalNotify= true; |
|
fIsFirstTimeEval = true; |
|
fVaultCallback = nil; |
|
fSDLMod = nil; |
|
fSelfKey = nil; |
|
fInstance = nil; |
|
fKeyCatcher = nil; |
|
fPipe = nil; |
|
fAmIAttachedToClone = false; |
|
|
|
// assume that all the functions are not available |
|
// ...if the functions are defined in the module, then we'll call 'em |
|
int i; |
|
for (i=0 ; i<kfunc_lastone; i++) |
|
fPyFunctionInstances[i] = nil; |
|
} |
|
|
|
plPythonFileMod::~plPythonFileMod() |
|
{ |
|
if ( !fAtConvertTime ) // if this is just an Add that's during a convert, then don't do anymore |
|
{ |
|
// remove our reference to the instance (but only if we made one) |
|
if(fInstance) |
|
{ |
|
if ( fInstance->ob_refcnt > 1) |
|
Py_DECREF(fInstance); |
|
// then have the glue delete the instance of class |
|
PyObject* delInst = PythonInterface::GetModuleItem("glue_delInst",fModule); |
|
if ( delInst!=nil && PyCallable_Check(delInst) ) |
|
{ |
|
PyObject* retVal = PyObject_CallFunction(delInst,nil); |
|
if ( retVal == nil ) |
|
{ |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
// display any output |
|
DisplayPythonOutput(); |
|
} |
|
} |
|
fInstance = nil; |
|
} |
|
|
|
// If we have a key catcher, get rid of it |
|
delete fKeyCatcher; |
|
fKeyCatcher = nil; |
|
|
|
// if we created a Vault callback, undo it and get rid of it |
|
if (fVaultCallback) |
|
{ |
|
// Set the callback for the vault thingy |
|
VaultUnregisterCallback(fVaultCallback); |
|
delete fVaultCallback; |
|
fVaultCallback = nil; |
|
} |
|
|
|
if (fSelfKey) |
|
{ |
|
Py_DECREF(fSelfKey); |
|
fSelfKey = nil; |
|
} |
|
|
|
// get rid of the python code |
|
if ( fPythonFile ) |
|
{ |
|
delete [] fPythonFile; |
|
fPythonFile = nil; |
|
} |
|
// then get rid of this module |
|
// NOTE: fModule shouldn't be made in the plugin, only at runtime |
|
if ( fModuleName && fModule ) |
|
{ |
|
//_PyModule_Clear(fModule); |
|
PyObject *m; |
|
PyObject *modules = PyImport_GetModuleDict(); |
|
if( modules && (m = PyDict_GetItemString(modules, fModuleName)) && PyModule_Check(m)) |
|
{ |
|
hsStatusMessageF("Module %s removed from python dictionary",fModuleName); |
|
PyDict_DelItemString(modules, fModuleName); |
|
} |
|
else |
|
{ |
|
hsStatusMessageF("Module %s not found in python dictionary. Already removed?",fModuleName); |
|
} |
|
// the above code should have unloaded the module from python, so it will delete itself, therefore |
|
// we need to set our pointer to nil to make sure we don't try to use it |
|
fModule = nil; |
|
} |
|
delete [] fModuleName; |
|
fModuleName = nil; |
|
} |
|
|
|
#include "plPythonPack.h" |
|
|
|
bool plPythonFileMod::ILoadPythonCode() |
|
{ |
|
|
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// get code from file and execute in module |
|
// see if the file exists first before trying to import it |
|
char pathandfile[256]; |
|
sprintf(pathandfile, ".\\python\\%s.py",fPythonFile); |
|
wchar *wPathandfile = hsStringToWString(pathandfile); |
|
hsBool exists = PathDoesFileExist(wPathandfile); |
|
delete [] wPathandfile; |
|
if (exists) |
|
{ |
|
char fromLoad[256]; |
|
//sprintf(fromLoad,"from %s import *", fPythonFile); |
|
// ok... we can't really use import because Python remembers too much where global variables came from |
|
// ...and using execfile make it sure that globals are defined in this module and not in the imported module |
|
sprintf(fromLoad,"execfile('.\\\\python\\\\%s.py')", fPythonFile); |
|
if ( PythonInterface::RunString( fromLoad, fModule) ) |
|
{ |
|
// we've loaded the code into our module |
|
// now attach the glue python code to the end |
|
if ( !PythonInterface::RunString("execfile('.\\\\python\\\\plasma\\\\glue.py')", fModule) ) |
|
{ |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
return false; |
|
} |
|
else |
|
return true; |
|
} |
|
DisplayPythonOutput(); |
|
char errMsg[256]; |
|
sprintf(errMsg,"Python file %s.py had errors!!! Could not load.",fPythonFile); |
|
PythonInterface::WriteToLog(errMsg); |
|
hsAssert(0,errMsg); |
|
return false; |
|
} |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
|
|
// Finally, try and find the file in the Python packfile |
|
// ... for the external users .pak file is only used |
|
PyObject* pythonCode = PythonPack::OpenPythonPacked(fPythonFile); |
|
if (pythonCode && PythonInterface::RunPYC(pythonCode, fModule)) |
|
return true; |
|
|
|
DisplayPythonOutput(); |
|
char errMsg[256]; |
|
sprintf(errMsg,"Python file %s.py was not found.",fPythonFile); |
|
PythonInterface::WriteToLog(errMsg); |
|
hsAssert(0,errMsg); |
|
return false; |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : AddTarget |
|
// PARAMETERS : sobj - object to add as our target |
|
// |
|
// PURPOSE : Get the Key of our target |
|
// |
|
// NOTE: This modifier wasn't intended to have multiple targets |
|
// |
|
void plPythonFileMod::AddTarget(plSceneObject* sobj) |
|
{ |
|
plMultiModifier::AddTarget(sobj); |
|
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey()); |
|
plgDispatch::Dispatch()->RegisterForExactType(plPlayerPageMsg::Index(), GetKey()); |
|
plgDispatch::Dispatch()->RegisterForExactType(plAgeBeginLoadingMsg::Index(), GetKey()); |
|
plgDispatch::Dispatch()->RegisterForExactType(plInitialAgeStateLoadedMsg::Index(), GetKey()); |
|
// initialize the python stuff |
|
if ( !fAtConvertTime ) // if this is just an Add that's during a convert, then don't do anymore |
|
{ |
|
// was there a python file module with this? |
|
if ( fPythonFile ) |
|
{ |
|
// has the module not been initialized yet |
|
if ( !fModule ) |
|
{ |
|
plKey pkey = sobj->GetKey(); |
|
// nope, must be the first object. Then use it as the basis for the module |
|
char modulename[256]; |
|
IMakeModuleName(modulename,sobj); |
|
delete [] fModuleName; |
|
fModuleName = StrDup(modulename); |
|
fModule = PythonInterface::CreateModule(modulename); |
|
|
|
// if we can't create the instance then there is nothing to do here |
|
if (!ILoadPythonCode()) |
|
{ |
|
// things are getting off on a bad foot... just say there wasn't a module... |
|
fModule = nil; |
|
return; |
|
} |
|
|
|
// set the name of the file (in the global dictionary of the module) |
|
PyObject* dict = PyModule_GetDict(fModule); |
|
PyObject* pfilename = PyString_FromString(fPythonFile); |
|
PyDict_SetItemString(dict, "glue_name", pfilename); |
|
// next we need to: |
|
// - create instance of class |
|
PyObject* getInst = PythonInterface::GetModuleItem("glue_getInst",fModule); |
|
fInstance = nil; |
|
if ( getInst!=nil && PyCallable_Check(getInst) ) |
|
{ |
|
fInstance = PyObject_CallFunction(getInst,nil); |
|
if ( fInstance == nil ) |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
// display any output |
|
DisplayPythonOutput(); |
|
if ( fInstance == nil ) // then there was an error |
|
{ |
|
// display any output (NOTE: this would be disabled in production) |
|
char errMsg[256]; |
|
sprintf(errMsg,"Python file %s.py, instance not found.",fPythonFile); |
|
PythonInterface::WriteToLog(errMsg); |
|
hsAssert(0, errMsg); |
|
return; // if we can't create the instance then there is nothing to do here |
|
} |
|
|
|
// Add the SDL modifier |
|
if (plPythonSDLModifier::HasSDL(fPythonFile)) |
|
{ |
|
plSceneObject* sceneObj = plSceneObject::ConvertNoRef(GetTarget(0)->GetKey()->ObjectIsLoaded()); |
|
if (sceneObj) |
|
{ |
|
hsAssert(!fSDLMod, "Python SDL modifier already created"); |
|
fSDLMod = TRACKED_NEW plPythonSDLModifier(this); |
|
sceneObj->AddModifier(fSDLMod); |
|
} |
|
} |
|
|
|
// - set the self.key and self.sceneobject in the instance of the class |
|
// create the pyKey for this modifier |
|
fSelfKey = pyKey::New(GetKey(),this); |
|
// set the selfKey as an attribute to their instance |
|
PyObject_SetAttrString(fInstance, "key", fSelfKey); |
|
// create the sceneobject |
|
PyObject* pSobj = pySceneObject::New(pkey, fSelfKey); |
|
// set the sceneobject as an attribute to their instance |
|
PyObject_SetAttrString(fInstance, "sceneobject", pSobj); |
|
Py_DECREF(pSobj); |
|
// set the isInitialStateLoaded to not loaded... yet |
|
PyObject* pInitialState = PyInt_FromLong(0); |
|
PyObject_SetAttrString(fInstance, "isInitialStateLoaded", pInitialState); |
|
Py_DECREF(pInitialState); |
|
// Give the SDL mod to Python |
|
if (fSDLMod) |
|
{ |
|
PyObject* pSDL = pySDLModifier::New(fSDLMod); |
|
PyObject_SetAttrString(fInstance, "SDL", pSDL); |
|
Py_DECREF(pSDL); |
|
} |
|
|
|
// - set the parameters |
|
PyObject* setParams = PythonInterface::GetModuleItem("glue_setParam",fModule); |
|
PyObject* check_isNamed = PythonInterface::GetModuleItem("glue_isNamedAttribute",fModule); |
|
if ( setParams!=nil && PyCallable_Check(setParams) ) |
|
{ |
|
// loop throught the parameters and set them by id |
|
// (will need to create the appropiate Python object for each type) |
|
int nparam; |
|
for ( nparam=0; nparam<GetParameterListCount() ; nparam++ ) |
|
{ |
|
plPythonParameter parameter = GetParameterItem(nparam); |
|
// create the python object that matches the type |
|
// (NOTE: this relies on function created above to help create Plasma python objects) |
|
PyObject* value = nil; // assume that there is no conversion available |
|
int isNamedAttr = 0; |
|
PyObject* retvalue; |
|
switch (parameter.fValueType) |
|
{ |
|
case plPythonParameter::kInt: |
|
value = PyInt_FromLong(parameter.datarecord.fIntNumber); |
|
break; |
|
case plPythonParameter::kFloat: |
|
value = PyFloat_FromDouble(parameter.datarecord.fFloatNumber); |
|
break; |
|
case plPythonParameter::kBoolean: |
|
value = PyInt_FromLong(parameter.datarecord.fBool); |
|
break; |
|
case plPythonParameter::kString: |
|
case plPythonParameter::kAnimationName: |
|
isNamedAttr = 0; |
|
if ( check_isNamed!=nil && PyCallable_Check(check_isNamed) ) |
|
{ |
|
retvalue = PyObject_CallFunction(check_isNamed,"l", parameter.fID); |
|
if ( retvalue == nil ) |
|
{ |
|
ReportError(); |
|
DisplayPythonOutput(); |
|
} |
|
if ( retvalue && PyInt_Check(retvalue) ) |
|
isNamedAttr = PyInt_AsLong(retvalue); |
|
Py_XDECREF(retvalue); |
|
// is it a NamedActivator |
|
if ( isNamedAttr == 1 || isNamedAttr == 2) |
|
{ |
|
if (plAgeLoader::GetInstance()->IsLoadingAge()) |
|
{ |
|
NamedComponent comp; |
|
comp.isActivator = (isNamedAttr == 1); |
|
comp.id = parameter.fID; |
|
comp.name = TRACKED_NEW char[strlen(parameter.datarecord.fString) + 1]; |
|
strcpy(comp.name, parameter.datarecord.fString); |
|
|
|
fNamedCompQueue.Append(comp); |
|
} |
|
else |
|
{ |
|
if (isNamedAttr == 1) |
|
IFindActivatorAndAdd(parameter.datarecord.fString, parameter.fID); |
|
else |
|
IFindResponderAndAdd(parameter.datarecord.fString, parameter.fID); |
|
} |
|
} |
|
} |
|
// if it wasn't a named string then must be normal string type |
|
if ( isNamedAttr == 0 ) |
|
if ( parameter.datarecord.fString != nil ) |
|
value = PyString_FromString(parameter.datarecord.fString); |
|
break; |
|
case plPythonParameter::kSceneObject: |
|
case plPythonParameter::kSceneObjectList: |
|
if ( parameter.fObjectKey != nil ) |
|
{ |
|
// create the sceneobject |
|
value = pySceneObject::New(parameter.fObjectKey, fSelfKey); |
|
} |
|
break; |
|
case plPythonParameter::kActivatorList: |
|
case plPythonParameter::kResponderList: |
|
case plPythonParameter::kDynamicText: |
|
case plPythonParameter::kGUIDialog: |
|
case plPythonParameter::kExcludeRegion: |
|
case plPythonParameter::kAnimation: |
|
case plPythonParameter::kBehavior: |
|
case plPythonParameter::kMaterial: |
|
case plPythonParameter::kGUIPopUpMenu: |
|
case plPythonParameter::kGUISkin: |
|
case plPythonParameter::kWaterComponent: |
|
case plPythonParameter::kSwimCurrentInterface: |
|
case plPythonParameter::kClusterComponentList: |
|
case plPythonParameter::kMaterialAnimation: |
|
case plPythonParameter::kGrassShaderComponent: |
|
if ( parameter.fObjectKey != nil ) |
|
{ |
|
// create pyKey for the object |
|
value = pyKey::New(parameter.fObjectKey); |
|
} |
|
break; |
|
} |
|
// if there is a value that was converted then tell the Python code |
|
if ( value != nil ) |
|
{ |
|
PyObject* retVal = PyObject_CallFunction(setParams,"lO", parameter.fID, value); |
|
if ( retVal == nil ) |
|
{ |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(value); |
|
} |
|
} |
|
} |
|
|
|
// check if we need to register named activators or responders |
|
if (fNamedCompQueue.Count() > 0) |
|
{ |
|
plgDispatch::Dispatch()->RegisterForExactType( plAgeLoadedMsg::Index(), GetKey() ); |
|
} |
|
|
|
// - find functions in class they've defined. |
|
PythonInterface::CheckInstanceForFunctions(fInstance,fFunctionNames,fPyFunctionInstances); |
|
// clear any errors created by checking for methods in a class |
|
PyErr_Clear(); // clear the error |
|
// register for messages that they have functions defined for |
|
// register for PageLoaded message if needed |
|
if ( fPyFunctionInstances[kfunc_PageLoad] != nil ) |
|
{ |
|
// register for plRoomLoadNotifyMsg |
|
plgDispatch::Dispatch()->RegisterForExactType(plRoomLoadNotifyMsg::Index(), GetKey()); |
|
} |
|
|
|
// register for ClothingUpdate message if needed |
|
if ( fPyFunctionInstances[kfunc_ClothingUpdate] != nil ) |
|
{ |
|
// register for plRoomLoadNotifyMsg |
|
plgDispatch::Dispatch()->RegisterForExactType(plClothingUpdateBCMsg::Index(), GetKey()); |
|
} |
|
|
|
// register for pfKIMsg message if needed |
|
if ( fPyFunctionInstances[kfunc_KIMsg] != nil ) |
|
{ |
|
// register for pfKIMsg |
|
plgDispatch::Dispatch()->RegisterForExactType(pfKIMsg::Index(), GetKey()); |
|
} |
|
|
|
// register for Member update message if needed |
|
if ( fPyFunctionInstances[kfunc_MemberUpdate] != nil ) |
|
{ |
|
// register for plMemberUpdateMsg |
|
plgDispatch::Dispatch()->RegisterForExactType(plMemberUpdateMsg::Index(), GetKey()); |
|
} |
|
|
|
// register for Remote Avatar Info message if needed |
|
if ( fPyFunctionInstances[kfunc_RemoteAvatarInfo] != nil ) |
|
{ |
|
// register for plRemoteAvatarInfoMsg |
|
plgDispatch::Dispatch()->RegisterForExactType(plRemoteAvatarInfoMsg::Index(), GetKey()); |
|
} |
|
|
|
// register for CCR message if needed |
|
if ( fPyFunctionInstances[kfunc_OnCCRMsg] != nil ) |
|
{ |
|
// register for plCCRCommunicationMsg |
|
plgDispatch::Dispatch()->RegisterForExactType(plCCRCommunicationMsg::Index(), GetKey()); |
|
} |
|
|
|
// register for VaultNotify message if needed |
|
if ( fPyFunctionInstances[kfunc_OnVaultNotify] != nil ) |
|
{ |
|
// register for plVaultNotifyMsg |
|
plgDispatch::Dispatch()->RegisterForExactType(plVaultNotifyMsg::Index(), GetKey()); |
|
} |
|
|
|
// register for Owndership change notification message if needed |
|
if ( fPyFunctionInstances[kfunc_OwnershipNotify] != nil ) |
|
{ |
|
// register for plNetOwnershipMsg |
|
plgDispatch::Dispatch()->RegisterForExactType(plNetOwnershipMsg::Index(), GetKey()); |
|
} |
|
|
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// register for Backdoor message if needed |
|
if ( fPyFunctionInstances[kfunc_OnBackdoorMsg] != nil ) |
|
{ |
|
// register for pfDebugTriggerMsg |
|
plgDispatch::Dispatch()->RegisterForExactType(pfBackdoorMsg::Index(), GetKey()); |
|
} |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
|
|
// register for VaultCallback events if needed |
|
if ( fPyFunctionInstances[kfunc_VaultEvent] != nil ) |
|
{ |
|
// create the callback object |
|
// Set the callback for the vault thingy |
|
fVaultCallback = TRACKED_NEW PythonVaultCallback( this, kfunc_VaultEvent ); |
|
VaultRegisterCallback(fVaultCallback); |
|
} |
|
|
|
// register ourselves to be the default key catcher if necessary |
|
if ( fPyFunctionInstances[kfunc_OnDefaultKeyCaught] != nil ) |
|
{ |
|
// Make us a key catcher |
|
fKeyCatcher = TRACKED_NEW pfPythonKeyCatcher( this ); |
|
|
|
// Tell the input interface manager to use our catcher |
|
plInputInterfaceMgr::GetInstance()->SetDefaultKeyCatcher( fKeyCatcher ); |
|
} |
|
|
|
// register for Marker messages if needed |
|
if ( fPyFunctionInstances[kfunc_OnMarkerMsg] != nil ) |
|
{ |
|
plgDispatch::Dispatch()->RegisterForExactType(pfMarkerMsg::Index(), GetKey()); |
|
} |
|
|
|
// if they are going to get LOS hit messages then we need to get the Pipeline pointer |
|
if ( fPyFunctionInstances[kfunc_OnLOSNotify] != nil ) |
|
{ |
|
plgDispatch::Dispatch()->RegisterForExactType( plRenderMsg::Index(), GetKey() ); |
|
} |
|
|
|
// if this is a climbing-wall function, we need to register for climbing wall messages |
|
if ( fPyFunctionInstances[kfunc_OnClimbBlockerEvent] != nil) |
|
{ |
|
plgDispatch::Dispatch()->RegisterForExactType( plClimbEventMsg::Index(), GetKey() ); |
|
} |
|
if ( fPyFunctionInstances[kfunc_OnAvatarSpawn] != nil) |
|
{ |
|
plgDispatch::Dispatch()->RegisterForExactType( plAvatarSpawnNotifyMsg::Index(), GetKey() ); |
|
} |
|
if ( fPyFunctionInstances[kfunc_OnAccountUpdate] != nil) |
|
{ |
|
plgDispatch::Dispatch()->RegisterForExactType( plAccountUpdateMsg::Index(), GetKey() ); |
|
} |
|
if ( fPyFunctionInstances[kfunc_gotPublicAgeList] != nil) |
|
{ |
|
plgDispatch::Dispatch()->RegisterForExactType(plNetCommPublicAgeListMsg::Index(), GetKey()); |
|
} |
|
if ( fPyFunctionInstances[kfunc_OnGameMgrMsg] != nil) |
|
{ |
|
pfGameMgr::GetInstance()->AddReceiver(GetKey()); |
|
} |
|
if ( fPyFunctionInstances[kfunc_OnAIMsg] != nil) |
|
{ |
|
// the message that is spammed to anyone who will listen |
|
plgDispatch::Dispatch()->RegisterForExactType(plAIBrainCreatedMsg::Index(), GetKey()); |
|
} |
|
if (fPyFunctionInstances[kfunc_OnSubtitleMsg]) |
|
plgDispatch::Dispatch()->RegisterForExactType(plSubtitleMsg::Index(), GetKey()); |
|
|
|
// As the last thing... call the OnInit function if they have one |
|
if ( fPyFunctionInstances[kfunc_Init] != nil ) |
|
{ |
|
plProfile_BeginTiming(PythonUpdate); |
|
// call it |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_Init],fFunctionNames[kfunc_Init],nil); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_Init] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
} |
|
|
|
// display python output |
|
DisplayPythonOutput(); |
|
} |
|
else |
|
{ |
|
// else if module is already created... Then we are just adding an addition object to the already existing SceneObject |
|
if ( fInstance ) // make sure that we have an instance already also |
|
{ |
|
PyObject* dict = PyModule_GetDict(fModule); |
|
// create pyKey for the object |
|
PyObject* pkeyObj = pyKey::New(sobj->GetKey()); |
|
// need to get the instance, that holds the sceneobject that we are attached to |
|
PyObject* getInst = PythonInterface::GetModuleItem("glue_getInst",fModule); |
|
// get the sceneObject that should already be created |
|
PyObject* pSceneObject = PyObject_GetAttrString(fInstance,"sceneobject"); |
|
// add our new object to the list of objects that are in the _selfObject |
|
PyObject* retVal = PyObject_CallMethod(pSceneObject,"addKey","O",pkeyObj ); |
|
Py_XDECREF(retVal); |
|
// GetAttrString put a ref on pSceneObject, but we're done with it now. |
|
Py_XDECREF(pSceneObject); |
|
Py_DECREF(pkeyObj); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
void plPythonFileMod::RemoveTarget(plSceneObject* so) |
|
{ |
|
// remove sdl modifier |
|
if (fSDLMod) |
|
{ |
|
if (GetNumTargets() > 0) |
|
{ |
|
plSceneObject* sceneObj = plSceneObject::ConvertNoRef(GetTarget(0)->GetKey()->ObjectIsLoaded()); |
|
if (sceneObj && fSDLMod) |
|
sceneObj->RemoveModifier(fSDLMod); |
|
} |
|
delete fSDLMod; |
|
fSDLMod = nil; |
|
} |
|
|
|
plMultiModifier::RemoveTarget(so); |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : HandleDiscardedKey |
|
// PARAMETERS : msg - the key event message that was discarded |
|
// |
|
// PURPOSE : API for processing discarded keys as the deafult key catcher |
|
// |
|
|
|
void plPythonFileMod::HandleDiscardedKey( plKeyEventMsg *msg ) |
|
{ |
|
// So OnDefaultKeyCaught takes two parameters: the key character pressed and a boolean saying up or down |
|
char keyChar = plKeyboardDevice::KeyEventToChar( msg ); |
|
|
|
// if the caps lock is down then reverse upper and lowercase |
|
if ( msg->GetCapsLockKeyDown() ) |
|
{ |
|
if ( std::islower(keyChar,std::locale()) ) |
|
keyChar = std::toupper(keyChar,std::locale()); |
|
else |
|
keyChar = std::tolower(keyChar,std::locale()); |
|
} |
|
|
|
if (!fPyFunctionInstances[kfunc_OnDefaultKeyCaught]) |
|
return; |
|
|
|
plProfile_BeginTiming( PythonUpdate ); |
|
|
|
PyObject* retVal = PyObject_CallMethod( fPyFunctionInstances[ kfunc_OnDefaultKeyCaught ], |
|
fFunctionNames[ kfunc_OnDefaultKeyCaught ], |
|
"ciiiii", |
|
keyChar, |
|
(int)msg->GetKeyDown(), |
|
(int)msg->GetRepeat(), |
|
(int)msg->GetShiftKeyDown(), |
|
(int)msg->GetCtrlKeyDown(), |
|
(int)msg->GetKeyCode() ); |
|
if( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[ kfunc_OnDefaultKeyCaught ] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
|
|
plProfile_EndTiming( PythonUpdate ); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : IMakeModuleName |
|
// PARAMETERS : sobj - object to add as our target |
|
// |
|
// PURPOSE : Get the Key of our target |
|
// |
|
// NOTE: This modifier wasn't intended to have multiple targets |
|
// |
|
void plPythonFileMod::IMakeModuleName(char* modulename,plSceneObject* sobj) |
|
{ |
|
// Forgive my general crapulance... |
|
// This strips underscores out of module names |
|
// so python won't truncate them... -S |
|
|
|
plKey pKey = GetKey(); |
|
plKey sKey = sobj->GetKey(); |
|
|
|
const char* pKeyName = pKey->GetName(); |
|
const char* pSobjName = sKey->GetName(); |
|
|
|
UInt16 len = hsStrlen(pKeyName); |
|
UInt16 slen = hsStrlen(pSobjName); |
|
|
|
hsAssert(len+slen < 256, "Warning: String length exceeds 256 characters."); |
|
|
|
int i, k = 0; |
|
for(i = 0; i < slen; i++) |
|
{ |
|
if(pSobjName[i] == '_') continue; |
|
|
|
modulename[k++] = pSobjName[i]; |
|
} |
|
for(i = 0; i < len; i++) |
|
{ |
|
if(pKeyName[i] == '_') continue; |
|
|
|
modulename[k++] = pKeyName[i]; |
|
} |
|
|
|
modulename[k] = '\0'; |
|
|
|
// check to see if we are attaching to a clone? |
|
plKeyImp* pKeyImp = (plKeyImp*)(sKey); |
|
if (pKeyImp->GetCloneOwner()) |
|
{ |
|
// we have an owner... so we must be a clone. |
|
// add the cloneID to the end of the module name |
|
// and set the fIAmAClone flag |
|
UInt32 cloneID = pKeyImp->GetUoid().GetCloneID(); |
|
sprintf(modulename,"%s%d",modulename,cloneID); |
|
fAmIAttachedToClone = true; |
|
} |
|
|
|
// make sure that the actual modulue will be uniqie |
|
if ( !PythonInterface::IsModuleNameUnique(modulename) ) |
|
{ |
|
// if not unique then add the sequence number to the end of the modulename |
|
UInt32 seqID = pKeyImp->GetUoid().GetLocation().GetSequenceNumber(); |
|
sprintf(modulename,"%s%d",modulename,seqID); |
|
} |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : ISetKeyValue |
|
// PARAMETERS : key to responder, parameter id |
|
// |
|
// PURPOSE : set the param in the python file |
|
// : so named stuff works |
|
// |
|
void plPythonFileMod::ISetKeyValue(const plKey& key, Int32 id) |
|
{ |
|
PyObject* setParams = PythonInterface::GetModuleItem("glue_setParam",fModule); |
|
|
|
if ( setParams != nil && PyCallable_Check(setParams) ) |
|
{ |
|
if ( key != nil ) |
|
{ |
|
// create pyKey for the object |
|
PyObject* value = pyKey::New(key); |
|
|
|
if ( value != nil ) |
|
{ |
|
PyObject* retVal = PyObject_CallFunction(setParams,"lO", id, value); |
|
if ( retVal == nil ) |
|
{ |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(value); |
|
} |
|
} |
|
} |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : IFindResponderAndAdd |
|
// PARAMETERS : ResponderName - name of the responder to find |
|
// |
|
// PURPOSE : find a responder by name in all age and page locations |
|
// : and add to the Parameter list |
|
// |
|
void plPythonFileMod::IFindResponderAndAdd(const char *responderName, Int32 id) |
|
{ |
|
if ( responderName != nil ) |
|
{ |
|
std::vector<plKey> keylist; |
|
const plLocation &loc = GetKey()->GetUoid().GetLocation(); |
|
plKeyFinder::Instance().ReallyStupidResponderSearch(responderName,keylist,loc); // use the really stupid search to find the responder |
|
// the keylist will be filled with all the keys that correspond to that responder |
|
int list_size = keylist.size(); |
|
int i; |
|
for ( i=0 ; i<list_size; i++ ) |
|
{ |
|
plPythonParameter parm(id); |
|
parm.SetToResponder(keylist[i]); |
|
AddParameter(parm); |
|
ISetKeyValue(keylist[i], id); |
|
} |
|
} |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : IFindActivatorAndAdd |
|
// PARAMETERS : ResponderName - name of the responder to find |
|
// |
|
// PURPOSE : find a responder by name in all age and page locations |
|
// : and add to the Parameter list |
|
// |
|
void plPythonFileMod::IFindActivatorAndAdd(const char *activatorName, Int32 id) |
|
{ |
|
if ( activatorName != nil ) |
|
{ |
|
std::vector<plKey> keylist; |
|
const plLocation &loc = GetKey()->GetUoid().GetLocation(); |
|
plKeyFinder::Instance().ReallyStupidActivatorSearch(activatorName,keylist, loc); // use the really stupid search to find the responder |
|
// the keylist will be filled with all the keys that correspond to that responder |
|
int list_size = keylist.size(); |
|
// create the Python object that is the list, starts as empty |
|
int i; |
|
for ( i=0 ; i<list_size; i++ ) |
|
{ |
|
plPythonParameter parm(id); |
|
parm.SetToActivator(keylist[i]); |
|
AddParameter(parm); |
|
ISetKeyValue(keylist[i], id); |
|
|
|
// need to add ourselves as a receiver to their list |
|
// first see if it is an logicMod, then add to their receiver list |
|
plLogicModifier *logic = plLogicModifier::ConvertNoRef(keylist[i]->ObjectIsLoaded()); |
|
if (logic) |
|
{ |
|
logic->AddNotifyReceiver(this->GetKey()); |
|
} |
|
else // else might be a python file key |
|
{ |
|
// next check to see if it is another PythonFileMod, and add to their notify list |
|
plPythonFileMod *pymod = plPythonFileMod::ConvertNoRef(keylist[i]->ObjectIsLoaded()); |
|
if (pymod) |
|
{ |
|
pymod->AddToNotifyList(this->GetKey()); |
|
} |
|
else // else maybe its just not loaded yet |
|
{ |
|
// setup a ref notify when it does get loaded |
|
hsgResMgr::ResMgr()->AddViaNotify(keylist[i], |
|
TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, kAddNotify, 0), |
|
plRefFlags::kPassiveRef); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : IEval |
|
// PARAMETERS : secs |
|
// del |
|
// dirty |
|
// |
|
// PURPOSE : This is where the main update work is done |
|
// Tasks: |
|
// - Call the Python code's Update function (if there) |
|
// |
|
hsBool plPythonFileMod::IEval(double secs, hsScalar del, UInt32 dirty) |
|
{ |
|
if ( fModule ) |
|
{ |
|
// if this is the first time at the Eval, then run Python init |
|
if ( fIsFirstTimeEval ) |
|
{ |
|
fIsFirstTimeEval = false; // no longer the first time |
|
// now run the __init__ function if there is one. |
|
// is the Update function defined and working (as far as we know)? |
|
if ( fPyFunctionInstances[kfunc_FirstUpdate] != nil ) |
|
{ |
|
plProfile_BeginTiming(PythonUpdate); |
|
// call it |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_FirstUpdate],fFunctionNames[kfunc_FirstUpdate],nil); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_FirstUpdate] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
} |
|
} |
|
|
|
// is the Update function defined and working (as far as we know)? |
|
if ( fPyFunctionInstances[kfunc_Update] != nil ) |
|
{ |
|
plProfile_BeginTiming(PythonUpdate); |
|
// call it |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_Update],fFunctionNames[kfunc_Update],"df",secs,del); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_Update] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : MsgReceive |
|
// PARAMETERS : msg - the message that came to us. |
|
// |
|
// PURPOSE : Handle all the different types of messages that we recv |
|
// |
|
hsBool plPythonFileMod::MsgReceive(plMessage* msg) |
|
{ |
|
// is it a ref message |
|
plGenRefMsg* genRefMsg = plGenRefMsg::ConvertNoRef(msg); |
|
if (genRefMsg) |
|
{ |
|
// is it a ref for a named activator that we need to add to notify? |
|
if ((genRefMsg->GetContext() & plRefMsg::kOnCreate) && genRefMsg->fWhich == kAddNotify) |
|
{ |
|
// which kind of activator is this |
|
plLogicModifier *logic = plLogicModifier::ConvertNoRef(genRefMsg->GetRef()); |
|
if (logic) |
|
{ |
|
logic->AddNotifyReceiver(this->GetKey()); |
|
} |
|
else // else might be a python file key |
|
{ |
|
// next check to see if it is another PythonFileMod, and add to their notify list |
|
plPythonFileMod *pymod = plPythonFileMod::ConvertNoRef(genRefMsg->GetRef()); |
|
if (pymod) |
|
{ |
|
pymod->AddToNotifyList(this->GetKey()); |
|
} |
|
} |
|
} |
|
} |
|
|
|
plAgeLoadedMsg* ageLoadedMsg = plAgeLoadedMsg::ConvertNoRef(msg); |
|
if (ageLoadedMsg && ageLoadedMsg->fLoaded) |
|
{ |
|
for (int i = 0; i < fNamedCompQueue.Count(); ++i) |
|
{ |
|
NamedComponent comp = fNamedCompQueue[i]; |
|
if (comp.isActivator) |
|
IFindActivatorAndAdd(comp.name, comp.id); |
|
else |
|
IFindResponderAndAdd(comp.name, comp.id); |
|
|
|
delete [] comp.name; |
|
} |
|
|
|
fNamedCompQueue.Reset(); |
|
|
|
plgDispatch::Dispatch()->UnRegisterForExactType( plAgeLoadedMsg::Index(), GetKey() ); |
|
} |
|
|
|
// if this is a render message, then we are just trying to get a pointer to the Pipeline |
|
plRenderMsg *rMsg = plRenderMsg::ConvertNoRef( msg ); |
|
if( rMsg != nil ) |
|
{ |
|
fPipe = rMsg->Pipeline(); |
|
plgDispatch::Dispatch()->UnRegisterForExactType( plRenderMsg::Index(), GetKey() ); |
|
return true; |
|
} |
|
|
|
// are they looking for an Notify message? should be coming from a proActivator |
|
if (fPyFunctionInstances[kfunc_Notify] != nil) |
|
{ |
|
// yes, so was there actually a plActivateMsg? |
|
plNotifyMsg* pNtfyMsg = plNotifyMsg::ConvertNoRef(msg); |
|
if (pNtfyMsg) |
|
{ |
|
// remember if this was a Local Broad cast or not |
|
fLocalNotify = (pNtfyMsg->HasBCastFlag(plMessage ::plBCastFlags::kNetNonLocal)) ? false : true; |
|
|
|
// create a list for the event records |
|
PyObject* levents = PyList_New(0); // start with a list of no elements |
|
// loop thought the event records to get the data and transform into python objects |
|
Int32 num_records = pNtfyMsg->GetEventCount(); |
|
int j; |
|
for ( j=0; j<num_records; j++ ) |
|
{ |
|
// get an event record |
|
proEventData* pED = pNtfyMsg->GetEventRecord(j); |
|
switch ( pED->fEventType ) |
|
{ |
|
|
|
case proEventData::kCollision: |
|
{ |
|
proCollisionEventData *eventData = (proCollisionEventData *)pED; |
|
// get data from the collision |
|
// create list |
|
PyObject* event = PyList_New(4); |
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kCollision)); |
|
PyList_SetItem(event, 1, PyInt_FromLong(eventData->fEnter ? 1 : 0)); |
|
PyList_SetItem(event, 2, pySceneObject::New(eventData->fHitter, fSelfKey)); |
|
PyList_SetItem(event, 3, pySceneObject::New(eventData->fHittee, fSelfKey)); |
|
// add this event record to the main event list (lists within a list) |
|
PyList_Append(levents, event); |
|
Py_DECREF(event); |
|
} |
|
break; |
|
|
|
case proEventData::kSpawned: |
|
{ |
|
proSpawnedEventData *eventData = (proSpawnedEventData *)pED; |
|
PyObject* event = PyList_New(3); |
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kSpawned)); |
|
PyList_SetItem(event, 1, pySceneObject::New(eventData->fSpawner, fSelfKey)); |
|
PyList_SetItem(event, 2, pySceneObject::New(eventData->fSpawnee, fSelfKey)); |
|
PyList_Append(levents, event); |
|
Py_DECREF(event); |
|
} |
|
break; |
|
|
|
case proEventData::kPicked: |
|
{ |
|
// get data from the picked event |
|
proPickedEventData *eventData = (proPickedEventData *)pED; |
|
// create list |
|
PyObject* event = PyList_New(6); |
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kPicked)); |
|
PyList_SetItem(event, 1, PyInt_FromLong(eventData->fEnabled ? 1 : 0)); |
|
PyList_SetItem(event, 2, pySceneObject::New(eventData->fPicker, fSelfKey)); |
|
PyList_SetItem(event, 3, pySceneObject::New(eventData->fPicked, fSelfKey)); |
|
PyList_SetItem(event, 4, pyPoint3::New(eventData->fHitPoint)); |
|
|
|
// make it in the local space |
|
hsPoint3 tolocal(0,0,0); |
|
if(eventData->fPicked) |
|
{ |
|
plSceneObject* obj = plSceneObject::ConvertNoRef(eventData->fPicked->ObjectIsLoaded()); |
|
if ( obj ) |
|
{ |
|
const plCoordinateInterface* ci = obj->GetCoordinateInterface(); |
|
if ( ci ) |
|
tolocal = (hsMatrix44)ci->GetWorldToLocal() * eventData->fHitPoint; |
|
} |
|
} |
|
PyList_SetItem(event, 5, pyPoint3::New(tolocal)); |
|
|
|
// add this event record to the main event list (lists within a list) |
|
PyList_Append(levents, event); |
|
Py_DECREF(event); |
|
} |
|
break; |
|
|
|
case proEventData::kControlKey: |
|
{ |
|
proControlKeyEventData *eventData = (proControlKeyEventData *)pED; |
|
// create event list |
|
PyObject* event = PyList_New(3); |
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kControlKey)); |
|
PyList_SetItem(event, 1, PyLong_FromLong(eventData->fControlKey)); |
|
PyList_SetItem(event, 2, PyInt_FromLong(eventData->fDown ? 1 : 0)); |
|
// add this event record to the main event list (lists within a list) |
|
PyList_Append(levents, event); |
|
Py_DECREF(event); |
|
} |
|
break; |
|
|
|
case proEventData::kVariable: |
|
{ |
|
proVariableEventData *eventData = (proVariableEventData *)pED; |
|
// create event list |
|
PyObject* event = PyList_New(4); |
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kVariable)); |
|
PyList_SetItem(event, 1, PyString_FromString(eventData->fName)); |
|
PyList_SetItem(event, 2, PyLong_FromLong(eventData->fDataType)); |
|
|
|
// depending on the data type create the data |
|
switch ( eventData->fDataType ) |
|
{ |
|
case proEventData::kFloat: |
|
PyList_SetItem(event, 3, PyFloat_FromDouble(eventData->fNumber.f)); |
|
break; |
|
case proEventData::kKey: |
|
PyList_SetItem(event, 3, pyKey::New(eventData->fKey)); |
|
break; |
|
case proEventData::kInt: |
|
PyList_SetItem(event, 3, PyInt_FromLong(eventData->fNumber.i)); |
|
break; |
|
default: |
|
Py_XINCREF(Py_None); |
|
PyList_SetItem(event, 3, Py_None); |
|
break; |
|
} |
|
// add this event record to the main event list (lists within a list) |
|
PyList_Append(levents, event); |
|
Py_DECREF(event); |
|
} |
|
break; |
|
|
|
case proEventData::kFacing: |
|
{ |
|
proFacingEventData *eventData = (proFacingEventData *)pED; |
|
// create event list |
|
PyObject* event = PyList_New(5); |
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kFacing)); |
|
PyList_SetItem(event, 1, PyInt_FromLong(eventData->enabled ? 1 : 0)); |
|
PyList_SetItem(event, 2, pySceneObject::New(eventData->fFacer, fSelfKey)); |
|
PyList_SetItem(event, 3, pySceneObject::New(eventData->fFacee, fSelfKey)); |
|
PyList_SetItem(event, 4, PyFloat_FromDouble(eventData->dot)); |
|
// add this event record to the main event list (lists within a list) |
|
PyList_Append(levents, event); |
|
Py_DECREF(event); |
|
} |
|
break; |
|
|
|
case proEventData::kContained: |
|
{ |
|
proContainedEventData *eventData = (proContainedEventData *)pED; |
|
// create event list |
|
PyObject* event = PyList_New(4); |
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kContained)); |
|
PyList_SetItem(event, 1, PyInt_FromLong(eventData->fEntering ? 1 : 0)); |
|
PyList_SetItem(event, 2, pySceneObject::New(eventData->fContained, fSelfKey)); |
|
PyList_SetItem(event, 3, pySceneObject::New(eventData->fContainer, fSelfKey)); |
|
// add this event record to the main event list (lists within a list) |
|
PyList_Append(levents, event); |
|
Py_DECREF(event); |
|
} |
|
break; |
|
|
|
case proEventData::kActivate: |
|
{ |
|
proActivateEventData *eventData = (proActivateEventData *)pED; |
|
// create event list |
|
PyObject* event = PyList_New(3); |
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kActivate)); |
|
PyList_SetItem(event, 1, PyInt_FromLong(eventData->fActive ? 1 : 0)); |
|
PyList_SetItem(event, 2, PyInt_FromLong(eventData->fActivate ? 1 : 0)); |
|
// add this event record to the main event list (lists within a list) |
|
PyList_Append(levents, event); |
|
Py_DECREF(event); |
|
} |
|
break; |
|
|
|
case proEventData::kCallback: |
|
{ |
|
proCallbackEventData *eventData = (proCallbackEventData *)pED; |
|
// create event list |
|
PyObject* event = PyList_New(2); |
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kCallback)); |
|
PyList_SetItem(event, 1, PyLong_FromLong(eventData->fEventType)); |
|
// add this event record to the main event list (lists within a list) |
|
PyList_Append(levents, event); |
|
Py_DECREF(event); |
|
} |
|
break; |
|
|
|
case proEventData::kResponderState: |
|
{ |
|
proResponderStateEventData *eventData = (proResponderStateEventData *)pED; |
|
// create event list |
|
PyObject* event = PyList_New(2); |
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kResponderState)); |
|
PyList_SetItem(event, 1, PyLong_FromLong(eventData->fState)); |
|
// add this event record to the main event list (lists within a list) |
|
PyList_Append(levents, event); |
|
Py_DECREF(event); |
|
} |
|
break; |
|
|
|
case proEventData::kMultiStage: |
|
{ |
|
proMultiStageEventData *eventData = (proMultiStageEventData *)pED; |
|
// create event list |
|
PyObject* event = PyList_New(4); |
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kMultiStage)); |
|
PyList_SetItem(event, 1, PyLong_FromLong(eventData->fStage)); |
|
PyList_SetItem(event, 2, PyLong_FromLong(eventData->fEvent)); |
|
PyList_SetItem(event, 3, pySceneObject::New(eventData->fAvatar, fSelfKey)); |
|
// add this event record to the main event list (lists within a list) |
|
PyList_Append(levents, event); |
|
Py_DECREF(event); |
|
} |
|
break; |
|
case proEventData::kOfferLinkingBook: |
|
{ |
|
proOfferLinkingBookEventData* eventData = (proOfferLinkingBookEventData*)pED; |
|
// create event list |
|
PyObject* event = PyList_New(4); |
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kOfferLinkingBook)); |
|
PyList_SetItem(event, 1, pySceneObject::New(eventData->offerer, fSelfKey)); |
|
PyList_SetItem(event, 2, PyInt_FromLong(eventData->targetAge)); |
|
PyList_SetItem(event, 3, PyInt_FromLong(eventData->offeree)); |
|
PyList_Append(levents, event); |
|
Py_DECREF(event); |
|
} |
|
break; |
|
case proEventData::kBook: |
|
{ |
|
proBookEventData* eventData = (proBookEventData*)pED; |
|
// create event list |
|
PyObject* event = PyList_New(3); |
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kBook)); |
|
PyList_SetItem(event, 1, PyLong_FromUnsignedLong(eventData->fEvent)); |
|
PyList_SetItem(event, 2, PyLong_FromUnsignedLong(eventData->fLinkID)); |
|
PyList_Append(levents, event); |
|
Py_DECREF(event); |
|
} |
|
break; |
|
} |
|
} |
|
|
|
// Need to determine which of the Activators sent this plNotifyMsg |
|
// and set the ID appropriately |
|
Int32 id = -1; // assume that none was found |
|
if ( pNtfyMsg->GetSender() != nil ) |
|
{ |
|
// loop throught the parameters and set them by id |
|
// (will need to create the appropiate Python object for each type) |
|
int npm; |
|
for ( npm=0; npm<GetParameterListCount() ; npm++ ) |
|
{ |
|
plPythonParameter parameter = GetParameterItem(npm); |
|
// is it something that could produce a plNotifiyMsg? |
|
if ( parameter.fValueType == plPythonParameter::kActivatorList |
|
|| parameter.fValueType == plPythonParameter::kBehavior |
|
|| parameter.fValueType == plPythonParameter::kResponderList ) |
|
{ |
|
// is there an actual ObjectKey to look at? |
|
if (parameter.fObjectKey != nil ) |
|
{ |
|
// is it the same as the sender of the notify message? |
|
if ( pNtfyMsg->GetSender()->GetUoid() == parameter.fObjectKey->GetUoid() ) |
|
{ |
|
// match! Then return that as the ID |
|
id = parameter.fID; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
// call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_Notify],fFunctionNames[kfunc_Notify], |
|
"flO",pNtfyMsg->fState,id,levents); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_Notify] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(levents); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
// are they looking for a key event message? |
|
if (fPyFunctionInstances[kfunc_OnKeyEvent] != nil) |
|
{ |
|
// we are looking for collision messages, is it one? |
|
plControlEventMsg* pEMsg = plControlEventMsg::ConvertNoRef(msg); |
|
if (pEMsg) |
|
{ |
|
// call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnKeyEvent],fFunctionNames[kfunc_OnKeyEvent], |
|
"ll",pEMsg->GetControlCode(),pEMsg->ControlActivated()); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnKeyEvent] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
|
|
} |
|
|
|
// are they looking for an Timer message? |
|
if (fPyFunctionInstances[kfunc_AtTimer]) |
|
{ |
|
// yes, so was there actually a plActivateMsg? |
|
plTimerCallbackMsg* pTimerMsg = plTimerCallbackMsg::ConvertNoRef(msg); |
|
if (pTimerMsg) |
|
{ |
|
// yes... |
|
// call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_AtTimer],fFunctionNames[kfunc_AtTimer], |
|
"l",pTimerMsg->fID); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_AtTimer] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
// are they looking for an GUINotify message? |
|
if (fPyFunctionInstances[kfunc_GUINotify]) |
|
{ |
|
// yes, so was there actually a plActivateMsg? |
|
pfGUINotifyMsg* pGUIMsg = pfGUINotifyMsg::ConvertNoRef(msg); |
|
if (pGUIMsg) |
|
{ |
|
// yes... |
|
// call it ... but first create the control that started this mess |
|
// create the key |
|
PyObject* pyControl = nil; |
|
if ( pGUIMsg->GetControlKey() ) // make sure there is a control key |
|
{ |
|
// now create the control... but first we need to find out what it is |
|
PyObject* pyCtrlKey = pyKey::New(pGUIMsg->GetControlKey()); |
|
UInt32 control_type = pyGUIDialog::WhatControlType(*(pyKey::ConvertFrom(pyCtrlKey))); |
|
Py_DECREF(pyCtrlKey); |
|
|
|
switch (control_type) |
|
{ |
|
case pyGUIDialog::kDialog: |
|
pyControl = pyGUIDialog::New(pGUIMsg->GetControlKey()); |
|
break; |
|
|
|
case pyGUIDialog::kButton: |
|
pyControl = pyGUIControlButton::New(pGUIMsg->GetControlKey()); |
|
break; |
|
|
|
case pyGUIDialog::kListBox: |
|
pyControl = pyGUIControlListBox::New(pGUIMsg->GetControlKey()); |
|
break; |
|
|
|
case pyGUIDialog::kTextBox: |
|
pyControl = pyGUIControlTextBox::New(pGUIMsg->GetControlKey()); |
|
break; |
|
|
|
case pyGUIDialog::kEditBox: |
|
pyControl = pyGUIControlEditBox::New(pGUIMsg->GetControlKey()); |
|
break; |
|
|
|
case pyGUIDialog::kUpDownPair: |
|
case pyGUIDialog::kKnob: |
|
pyControl = pyGUIControlValue::New(pGUIMsg->GetControlKey()); |
|
break; |
|
|
|
case pyGUIDialog::kCheckBox: |
|
pyControl = pyGUIControlCheckBox::New(pGUIMsg->GetControlKey()); |
|
break; |
|
|
|
case pyGUIDialog::kRadioGroup: |
|
pyControl = pyGUIControlRadioGroup::New(pGUIMsg->GetControlKey()); |
|
break; |
|
|
|
case pyGUIDialog::kDynamicText: |
|
pyControl = pyGUIControlDynamicText::New(pGUIMsg->GetControlKey()); |
|
break; |
|
|
|
case pyGUIDialog::kMultiLineEdit: |
|
pyControl = pyGUIControlMultiLineEdit::New(pGUIMsg->GetControlKey()); |
|
break; |
|
|
|
case pyGUIDialog::kPopUpMenu: |
|
pyControl = pyGUIPopUpMenu::New(pGUIMsg->GetControlKey()); |
|
break; |
|
|
|
case pyGUIDialog::kClickMap: |
|
pyControl = pyGUIControlClickMap::New(pGUIMsg->GetControlKey()); |
|
break; |
|
|
|
default: |
|
// we don't know what it is... just send 'em the pyKey |
|
pyControl = pyKey::New(pGUIMsg->GetControlKey()); |
|
break; |
|
|
|
} |
|
} |
|
// Need to determine which of the GUIDialogs sent this plGUINotifyMsg |
|
// and set the ID appropriately |
|
Int32 id = -1; // assume that none was found |
|
if ( pGUIMsg->GetSender() != nil ) |
|
{ |
|
// loop throught the parameters and set them by id |
|
// (will need to create the appropiate Python object for each type) |
|
int npm; |
|
for ( npm=0; npm<GetParameterListCount() ; npm++ ) |
|
{ |
|
plPythonParameter parameter = GetParameterItem(npm); |
|
// is it something that could produce a plNotifiyMsg? |
|
if ( parameter.fValueType == plPythonParameter::kGUIDialog || parameter.fValueType == plPythonParameter::kGUIPopUpMenu ) |
|
{ |
|
// is there an actual ObjectKey to look at? |
|
if (parameter.fObjectKey != nil ) |
|
{ |
|
// is it the same of the sender of the notify message? |
|
if ( pGUIMsg->GetSender()->GetUoid() == parameter.fObjectKey->GetUoid() ) |
|
{ |
|
// match! then set the ID to what the parameter is, so the python programmer can find it |
|
id = parameter.fID; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
// make sure that we found a control to go with this |
|
if ( pyControl == nil ) |
|
{ |
|
// if none then return a Python None object |
|
Py_INCREF(Py_None); |
|
pyControl = Py_None; |
|
} |
|
|
|
// call their OnGUINotify method |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_GUINotify],fFunctionNames[kfunc_GUINotify], |
|
"lOl",id,pyControl,pGUIMsg->GetEvent() ); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_GUINotify] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(pyControl); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
// are they looking for an RoomLoadNotify message? |
|
if (fPyFunctionInstances[kfunc_PageLoad]) |
|
{ |
|
// yes, so was there actually a plRoomLoadNotifyMsg? |
|
plRoomLoadNotifyMsg* pRLNMsg = plRoomLoadNotifyMsg::ConvertNoRef(msg); |
|
if (pRLNMsg) |
|
{ |
|
// yes... |
|
// call it |
|
char* roomname = ""; |
|
if ( pRLNMsg->GetRoom() != nil ) |
|
roomname = (char*)pRLNMsg->GetRoom()->GetName(); |
|
|
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_PageLoad],fFunctionNames[kfunc_PageLoad], |
|
"ls",pRLNMsg->GetWhatHappen(),roomname); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_PageLoad] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
|
|
// are they looking for an ClothingUpdate message? |
|
if (fPyFunctionInstances[kfunc_ClothingUpdate]) |
|
{ |
|
// yes, so was there actually a plClothingUpdateBCMsg? |
|
plClothingUpdateBCMsg* pCUMsg = plClothingUpdateBCMsg::ConvertNoRef(msg); |
|
if (pCUMsg) |
|
{ |
|
// yes... |
|
// call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_ClothingUpdate],fFunctionNames[kfunc_ClothingUpdate],nil); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_ClothingUpdate] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
// are they looking for an KIMsg message? |
|
if (fPyFunctionInstances[kfunc_KIMsg]) |
|
{ |
|
// yes, so was there actually a pfKIMsg? |
|
pfKIMsg* pkimsg = pfKIMsg::ConvertNoRef(msg); |
|
if (pkimsg && pkimsg->GetCommand() != pfKIMsg::kHACKChatMsg) |
|
{ |
|
// yes... |
|
// find the value that would go with a command |
|
PyObject* value; |
|
std::wstring str; |
|
switch (pkimsg->GetCommand()) |
|
{ |
|
case pfKIMsg::kSetChatFadeDelay: |
|
value = PyFloat_FromDouble(pkimsg->GetDelay()); |
|
break; |
|
case pfKIMsg::kSetTextChatAdminMode: |
|
value = PyLong_FromLong(pkimsg->GetFlags()&pfKIMsg::kAdminMsg ? 1 : 0 ); |
|
break; |
|
case pfKIMsg::kYesNoDialog: |
|
value = PyTuple_New(2); |
|
str = pkimsg->GetStringU(); |
|
PyTuple_SetItem(value, 0, PyUnicode_FromWideChar(str.c_str(), str.length())); |
|
PyTuple_SetItem(value, 1, pyKey::New(pkimsg->GetSender())); |
|
break; |
|
case pfKIMsg::kGZInRange: |
|
value = PyTuple_New(2); |
|
PyTuple_SetItem(value, 0, PyLong_FromLong(pkimsg->GetIntValue())); |
|
PyTuple_SetItem(value, 1, pyKey::New(pkimsg->GetSender())); |
|
break; |
|
case pfKIMsg::kRateIt: |
|
value = PyTuple_New(3); |
|
str = pkimsg->GetStringU(); |
|
PyTuple_SetItem(value,0,PyString_FromString(pkimsg->GetUser())); |
|
PyTuple_SetItem(value,1,PyUnicode_FromWideChar(str.c_str(), str.length())); |
|
PyTuple_SetItem(value,2,PyLong_FromLong(pkimsg->GetIntValue())); |
|
break; |
|
case pfKIMsg::kRegisterImager: |
|
value = PyTuple_New(2); |
|
str = pkimsg->GetStringU(); |
|
PyTuple_SetItem(value, 0, PyUnicode_FromWideChar(str.c_str(), str.length())); |
|
PyTuple_SetItem(value, 1, pyKey::New(pkimsg->GetSender())); |
|
break; |
|
case pfKIMsg::kAddPlayerDevice: |
|
case pfKIMsg::kRemovePlayerDevice: |
|
{ |
|
str = pkimsg->GetStringU(); |
|
if ( str.length() > 0 ) |
|
value = PyUnicode_FromWideChar(str.c_str(), str.length()); |
|
else |
|
{ |
|
Py_INCREF(Py_None); |
|
value = Py_None; |
|
} |
|
} |
|
break; |
|
case pfKIMsg::kKIChatStatusMsg: |
|
case pfKIMsg::kKILocalChatStatusMsg: |
|
case pfKIMsg::kKILocalChatErrorMsg: |
|
case pfKIMsg::kKIOKDialog: |
|
case pfKIMsg::kKIOKDialogNoQuit: |
|
case pfKIMsg::kGZFlashUpdate: |
|
case pfKIMsg::kKICreateMarkerNode: |
|
str = pkimsg->GetStringU(); |
|
value = PyUnicode_FromWideChar(str.c_str(), str.length()); |
|
break; |
|
case pfKIMsg::kMGStartCGZGame: |
|
case pfKIMsg::kMGStopCGZGame: |
|
case pfKIMsg::kFriendInviteSent: |
|
default: |
|
value = PyLong_FromLong(pkimsg->GetIntValue()); |
|
break; |
|
} |
|
|
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_KIMsg],fFunctionNames[kfunc_KIMsg], |
|
"lO",pkimsg->GetCommand(),value); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_KIMsg] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(value); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
// are they looking for an MemberUpdate message? |
|
if (fPyFunctionInstances[kfunc_MemberUpdate]) |
|
{ |
|
// yes, so was there actually a plMemberUpdateMsg? |
|
plMemberUpdateMsg* pmumsg = plMemberUpdateMsg::ConvertNoRef(msg); |
|
if (pmumsg) |
|
{ |
|
// yes... then call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_MemberUpdate],fFunctionNames[kfunc_MemberUpdate],nil); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_MemberUpdate] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
// are they looking for a RemoteAvatar Info message? |
|
if (fPyFunctionInstances[kfunc_RemoteAvatarInfo]) |
|
{ |
|
// yes, so was there actually a plActivateMsg? |
|
plRemoteAvatarInfoMsg* pramsg = plRemoteAvatarInfoMsg::ConvertNoRef(msg); |
|
if (pramsg) |
|
{ |
|
// yes... |
|
PyObject* player; |
|
// if there was no avatar key in the message |
|
if ( pramsg->GetAvatarKey() == nil ) |
|
{ |
|
// then just return a None... same thing as nil.. which I guess means a non-avatar is selected |
|
player = PyInt_FromLong(0); |
|
} |
|
else |
|
{ |
|
// try to create the pyPlayer for where this message came from |
|
int mbrIndex = plNetClientMgr::GetInstance()->TransportMgr().FindMember(pramsg->GetAvatarKey()); |
|
if ( mbrIndex != -1 ) |
|
{ |
|
plNetTransportMember *mbr = plNetClientMgr::GetInstance()->TransportMgr().GetMember( mbrIndex ); |
|
player = pyPlayer::New(mbr->GetAvatarKey(), mbr->GetPlayerName(), mbr->GetPlayerID(), mbr->GetDistSq()); |
|
} |
|
else |
|
{ |
|
// else if we could not find the player in our list, then no avatar selected |
|
player = PyInt_FromLong(0); |
|
} |
|
} |
|
|
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_RemoteAvatarInfo],fFunctionNames[kfunc_RemoteAvatarInfo], |
|
"O",player); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_RemoteAvatarInfo] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(player); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
|
|
// are they looking for a CCR communication message? |
|
if (fPyFunctionInstances[kfunc_OnCCRMsg]) |
|
{ |
|
// yes, so was there actually a plActivateMsg? |
|
plCCRCommunicationMsg* ccrmsg = plCCRCommunicationMsg::ConvertNoRef(msg); |
|
if (ccrmsg) |
|
{ |
|
const char* textmessage = ccrmsg->GetMessage(); |
|
if ( textmessage == nil) |
|
textmessage = ""; |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnCCRMsg],fFunctionNames[kfunc_OnCCRMsg], |
|
"lsl",ccrmsg->GetType(),textmessage,ccrmsg->GetCCRPlayerID()); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnCCRMsg] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
|
|
// are they looking for a VaultNotify message? |
|
if (fPyFunctionInstances[kfunc_OnVaultNotify]) |
|
{ |
|
// yes, so was there actually a plVaultNotifyMsg? |
|
if (plVaultNotifyMsg * vaultNotifyMsg = plVaultNotifyMsg::ConvertNoRef(msg)) |
|
{ |
|
if ( hsSucceeded( vaultNotifyMsg->GetResultCode() ) ) |
|
{ |
|
// Create a tuple for second argument according to msg type. |
|
// Default to an empty tuple. |
|
PyObject* ptuple = PyTuple_New(0); |
|
switch ( vaultNotifyMsg->GetType() ) |
|
{ |
|
case plVaultNotifyMsg::kRegisteredOwnedAge: |
|
case plVaultNotifyMsg::kRegisteredVisitAge: |
|
case plVaultNotifyMsg::kUnRegisteredOwnedAge: |
|
case plVaultNotifyMsg::kUnRegisteredVisitAge: { |
|
if (RelVaultNode * rvn = VaultGetNodeIncRef(vaultNotifyMsg->GetArgs()->GetInt(plNetCommon::VaultTaskArgs::kAgeLinkNode))) { |
|
Py_DECREF(ptuple); |
|
ptuple = PyTuple_New(1); |
|
PyTuple_SetItem(ptuple, 0, pyVaultAgeLinkNode::New(rvn)); |
|
rvn->DecRef(); |
|
} |
|
} |
|
break; |
|
|
|
case plVaultNotifyMsg::kPublicAgeCreated: |
|
case plVaultNotifyMsg::kPublicAgeRemoved: { |
|
if (const char * ageName = vaultNotifyMsg->GetArgs()->GetString(plNetCommon::VaultTaskArgs::kAgeFilename)) { |
|
Py_DECREF(ptuple); |
|
ptuple = PyTuple_New(1); |
|
PyTuple_SetItem(ptuple, 0, PyString_FromString(ageName)); |
|
} |
|
} |
|
break; |
|
} |
|
|
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnVaultNotify],fFunctionNames[kfunc_OnVaultNotify], |
|
"lO",vaultNotifyMsg->GetType(),ptuple); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnVaultNotify] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(ptuple); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
} |
|
return true; |
|
} |
|
} |
|
|
|
|
|
// are they looking for a RealTimeChat message? |
|
if (fPyFunctionInstances[kfunc_RTChat]) |
|
{ |
|
// yes, so was there actually a pfKIMsg? |
|
pfKIMsg* pkimsg = pfKIMsg::ConvertNoRef(msg); |
|
if (pkimsg && pkimsg->GetCommand() == pfKIMsg::kHACKChatMsg) |
|
{ |
|
// yes... |
|
// filter ignored player |
|
if ( !VaultAmIgnoringPlayer( pkimsg->GetPlayerID() ) ) |
|
{ |
|
// create the pyPlayer for where this message came from |
|
PyObject* player; |
|
PyObject* ptPlayerClass = PythonInterface::GetPlasmaItem("ptPlayer"); |
|
hsAssert(ptPlayerClass,"Could not create a ptPlayer"); |
|
int mbrIndex = plNetClientMgr::GetInstance()->TransportMgr().FindMember(pkimsg->GetPlayerID()); |
|
if ( mbrIndex != -1 ) |
|
{ |
|
plNetTransportMember *mbr = plNetClientMgr::GetInstance()->TransportMgr().GetMember( mbrIndex ); |
|
player = pyPlayer::New(mbr->GetAvatarKey(), pkimsg->GetUser(), mbr->GetPlayerID(), mbr->GetDistSq()); |
|
} |
|
else |
|
{ |
|
// else if we could not find the player in our list, then just return a string of the user's name |
|
const char * fromName = pkimsg->GetUser(); |
|
if (!fromName) |
|
fromName = "Anonymous Coward"; |
|
player = pyPlayer::New(plNetClientMgr::GetInstance()->GetLocalPlayerKey(), fromName, pkimsg->GetPlayerID(), 0.0); |
|
} |
|
|
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_RTChat],fFunctionNames[kfunc_RTChat], |
|
"Osl",player,pkimsg->GetString().c_str(),pkimsg->GetFlags()); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_RTChat] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(player); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
} |
|
if (plPlayerPageMsg::ConvertNoRef(msg)) |
|
{ |
|
if (fPyFunctionInstances[kfunc_AvatarPage]) |
|
{ |
|
// yes, so was there actually a player page msg |
|
plPlayerPageMsg* ppMsg = plPlayerPageMsg::ConvertNoRef(msg); |
|
if (ppMsg) |
|
{ |
|
PyObject* pSobj = pySceneObject::New(ppMsg->fPlayer, fSelfKey); |
|
plProfile_BeginTiming(PythonUpdate); |
|
plSynchEnabler ps(true); // enable dirty state tracking during shutdown |
|
|
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_AvatarPage],fFunctionNames[kfunc_AvatarPage], |
|
"Oli",pSobj,!ppMsg->fUnload,ppMsg->fLastOut); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_AvatarPage] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(pSobj); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
} |
|
if (plAgeBeginLoadingMsg::ConvertNoRef(msg)) |
|
{ |
|
if (fPyFunctionInstances[kfunc_OnBeginAgeLoad]) |
|
{ |
|
// yes, so was there actually a player page msg |
|
plAgeBeginLoadingMsg* ppMsg = plAgeBeginLoadingMsg::ConvertNoRef(msg); |
|
if (ppMsg) |
|
{ |
|
PyObject* pSobj = pySceneObject::New(plNetClientMgr::GetInstance()->GetLocalPlayerKey(), fSelfKey); |
|
plProfile_BeginTiming(PythonUpdate); |
|
plSynchEnabler ps(true); // enable dirty state tracking during shutdown |
|
|
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnBeginAgeLoad],fFunctionNames[kfunc_OnBeginAgeLoad], |
|
"O",pSobj); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnBeginAgeLoad] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(pSobj); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
} |
|
if (plInitialAgeStateLoadedMsg::ConvertNoRef(msg))// initial server update complete message |
|
{ |
|
// make sure there is a valid python instance |
|
if ( fInstance ) |
|
{ |
|
// set the isInitialStateLoaded to that it is loaded |
|
PyObject* pInitialState = PyInt_FromLong(1); |
|
PyObject_SetAttrString(fInstance, "isInitialStateLoaded", pInitialState); |
|
Py_DECREF(pInitialState); |
|
} |
|
if (fPyFunctionInstances[kfunc_OnServerInitComplete]) |
|
{ |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnServerInitComplete],fFunctionNames[kfunc_OnServerInitComplete],nil); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnServerInitComplete] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
|
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
// are they looking for an plSDLNotificationMsg message? |
|
if (fPyFunctionInstances[kfunc_SDLNotify]) |
|
{ |
|
// yes, so was there actually a plSDLNotificationMsg? |
|
plSDLNotificationMsg* sn = plSDLNotificationMsg::ConvertNoRef(msg); |
|
if (sn) |
|
{ |
|
const char* tag = sn->fHintString.c_str(); |
|
if (tag == nil) |
|
tag = ""; |
|
// yes... then call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_SDLNotify],fFunctionNames[kfunc_SDLNotify], |
|
"ssls",sn->fVar->GetName(),sn->fSDLName.c_str(),sn->fPlayerID,tag); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_SDLNotify] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
// are they looking for an plNetOwnershipMsg message? |
|
if (fPyFunctionInstances[kfunc_OwnershipNotify]) |
|
{ |
|
// yes, so was there actually a plNetOwnershipMsg? |
|
plNetOwnershipMsg* nom = plNetOwnershipMsg::ConvertNoRef(msg); |
|
if (nom) |
|
{ |
|
// yes... then call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OwnershipNotify],fFunctionNames[kfunc_OwnershipNotify], |
|
nil); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OwnershipNotify] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
// are they looking for an pfMarkerMsg message? |
|
if (fPyFunctionInstances[kfunc_OnMarkerMsg]) |
|
{ |
|
pfMarkerMsg* markermsg = pfMarkerMsg::ConvertNoRef(msg); |
|
if (markermsg) |
|
{ |
|
// yes... then call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
// Default to an empty tuple. |
|
PyObject* ptuple = PyTuple_New(0); |
|
switch ( markermsg->fType ) |
|
{ |
|
case pfMarkerMsg::kMarkerCaptured: |
|
// Sent when we collide with a marker |
|
Py_DECREF(ptuple); |
|
ptuple = PyTuple_New(1); |
|
PyTuple_SetItem(ptuple, 0, PyLong_FromUnsignedLong((long)markermsg->fMarkerID)); |
|
break; |
|
} |
|
|
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnMarkerMsg], fFunctionNames[kfunc_OnMarkerMsg], |
|
"lO", (UInt32)markermsg->fType, ptuple); |
|
if (retVal == nil) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnMarkerMsg] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(ptuple); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// are they looking for an pfDebugTriggerMsg message? |
|
if (fPyFunctionInstances[kfunc_OnBackdoorMsg]) |
|
{ |
|
// yes, so was there actually a plNetOwnershipMsg? |
|
pfBackdoorMsg* dt = pfBackdoorMsg::ConvertNoRef(msg); |
|
if (dt) |
|
{ |
|
// yes... then call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnBackdoorMsg], |
|
fFunctionNames[kfunc_OnBackdoorMsg], |
|
"ss",dt->GetTarget(),dt->GetString()); |
|
if ( retVal == nil ) |
|
{ |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
|
|
// are they looking for a plLOSHitMsg message? |
|
if (fPyFunctionInstances[kfunc_OnLOSNotify]) |
|
{ |
|
// yes, so was there actually a plLOSHitMsg? |
|
plLOSHitMsg *pLOSMsg = plLOSHitMsg::ConvertNoRef( msg ); |
|
if (pLOSMsg) |
|
{ |
|
// yes... then call it (self,ID,noHitFlag,sceneobject,hitPoint,distance) |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* scobj; |
|
PyObject* hitpoint; |
|
if ( pLOSMsg->fObj && plSceneObject::ConvertNoRef( pLOSMsg->fObj->ObjectIsLoaded()) ) |
|
{ |
|
scobj = pySceneObject::New(pLOSMsg->fObj); |
|
hitpoint = pyPoint3::New(pLOSMsg->fHitPoint); |
|
} |
|
else |
|
{ |
|
// otherwise return a None object for the avatarKey |
|
Py_INCREF(Py_None); |
|
scobj = Py_None; |
|
Py_INCREF(Py_None); |
|
hitpoint = Py_None; |
|
} |
|
|
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnLOSNotify], |
|
fFunctionNames[kfunc_OnLOSNotify], |
|
"llOOf",pLOSMsg->fRequestID,pLOSMsg->fNoHit, |
|
scobj, hitpoint, pLOSMsg->fDistance); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnLOSNotify] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(scobj); |
|
Py_DECREF(hitpoint); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
// are they looking for a plAvatarBehaviorNotifyMsg message? |
|
if (fPyFunctionInstances[kfunc_OnBehaviorNotify]) |
|
{ |
|
// yes, so was there actually a plAvatarBehaviorNotifyMsg? |
|
plAvatarBehaviorNotifyMsg *behNotifymsg = plAvatarBehaviorNotifyMsg::ConvertNoRef(msg); |
|
if (behNotifymsg) |
|
{ |
|
// yes... then call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
// the parent of the sender should be the avatar that did the behavior |
|
PyObject* pSobj; |
|
|
|
plModifier* avmod = plModifier::ConvertNoRef(behNotifymsg->GetSender()->ObjectIsLoaded()); |
|
if ( avmod && avmod->GetNumTargets() > 0 ) |
|
{ |
|
pSobj = pySceneObject::New(avmod->GetTarget(0)->GetKey(), fSelfKey); |
|
} |
|
else |
|
{ |
|
// otherwise return a None object for the avatarKey |
|
Py_INCREF(Py_None); |
|
pSobj = Py_None; |
|
} |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnBehaviorNotify], |
|
fFunctionNames[kfunc_OnBehaviorNotify], |
|
"lOl",behNotifymsg->fType,pSobj,behNotifymsg->state); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnBehaviorNotify] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(pSobj); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
// are they looking for a pfMovieEventMsg message? |
|
if (fPyFunctionInstances[kfunc_OnMovieEvent]) |
|
{ |
|
// yes, so was there actually a pfMovieEventMsg? |
|
pfMovieEventMsg *moviemsg = pfMovieEventMsg::ConvertNoRef(msg); |
|
if (moviemsg) |
|
{ |
|
// yes... then call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnMovieEvent], |
|
fFunctionNames[kfunc_OnMovieEvent], |
|
"si",moviemsg->fMovieName,(UInt32)moviemsg->fReason); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnMovieEvent] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
// are they looking for a plCaptureRenderMsg message? |
|
if (fPyFunctionInstances[kfunc_OnScreenCaptureDone]) |
|
{ |
|
// yes, so was there actually a pfMovieEventMsg? |
|
plCaptureRenderMsg *capturemsg = plCaptureRenderMsg::ConvertNoRef(msg); |
|
if (capturemsg) |
|
{ |
|
// yes... then call it |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* pSobj; |
|
|
|
if ( capturemsg->GetMipmap() ) |
|
{ |
|
pSobj = pyImage::New(capturemsg->GetMipmap()); |
|
} |
|
else |
|
{ |
|
// otherwise return a None object for the avatarKey |
|
Py_INCREF(Py_None); |
|
pSobj = Py_None; |
|
} |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnScreenCaptureDone], |
|
fFunctionNames[kfunc_OnScreenCaptureDone], |
|
"O",pSobj); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnScreenCaptureDone] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(pSobj); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
if (fPyFunctionInstances[kfunc_OnClimbBlockerEvent]) |
|
{ |
|
plClimbEventMsg* pEvent = plClimbEventMsg::ConvertNoRef(msg); |
|
if (pEvent) |
|
{ |
|
PyObject* pSobj = pySceneObject::New(pEvent->GetSender(), fSelfKey); |
|
|
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnClimbBlockerEvent], |
|
fFunctionNames[kfunc_OnClimbBlockerEvent], |
|
"O",pSobj); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnClimbBlockerEvent] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
Py_DECREF(pSobj); |
|
return true; |
|
} |
|
} |
|
if (fPyFunctionInstances[kfunc_OnAvatarSpawn]) |
|
{ |
|
plAvatarSpawnNotifyMsg* pSpawn = plAvatarSpawnNotifyMsg::ConvertNoRef(msg); |
|
if (pSpawn) |
|
{ |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnAvatarSpawn], |
|
fFunctionNames[kfunc_OnAvatarSpawn], |
|
"l",1); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnAvatarSpawn] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
return true; |
|
} |
|
} |
|
|
|
if (fPyFunctionInstances[kfunc_OnAccountUpdate]) |
|
{ |
|
plAccountUpdateMsg* pUpdateMsg = plAccountUpdateMsg::ConvertNoRef(msg); |
|
if (pUpdateMsg) |
|
{ |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnAccountUpdate], fFunctionNames[kfunc_OnAccountUpdate], |
|
"iii", (int)pUpdateMsg->GetUpdateType(), (int)pUpdateMsg->GetResult(), (int)pUpdateMsg->GetPlayerInt() |
|
); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnAccountUpdate] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
|
|
return true; |
|
} |
|
} |
|
|
|
if (fPyFunctionInstances[kfunc_gotPublicAgeList]) |
|
{ |
|
plNetCommPublicAgeListMsg * pPubAgeMsg = plNetCommPublicAgeListMsg::ConvertNoRef(msg); |
|
if (pPubAgeMsg) |
|
{ |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* pyEL = PyList_New(pPubAgeMsg->ages.Count()); |
|
for (unsigned i = 0; i<pPubAgeMsg->ages.Count(); ++i) { |
|
plAgeInfoStruct ageInfo; |
|
ageInfo.CopyFrom(pPubAgeMsg->ages[i]); |
|
unsigned nPlayers = pPubAgeMsg->ages[i].currentPopulation; |
|
unsigned nOwners = pPubAgeMsg->ages[i].population; |
|
|
|
PyObject* t = PyTuple_New(3); |
|
PyTuple_SetItem(t, 0, pyAgeInfoStruct::New(&ageInfo)); |
|
PyTuple_SetItem(t, 1, PyLong_FromUnsignedLong(nPlayers)); |
|
PyTuple_SetItem(t, 2, PyLong_FromUnsignedLong(nOwners)); |
|
PyList_SetItem(pyEL, i, t); // steals the ref |
|
} |
|
|
|
PyObject* retVal = PyObject_CallMethod( |
|
fPyFunctionInstances[kfunc_gotPublicAgeList], |
|
fFunctionNames[kfunc_gotPublicAgeList], |
|
"O", |
|
pyEL |
|
); |
|
if ( retVal == nil ) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_gotPublicAgeList] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
|
|
return true; |
|
} |
|
} |
|
|
|
if (fPyFunctionInstances[kfunc_OnGameMgrMsg]) |
|
{ |
|
pfGameMgrMsg* gameMgrMsg = pfGameMgrMsg::ConvertNoRef(msg); |
|
if (gameMgrMsg) |
|
{ |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* pythonMsg = pyGameMgrMsg::New(gameMgrMsg); |
|
PyObject* retVal = PyObject_CallMethod( |
|
fPyFunctionInstances[kfunc_OnGameMgrMsg], |
|
fFunctionNames[kfunc_OnGameMgrMsg], |
|
"O", |
|
pythonMsg |
|
); |
|
Py_DECREF(pythonMsg); |
|
if (retVal == nil) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnGameMgrMsg] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output |
|
DisplayPythonOutput(); |
|
|
|
return true; |
|
} |
|
} |
|
|
|
if (fPyFunctionInstances[kfunc_OnGameCliMsg]) |
|
{ |
|
pfGameCliMsg* gameMgrMsg = pfGameCliMsg::ConvertNoRef(msg); |
|
if (gameMgrMsg) |
|
{ |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* pythonMsg = pyGameCliMsg::New(gameMgrMsg); |
|
PyObject* retVal = PyObject_CallMethod( |
|
fPyFunctionInstances[kfunc_OnGameCliMsg], |
|
fFunctionNames[kfunc_OnGameCliMsg], |
|
"O", |
|
pythonMsg |
|
); |
|
Py_DECREF(pythonMsg); |
|
if (retVal == nil) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnGameCliMsg] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output |
|
DisplayPythonOutput(); |
|
|
|
return true; |
|
} |
|
} |
|
|
|
if (fPyFunctionInstances[kfunc_OnAIMsg]) |
|
{ |
|
plAIMsg* aiMsg = plAIMsg::ConvertNoRef(msg); |
|
if (aiMsg) |
|
{ |
|
plProfile_BeginTiming(PythonUpdate); |
|
|
|
// grab the sender (the armature mod that has our brain) |
|
plArmatureMod* armMod = plArmatureMod::ConvertNoRef(aiMsg->GetSender()->ObjectIsLoaded()); |
|
PyObject* brainObj = NULL; |
|
if (armMod) |
|
{ |
|
plArmatureBrain* brain = armMod->FindBrainByClass(plAvBrainCritter::Index()); |
|
plAvBrainCritter* critterBrain = plAvBrainCritter::ConvertNoRef(brain); |
|
if (critterBrain) |
|
brainObj = pyCritterBrain::New(critterBrain); |
|
} |
|
if (!brainObj) |
|
{ |
|
Py_INCREF(Py_None); |
|
brainObj = Py_None; |
|
} |
|
|
|
// set up the msg type and any args, based on the message we got |
|
int msgType = plAIMsg::kAIMsg_Unknown; |
|
PyObject* args = NULL; |
|
plAIBrainCreatedMsg* brainCreatedMsg = plAIBrainCreatedMsg::ConvertNoRef(aiMsg); |
|
if (brainCreatedMsg) |
|
msgType = plAIMsg::kAIMsg_BrainCreated; |
|
|
|
plAIArrivedAtGoalMsg* arrivedMsg = plAIArrivedAtGoalMsg::ConvertNoRef(aiMsg); |
|
if (arrivedMsg) |
|
{ |
|
msgType = plAIMsg::kAIMsg_ArrivedAtGoal; |
|
args = PyTuple_New(1); |
|
PyTuple_SetItem(args, 0, pyPoint3::New(arrivedMsg->Goal())); |
|
} |
|
|
|
// if no args were set, simply set to none |
|
if (!args) |
|
{ |
|
Py_INCREF(Py_None); |
|
args = Py_None; |
|
} |
|
|
|
// call the function with the above arguments |
|
PyObject* retVal = PyObject_CallMethod( |
|
fPyFunctionInstances[kfunc_OnAIMsg], |
|
fFunctionNames[kfunc_OnAIMsg], |
|
"OisO", |
|
brainObj, msgType, aiMsg->BrainUserString().c_str(), args |
|
); |
|
Py_DECREF(brainObj); |
|
Py_DECREF(args); |
|
if (retVal == nil) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnAIMsg] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
Py_XDECREF(retVal); |
|
|
|
plProfile_EndTiming(PythonUpdate); |
|
// display any output |
|
DisplayPythonOutput(); |
|
|
|
return true; |
|
} |
|
} |
|
|
|
if (fPyFunctionInstances[kfunc_OnSubtitleMsg]) |
|
{ |
|
plSubtitleMsg* pSubMsg = plSubtitleMsg::ConvertNoRef(msg); |
|
if (pSubMsg) |
|
{ |
|
plProfile_BeginTiming(PythonUpdate); |
|
PyObject* retVal = PyObject_CallMethod( |
|
fPyFunctionInstances[kfunc_OnSubtitleMsg], fFunctionNames[kfunc_OnSubtitleMsg], |
|
"ss", pSubMsg->GetText().c_str(), pSubMsg->GetSpeaker().c_str()); |
|
if (retVal == nil) |
|
{ |
|
#ifndef PLASMA_EXTERNAL_RELEASE |
|
// for some reason this function didn't, remember that and not call it again |
|
fPyFunctionInstances[kfunc_OnSubtitleMsg] = nil; |
|
#endif //PLASMA_EXTERNAL_RELEASE |
|
// if there was an error make sure that the stderr gets flushed so it can be seen |
|
ReportError(); |
|
} |
|
|
|
Py_XDECREF(retVal); |
|
plProfile_EndTiming(PythonUpdate); |
|
|
|
// display any output (NOTE: this would be disabled in production) |
|
DisplayPythonOutput(); |
|
|
|
// we handled this message (I think) |
|
return true; |
|
} |
|
} |
|
|
|
return plModifier::MsgReceive(msg); |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : ReportError |
|
// PARAMETERS : |
|
// |
|
// PURPOSE : Report error to somewhere |
|
// |
|
void plPythonFileMod::ReportError() |
|
{ |
|
char objectName[128]; |
|
StrCopy(objectName, this->GetKeyName(), arrsize(objectName)); |
|
StrPack(objectName, " - ", arrsize(objectName)); |
|
|
|
PythonInterface::WriteToStdErr(objectName); |
|
|
|
PyErr_Print(); // make sure the error is printed |
|
PyErr_Clear(); // clear the error |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : DisplayPythonOutput |
|
// PARAMETERS : |
|
// |
|
// PURPOSE : display any Python stdout or stderr to file and to screen(later) |
|
// |
|
void plPythonFileMod::DisplayPythonOutput() |
|
{ |
|
// get the messages |
|
PythonInterface::getOutputAndReset(); |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : SetSourceFile |
|
// PARAMETERS : code - text source code |
|
// : filename - where the source code came from (just say the object name) |
|
// |
|
// PURPOSE : Sets the source code for this modifier. |
|
// : Compile it into a Python code object |
|
// : (This is usually called by the component) |
|
// |
|
void plPythonFileMod::SetSourceFile(const char* filename) |
|
{ |
|
delete [] fPythonFile; |
|
fPythonFile = hsStrcpy(filename); |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : getPythonOutput |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : get the Output to the error file to be displayed |
|
// |
|
int plPythonFileMod::getPythonOutput(std::string* line) |
|
{ |
|
return PythonInterface::getOutputAndReset(line); |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : EnableControlKeys |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : get the Output to the error file to be displayed |
|
// |
|
void plPythonFileMod::EnableControlKeyEvents() |
|
{ |
|
// register for keyboard events if needed |
|
if ( fPyFunctionInstances[kfunc_OnKeyEvent] != nil ) |
|
{ |
|
// register for key events |
|
plCmdIfaceModMsg* pModMsg = TRACKED_NEW plCmdIfaceModMsg; |
|
pModMsg->SetBCastFlag(plMessage::kBCastByExactType); |
|
pModMsg->SetSender(GetKey()); |
|
pModMsg->SetCmd(plCmdIfaceModMsg::kAdd); |
|
plgDispatch::MsgSend(pModMsg); |
|
} |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////// |
|
// |
|
// Function : DisableControlKeys |
|
// PARAMETERS : none |
|
// |
|
// PURPOSE : get the Output to the error file to be displayed |
|
// |
|
void plPythonFileMod::DisableControlKeyEvents() |
|
{ |
|
// unregister for key events |
|
plCmdIfaceModMsg* pModMsg = TRACKED_NEW plCmdIfaceModMsg; |
|
pModMsg->SetBCastFlag(plMessage::kBCastByExactType); |
|
pModMsg->SetSender(GetKey()); |
|
pModMsg->SetCmd(plCmdIfaceModMsg::kRemove); |
|
plgDispatch::MsgSend(pModMsg); |
|
} |
|
|
|
void plPythonFileMod::Read(hsStream* stream, hsResMgr* mgr) |
|
{ |
|
plMultiModifier::Read(stream, mgr); |
|
|
|
// read in the compile python code (pyc) |
|
if ( fPythonFile ) |
|
{ |
|
// if we already have some code, get rid of it! |
|
delete [] fPythonFile; |
|
fPythonFile = nil; |
|
} |
|
fPythonFile = stream->ReadSafeString(); |
|
|
|
// then read in the list of receivers that want to be notified |
|
int nRcvs = stream->ReadSwap32(); |
|
fReceivers.Reset(); |
|
int m; |
|
for( m=0; m<nRcvs; m++ ) |
|
{ |
|
fReceivers.Append(mgr->ReadKey(stream)); |
|
} |
|
|
|
// then read in the list of parameters |
|
int nParms = stream->ReadSwap32(); |
|
fParameters.SetCountAndZero(nParms); |
|
int i; |
|
for( i=0; i<nParms; i++ ) |
|
{ |
|
plPythonParameter parm; |
|
parm.Read(stream,mgr); |
|
fParameters[i] = parm; |
|
} |
|
} |
|
|
|
void plPythonFileMod::Write(hsStream* stream, hsResMgr* mgr) |
|
{ |
|
plMultiModifier::Write(stream, mgr); |
|
|
|
stream->WriteSafeString(fPythonFile); |
|
|
|
// then write out the list of receivers that want to be notified |
|
stream->WriteSwap32(fReceivers.GetCount()); |
|
int m; |
|
for( m=0; m<fReceivers.GetCount(); m++ ) |
|
mgr->WriteKey(stream, fReceivers[m]); |
|
|
|
// then write out the list of parameters |
|
stream->WriteSwap32(fParameters.GetCount()); |
|
int i; |
|
for( i=0; i<fParameters.GetCount(); i++ ) |
|
fParameters[i].Write(stream,mgr); |
|
} |
|
|
|
//// kGlobalNameKonstant ///////////////////////////////////////////////// |
|
// My continued attempt to spread the CORRECT way to spell konstant. -mcn |
|
|
|
char plPythonFileMod::kGlobalNameKonstant[] = "VeryVerySpecialPythonFileMod";
|
|
|