/*==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 .
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
#include
#include "HeadSpin.h"
#include "plgDispatch.h"
#include "pyGeometry3.h"
#include "pyKey.h"
#include "hsResMgr.h"
#include "hsStream.h"
#pragma hdrstop
#include "plPythonFileMod.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 "pfMessage/pfGameScoreMsg.h"
#include "plProfile.h"
#include "cyPythonInterface.h"
#include "cyDraw.h"
#include "cyPhysics.h"
#include "pySceneObject.h"
#include "cyMisc.h"
#include "cyCamera.h"
#include "pyNotify.h"
#include "cyAvatar.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 "pyGameScoreMsg.h"
#include "plPythonSDLModifier.h"
#include "plMessage/plTimerCallbackMsg.h"
plProfile_CreateTimer("Update", "Python", PythonUpdate);
/////////////////////////////////////////////////////////////////////////////
//
// fFunctionNames - the actual names of the functions for On[event] types
//
const 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
"OnGameScoreMsg", // kfunc_OnGameScoreMsg
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],
(char*)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],
(char*)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],
(char*)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 );
}
};
bool plPythonFileMod::fAtConvertTime = false;
/////////////////////////////////////////////////////////////////////////////
//
// Function : plPythonFileMod and ~plPythonFileMod
// PARAMETERS : none
//
// PURPOSE : Constructor and destructor
//
plPythonFileMod::plPythonFileMod()
{
fPythonFile = 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.IsNull() && fModule )
{
//_PyModule_Clear(fModule);
PyObject *m;
PyObject *modules = PyImport_GetModuleDict();
if( modules && (m = PyDict_GetItemString(modules, fModuleName.c_str())) && PyModule_Check(m))
{
hsStatusMessageF("Module %s removed from python dictionary",fModuleName.c_str());
PyDict_DelItemString(modules, fModuleName.c_str());
}
else
{
hsStatusMessageF("Module %s not found in python dictionary. Already removed?",fModuleName.c_str());
}
// 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;
}
fModuleName = plString::Null;
}
#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
plFileName pyfile = plFileName::Join(".", "python", plString::Format("%s.py", fPythonFile));
if (plFileInfo(pyfile).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
fModuleName = IMakeModuleName(sobj);
fModule = PythonInterface::CreateModule(fModuleName.c_str());
// 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 = 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 = parameter.fString;
fNamedCompQueue.Append(comp);
}
else
{
if (isNamedAttr == 1)
IFindActivatorAndAdd(parameter.fString, parameter.fID);
else
IFindResponderAndAdd(parameter.fString, parameter.fID);
}
}
}
// if it wasn't a named string then must be normal string type
if ( isNamedAttr == 0 )
if ( !parameter.fString.IsNull() )
value = PyString_FromString(parameter.fString.c_str());
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,(char**)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 = 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 = 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],
(char*)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();
}
// Oversight fix... Sometimes PythonFileMods are loaded after the AgeInitialState is received.
// We should really let the script know about that via OnServerInitComplete anyway because it's
// not good to make assumptions about game state in workarounds for that method not being called
plNetClientApp* na = plNetClientApp::GetInstance();
if (!na->GetFlagsBit(plNetClientApp::kLoadingInitialAgeState) && na->GetFlagsBit(plNetClientApp::kPlayingGame))
{
plgDispatch::Dispatch()->UnRegisterForExactType(plInitialAgeStateLoadedMsg::Index(), GetKey());
if (fPyFunctionInstances[kfunc_OnServerInitComplete])
{
plProfile_BeginTiming(PythonUpdate);
// call it
PyObject* retVal = PyObject_CallMethod(fPyFunctionInstances[kfunc_OnServerInitComplete],
(char*)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();
}
}
// 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 )
{
if (!fPyFunctionInstances[kfunc_OnDefaultKeyCaught])
return;
plProfile_BeginTiming( PythonUpdate );
PyObject* retVal = PyObject_CallMethod(
fPyFunctionInstances[ kfunc_OnDefaultKeyCaught ],
(char*)fFunctionNames[ kfunc_OnDefaultKeyCaught ],
"ciiiii",
msg->GetKeyChar(),
(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
//
plString plPythonFileMod::IMakeModuleName(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().c_str();
const char* pSobjName = sKey->GetName().c_str();
uint16_t len = pKey->GetName().GetSize();
uint16_t slen = sKey->GetName().GetSize();
hsAssert(len+slen < 256, "Warning: String length exceeds 256 characters.");
char modulename[256];
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';
plString name = plString::FromUtf8(modulename);
// 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_t cloneID = pKeyImp->GetUoid().GetCloneID();
name += plString::Format("%d", 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_t seqID = pKeyImp->GetUoid().GetLocation().GetSequenceNumber();
name += plString::Format("%d", seqID);
}
return name;
}
/////////////////////////////////////////////////////////////////////////////
//
// 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_t 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 plString &responderName, int32_t id)
{
if ( !responderName.IsNull() )
{
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],
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)
//
bool plPythonFileMod::IEval(double secs, float del, uint32_t 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],
(char*)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],
(char*)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
//
bool 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);
}
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::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_t 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::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_t 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],
(char*)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],
(char*)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],
(char*)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_t 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_t 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],
(char*)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
const char* roomname = "";
if ( pRLNMsg->GetRoom() != nil )
roomname = pRLNMsg->GetRoom()->GetName().c_str();
plProfile_BeginTiming(PythonUpdate);
PyObject* retVal = PyObject_CallMethod(
fPyFunctionInstances[kfunc_PageLoad],
(char*)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],
(char*)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;
plStringBuffer 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->GetString().ToWchar();
PyTuple_SetItem(value, 0, PyUnicode_FromWideChar(str, str.GetSize()));
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->GetString().ToWchar();
PyTuple_SetItem(value,0,PyString_FromString(pkimsg->GetUser()));
PyTuple_SetItem(value,1,PyUnicode_FromWideChar(str, str.GetSize()));
PyTuple_SetItem(value,2,PyLong_FromLong(pkimsg->GetIntValue()));
break;
case pfKIMsg::kRegisterImager:
value = PyTuple_New(2);
str = pkimsg->GetString().ToWchar();
PyTuple_SetItem(value, 0, PyUnicode_FromWideChar(str, str.GetSize()));
PyTuple_SetItem(value, 1, pyKey::New(pkimsg->GetSender()));
break;
case pfKIMsg::kAddPlayerDevice:
case pfKIMsg::kRemovePlayerDevice:
{
str = pkimsg->GetString().ToWchar();
if ( str.GetSize() > 0 )
value = PyUnicode_FromWideChar(str, str.GetSize());
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->GetString().ToWchar();
value = PyUnicode_FromWideChar(str, str.GetSize());
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],
(char*)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],
(char*)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().c_str(), 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],
(char*)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],
(char*)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],
(char*)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);
plStringBuffer wMessage = pkimsg->GetString().ToWchar();
PyObject* uMessage = PyUnicode_FromWideChar(wMessage, wMessage.GetSize());
PyObject* retVal = PyObject_CallMethod(
fPyFunctionInstances[kfunc_RTChat],
(char*)fFunctionNames[kfunc_RTChat],
"OOl", player, uMessage, pkimsg->GetFlags());
Py_DECREF(uMessage);
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],
(char*)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],
(char*)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],
(char*)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)
{
plString tag = sn->fHintString;
// yes... then call it
plProfile_BeginTiming(PythonUpdate);
PyObject* retVal = PyObject_CallMethod(
fPyFunctionInstances[kfunc_SDLNotify],
(char*)fFunctionNames[kfunc_SDLNotify],
"ssls", sn->fVar->GetName().c_str(), sn->fSDLName.c_str(),
sn->fPlayerID, tag.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_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],
(char*)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],
(char*)fFunctionNames[kfunc_OnMarkerMsg],
"lO", (uint32_t)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],
(char*)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],
(char*)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],
(char*)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],
(char*)fFunctionNames[kfunc_OnMovieEvent],
"si", moviemsg->fMovieName.AsString().c_str(), (uint32_t)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],
(char*)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],
(char*)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],
(char*)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],
(char*)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],
(char*)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],
(char*)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],
(char*)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],
(char*)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_OnGameScoreMsg])
{
pfGameScoreMsg* pScoreMsg = pfGameScoreMsg::ConvertNoRef(msg);
if (pScoreMsg)
{
plProfile_BeginTiming(PythonUpdate);
// Creates the final ptGameScoreMsg and ships it off to OnGameScoreMsg
PyObject* pyMsg = pyGameScoreMsg::CreateFinal(pScoreMsg);
PyObject* retVal = PyObject_CallMethod(
fPyFunctionInstances[kfunc_OnGameScoreMsg],
(char*)fFunctionNames[kfunc_OnGameScoreMsg],
"O", pyMsg
);
Py_DECREF(pyMsg);
if (retVal == nil)
{
#ifndef PLASMA_EXTERNAL_RELEASE
// for some reason this function didn't, remember that and not call it again
fPyFunctionInstances[kfunc_OnGameScoreMsg] = nil;
#endif //PLASMA_EXTERNAL_RELEASE
// if there was an error make sure that the stderr gets flushed so it can be seen
ReportError();
}
plProfile_EndTiming(PythonUpdate);
return true;
}
}
return plModifier::MsgReceive(msg);
}
/////////////////////////////////////////////////////////////////////////////
//
// Function : ReportError
// PARAMETERS :
//
// PURPOSE : Report error to somewhere
//
void plPythonFileMod::ReportError()
{
plString objectName = this->GetKeyName();
objectName += " - ";
PythonInterface::WriteToStdErr(objectName.c_str());
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 = 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 = 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->ReadLE32();
fReceivers.Reset();
int m;
for( m=0; mReadKey(stream));
}
// then read in the list of parameters
int nParms = stream->ReadLE32();
fParameters.SetCountAndZero(nParms);
int i;
for( i=0; iWriteSafeString(fPythonFile);
// then write out the list of receivers that want to be notified
stream->WriteLE32(fReceivers.GetCount());
int m;
for( m=0; mWriteKey(stream, fReceivers[m]);
// then write out the list of parameters
stream->WriteLE32(fParameters.GetCount());
int i;
for( i=0; i