/*==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 . 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 "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 #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 { 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 ; iob_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; nparamIsLoadingAge()) { 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()); } // 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 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 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 ; iObjectIsLoaded()); 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; jGetEventRecord(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::kNumber: PyList_SetItem(event, 3, PyFloat_FromDouble(eventData->fNumber)); break; case proEventData::kKey: PyList_SetItem(event, 3, pyKey::New(eventData->fKey)); 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; npmGetSender()->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; npmGetSender()->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; iages.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; } } 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; mReadKey(stream)); } // then read in the list of parameters int nParms = stream->ReadSwap32(); fParameters.SetCountAndZero(nParms); int i; for( i=0; iWriteSafeString(fPythonFile); // then write out the list of receivers that want to be notified stream->WriteSwap32(fReceivers.GetCount()); int m; for( m=0; mWriteKey(stream, fReceivers[m]); // then write out the list of parameters stream->WriteSwap32(fParameters.GetCount()); int i; for( i=0; i