|
|
|
/*==LICENSE==*
|
|
|
|
|
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools
|
|
|
|
Copyright (C) 2011 Cyan Worlds, Inc.
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
Additional permissions under GNU GPL version 3 section 7
|
|
|
|
|
|
|
|
If you modify this Program, or any covered work, by linking or
|
|
|
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
|
|
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
|
|
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
|
|
|
(or a modified version of those libraries),
|
|
|
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
|
|
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
|
|
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
|
|
|
licensors of this Program grant you additional
|
|
|
|
permission to convey the resulting work. Corresponding Source for a
|
|
|
|
non-source form of such a combination shall include the source code for
|
|
|
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
|
|
|
work.
|
|
|
|
|
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com
|
|
|
|
or by snail mail at:
|
|
|
|
Cyan Worlds, Inc.
|
|
|
|
14617 N Newport Hwy
|
|
|
|
Mead, WA 99021
|
|
|
|
|
|
|
|
*==LICENSE==*/
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// plPythonFileMod - the 'special' Python File modifier.
|
|
|
|
//
|
|
|
|
// This modifier will handle the interface to python code that has been file-ized.
|
|
|
|
//
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#include <Python.h>
|
|
|
|
#include <locale>
|
|
|
|
#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 ; i<kfunc_lastone; i++)
|
|
|
|
fPyFunctionInstances[i] = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
plPythonFileMod::~plPythonFileMod()
|
|
|
|
{
|
|
|
|
if ( !fAtConvertTime ) // if this is just an Add that's during a convert, then don't do anymore
|
|
|
|
{
|
|
|
|
// remove our reference to the instance (but only if we made one)
|
|
|
|
if(fInstance)
|
|
|
|
{
|
|
|
|
if ( fInstance->ob_refcnt > 1)
|
|
|
|
Py_DECREF(fInstance);
|
|
|
|
// then have the glue delete the instance of class
|
|
|
|
PyObject* delInst = PythonInterface::GetModuleItem("glue_delInst",fModule);
|
|
|
|
if ( delInst!=nil && PyCallable_Check(delInst) )
|
|
|
|
{
|
|
|
|
PyObject* retVal = PyObject_CallFunction(delInst,nil);
|
|
|
|
if ( retVal == nil )
|
|
|
|
{
|
|
|
|
// if there was an error make sure that the stderr gets flushed so it can be seen
|
|
|
|
ReportError();
|
|
|
|
}
|
|
|
|
Py_XDECREF(retVal);
|
|
|
|
// display any output
|
|
|
|
DisplayPythonOutput();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fInstance = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we have a key catcher, get rid of it
|
|
|
|
delete fKeyCatcher;
|
|
|
|
fKeyCatcher = nil;
|
|
|
|
|
|
|
|
// if we created a Vault callback, undo it and get rid of it
|
|
|
|
if (fVaultCallback)
|
|
|
|
{
|
|
|
|
// Set the callback for the vault thingy
|
|
|
|
VaultUnregisterCallback(fVaultCallback);
|
|
|
|
delete fVaultCallback;
|
|
|
|
fVaultCallback = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fSelfKey)
|
|
|
|
{
|
|
|
|
Py_DECREF(fSelfKey);
|
|
|
|
fSelfKey = nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
// get rid of the python code
|
|
|
|
if ( fPythonFile )
|
|
|
|
{
|
|
|
|
delete [] fPythonFile;
|
|
|
|
fPythonFile = nil;
|
|
|
|
}
|
|
|
|
// then get rid of this module
|
|
|
|
// NOTE: fModule shouldn't be made in the plugin, only at runtime
|
|
|
|
if ( !fModuleName.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
|
|
|
|
char pathandfile[256];
|
|
|
|
sprintf(pathandfile, ".\\python\\%s.py",fPythonFile);
|
|
|
|
wchar_t *wPathandfile = hsStringToWString(pathandfile);
|
|
|
|
bool 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
|
|
|
|
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; nparam<GetParameterListCount() ; nparam++ )
|
|
|
|
{
|
|
|
|
plPythonParameter parameter = GetParameterItem(nparam);
|
|
|
|
// create the python object that matches the type
|
|
|
|
// (NOTE: this relies on function created above to help create Plasma python objects)
|
|
|
|
PyObject* value = nil; // assume that there is no conversion available
|
|
|
|
int isNamedAttr = 0;
|
|
|
|
PyObject* retvalue;
|
|
|
|
switch (parameter.fValueType)
|
|
|
|
{
|
|
|
|
case plPythonParameter::kInt:
|
|
|
|
value = PyInt_FromLong(parameter.datarecord.fIntNumber);
|
|
|
|
break;
|
|
|
|
case plPythonParameter::kFloat:
|
|
|
|
value = PyFloat_FromDouble(parameter.datarecord.fFloatNumber);
|
|
|
|
break;
|
|
|
|
case plPythonParameter::kbool:
|
|
|
|
value = PyInt_FromLong(parameter.datarecord.fBool);
|
|
|
|
break;
|
|
|
|
case plPythonParameter::kString:
|
|
|
|
case plPythonParameter::kAnimationName:
|
|
|
|
isNamedAttr = 0;
|
|
|
|
if ( check_isNamed!=nil && PyCallable_Check(check_isNamed) )
|
|
|
|
{
|
|
|
|
retvalue = PyObject_CallFunction(check_isNamed,"l", parameter.fID);
|
|
|
|
if ( retvalue == nil )
|
|
|
|
{
|
|
|
|
ReportError();
|
|
|
|
DisplayPythonOutput();
|
|
|
|
}
|
|
|
|
if ( retvalue && PyInt_Check(retvalue) )
|
|
|
|
isNamedAttr = PyInt_AsLong(retvalue);
|
|
|
|
Py_XDECREF(retvalue);
|
|
|
|
// is it a NamedActivator
|
|
|
|
if ( isNamedAttr == 1 || isNamedAttr == 2)
|
|
|
|
{
|
|
|
|
if (plAgeLoader::GetInstance()->IsLoadingAge())
|
|
|
|
{
|
|
|
|
NamedComponent comp;
|
|
|
|
comp.isActivator = (isNamedAttr == 1);
|
|
|
|
comp.id = parameter.fID;
|
|
|
|
comp.name = 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<plKey> keylist;
|
|
|
|
const plLocation &loc = GetKey()->GetUoid().GetLocation();
|
|
|
|
plKeyFinder::Instance().ReallyStupidResponderSearch(responderName,keylist,loc); // use the really stupid search to find the responder
|
|
|
|
// the keylist will be filled with all the keys that correspond to that responder
|
|
|
|
int list_size = keylist.size();
|
|
|
|
int i;
|
|
|
|
for ( i=0 ; i<list_size; i++ )
|
|
|
|
{
|
|
|
|
plPythonParameter parm(id);
|
|
|
|
parm.SetToResponder(keylist[i]);
|
|
|
|
AddParameter(parm);
|
|
|
|
ISetKeyValue(keylist[i], id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Function : IFindActivatorAndAdd
|
|
|
|
// PARAMETERS : ResponderName - name of the responder to find
|
|
|
|
//
|
|
|
|
// PURPOSE : find a responder by name in all age and page locations
|
|
|
|
// : and add to the Parameter list
|
|
|
|
//
|
|
|
|
void plPythonFileMod::IFindActivatorAndAdd(const plString &activatorName, int32_t id)
|
|
|
|
{
|
|
|
|
if ( !activatorName.IsNull() )
|
|
|
|
{
|
|
|
|
std::vector<plKey> keylist;
|
|
|
|
const plLocation &loc = GetKey()->GetUoid().GetLocation();
|
|
|
|
plKeyFinder::Instance().ReallyStupidActivatorSearch(activatorName,keylist, loc); // use the really stupid search to find the responder
|
|
|
|
// the keylist will be filled with all the keys that correspond to that responder
|
|
|
|
int list_size = keylist.size();
|
|
|
|
// create the Python object that is the list, starts as empty
|
|
|
|
int i;
|
|
|
|
for ( i=0 ; i<list_size; i++ )
|
|
|
|
{
|
|
|
|
plPythonParameter parm(id);
|
|
|
|
parm.SetToActivator(keylist[i]);
|
|
|
|
AddParameter(parm);
|
|
|
|
ISetKeyValue(keylist[i], id);
|
|
|
|
|
|
|
|
// need to add ourselves as a receiver to their list
|
|
|
|
// first see if it is an logicMod, then add to their receiver list
|
|
|
|
plLogicModifier *logic = plLogicModifier::ConvertNoRef(keylist[i]->ObjectIsLoaded());
|
|
|
|
if (logic)
|
|
|
|
{
|
|
|
|
logic->AddNotifyReceiver(this->GetKey());
|
|
|
|
}
|
|
|
|
else // else might be a python file key
|
|
|
|
{
|
|
|
|
// next check to see if it is another PythonFileMod, and add to their notify list
|
|
|
|
plPythonFileMod *pymod = plPythonFileMod::ConvertNoRef(keylist[i]->ObjectIsLoaded());
|
|
|
|
if (pymod)
|
|
|
|
{
|
|
|
|
pymod->AddToNotifyList(this->GetKey());
|
|
|
|
}
|
|
|
|
else // else maybe its just not loaded yet
|
|
|
|
{
|
|
|
|
// setup a ref notify when it does get loaded
|
|
|
|
hsgResMgr::ResMgr()->AddViaNotify(keylist[i],
|
|
|
|
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; j<num_records; j++ )
|
|
|
|
{
|
|
|
|
// get an event record
|
|
|
|
proEventData* pED = pNtfyMsg->GetEventRecord(j);
|
|
|
|
switch ( pED->fEventType )
|
|
|
|
{
|
|
|
|
|
|
|
|
case proEventData::kCollision:
|
|
|
|
{
|
|
|
|
proCollisionEventData *eventData = (proCollisionEventData *)pED;
|
|
|
|
// get data from the collision
|
|
|
|
// create list
|
|
|
|
PyObject* event = PyList_New(4);
|
|
|
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kCollision));
|
|
|
|
PyList_SetItem(event, 1, PyInt_FromLong(eventData->fEnter ? 1 : 0));
|
|
|
|
PyList_SetItem(event, 2, pySceneObject::New(eventData->fHitter, fSelfKey));
|
|
|
|
PyList_SetItem(event, 3, pySceneObject::New(eventData->fHittee, fSelfKey));
|
|
|
|
// add this event record to the main event list (lists within a list)
|
|
|
|
PyList_Append(levents, event);
|
|
|
|
Py_DECREF(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case proEventData::kSpawned:
|
|
|
|
{
|
|
|
|
proSpawnedEventData *eventData = (proSpawnedEventData *)pED;
|
|
|
|
PyObject* event = PyList_New(3);
|
|
|
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kSpawned));
|
|
|
|
PyList_SetItem(event, 1, pySceneObject::New(eventData->fSpawner, fSelfKey));
|
|
|
|
PyList_SetItem(event, 2, pySceneObject::New(eventData->fSpawnee, fSelfKey));
|
|
|
|
PyList_Append(levents, event);
|
|
|
|
Py_DECREF(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case proEventData::kPicked:
|
|
|
|
{
|
|
|
|
// get data from the picked event
|
|
|
|
proPickedEventData *eventData = (proPickedEventData *)pED;
|
|
|
|
// create list
|
|
|
|
PyObject* event = PyList_New(6);
|
|
|
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kPicked));
|
|
|
|
PyList_SetItem(event, 1, PyInt_FromLong(eventData->fEnabled ? 1 : 0));
|
|
|
|
PyList_SetItem(event, 2, pySceneObject::New(eventData->fPicker, fSelfKey));
|
|
|
|
PyList_SetItem(event, 3, pySceneObject::New(eventData->fPicked, fSelfKey));
|
|
|
|
PyList_SetItem(event, 4, pyPoint3::New(eventData->fHitPoint));
|
|
|
|
|
|
|
|
// make it in the local space
|
|
|
|
hsPoint3 tolocal(0,0,0);
|
|
|
|
if(eventData->fPicked)
|
|
|
|
{
|
|
|
|
plSceneObject* obj = plSceneObject::ConvertNoRef(eventData->fPicked->ObjectIsLoaded());
|
|
|
|
if ( obj )
|
|
|
|
{
|
|
|
|
const plCoordinateInterface* ci = obj->GetCoordinateInterface();
|
|
|
|
if ( ci )
|
|
|
|
tolocal = (hsMatrix44)ci->GetWorldToLocal() * eventData->fHitPoint;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PyList_SetItem(event, 5, pyPoint3::New(tolocal));
|
|
|
|
|
|
|
|
// add this event record to the main event list (lists within a list)
|
|
|
|
PyList_Append(levents, event);
|
|
|
|
Py_DECREF(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case proEventData::kControlKey:
|
|
|
|
{
|
|
|
|
proControlKeyEventData *eventData = (proControlKeyEventData *)pED;
|
|
|
|
// create event list
|
|
|
|
PyObject* event = PyList_New(3);
|
|
|
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kControlKey));
|
|
|
|
PyList_SetItem(event, 1, PyLong_FromLong(eventData->fControlKey));
|
|
|
|
PyList_SetItem(event, 2, PyInt_FromLong(eventData->fDown ? 1 : 0));
|
|
|
|
// add this event record to the main event list (lists within a list)
|
|
|
|
PyList_Append(levents, event);
|
|
|
|
Py_DECREF(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case proEventData::kVariable:
|
|
|
|
{
|
|
|
|
proVariableEventData *eventData = (proVariableEventData *)pED;
|
|
|
|
// create event list
|
|
|
|
PyObject* event = PyList_New(4);
|
|
|
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kVariable));
|
|
|
|
PyList_SetItem(event, 1, PyString_FromString(eventData->fName));
|
|
|
|
PyList_SetItem(event, 2, PyLong_FromLong(eventData->fDataType));
|
|
|
|
|
|
|
|
// depending on the data type create the data
|
|
|
|
switch ( eventData->fDataType )
|
|
|
|
{
|
|
|
|
case proEventData::kFloat:
|
|
|
|
PyList_SetItem(event, 3, PyFloat_FromDouble(eventData->fNumber.f));
|
|
|
|
break;
|
|
|
|
case proEventData::kKey:
|
|
|
|
PyList_SetItem(event, 3, pyKey::New(eventData->fKey));
|
|
|
|
break;
|
|
|
|
case proEventData::kInt:
|
|
|
|
PyList_SetItem(event, 3, PyInt_FromLong(eventData->fNumber.i));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Py_XINCREF(Py_None);
|
|
|
|
PyList_SetItem(event, 3, Py_None);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// add this event record to the main event list (lists within a list)
|
|
|
|
PyList_Append(levents, event);
|
|
|
|
Py_DECREF(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case proEventData::kFacing:
|
|
|
|
{
|
|
|
|
proFacingEventData *eventData = (proFacingEventData *)pED;
|
|
|
|
// create event list
|
|
|
|
PyObject* event = PyList_New(5);
|
|
|
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kFacing));
|
|
|
|
PyList_SetItem(event, 1, PyInt_FromLong(eventData->enabled ? 1 : 0));
|
|
|
|
PyList_SetItem(event, 2, pySceneObject::New(eventData->fFacer, fSelfKey));
|
|
|
|
PyList_SetItem(event, 3, pySceneObject::New(eventData->fFacee, fSelfKey));
|
|
|
|
PyList_SetItem(event, 4, PyFloat_FromDouble(eventData->dot));
|
|
|
|
// add this event record to the main event list (lists within a list)
|
|
|
|
PyList_Append(levents, event);
|
|
|
|
Py_DECREF(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case proEventData::kContained:
|
|
|
|
{
|
|
|
|
proContainedEventData *eventData = (proContainedEventData *)pED;
|
|
|
|
// create event list
|
|
|
|
PyObject* event = PyList_New(4);
|
|
|
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kContained));
|
|
|
|
PyList_SetItem(event, 1, PyInt_FromLong(eventData->fEntering ? 1 : 0));
|
|
|
|
PyList_SetItem(event, 2, pySceneObject::New(eventData->fContained, fSelfKey));
|
|
|
|
PyList_SetItem(event, 3, pySceneObject::New(eventData->fContainer, fSelfKey));
|
|
|
|
// add this event record to the main event list (lists within a list)
|
|
|
|
PyList_Append(levents, event);
|
|
|
|
Py_DECREF(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case proEventData::kActivate:
|
|
|
|
{
|
|
|
|
proActivateEventData *eventData = (proActivateEventData *)pED;
|
|
|
|
// create event list
|
|
|
|
PyObject* event = PyList_New(3);
|
|
|
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kActivate));
|
|
|
|
PyList_SetItem(event, 1, PyInt_FromLong(eventData->fActive ? 1 : 0));
|
|
|
|
PyList_SetItem(event, 2, PyInt_FromLong(eventData->fActivate ? 1 : 0));
|
|
|
|
// add this event record to the main event list (lists within a list)
|
|
|
|
PyList_Append(levents, event);
|
|
|
|
Py_DECREF(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case proEventData::kCallback:
|
|
|
|
{
|
|
|
|
proCallbackEventData *eventData = (proCallbackEventData *)pED;
|
|
|
|
// create event list
|
|
|
|
PyObject* event = PyList_New(2);
|
|
|
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kCallback));
|
|
|
|
PyList_SetItem(event, 1, PyLong_FromLong(eventData->fEventType));
|
|
|
|
// add this event record to the main event list (lists within a list)
|
|
|
|
PyList_Append(levents, event);
|
|
|
|
Py_DECREF(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case proEventData::kResponderState:
|
|
|
|
{
|
|
|
|
proResponderStateEventData *eventData = (proResponderStateEventData *)pED;
|
|
|
|
// create event list
|
|
|
|
PyObject* event = PyList_New(2);
|
|
|
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kResponderState));
|
|
|
|
PyList_SetItem(event, 1, PyLong_FromLong(eventData->fState));
|
|
|
|
// add this event record to the main event list (lists within a list)
|
|
|
|
PyList_Append(levents, event);
|
|
|
|
Py_DECREF(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case proEventData::kMultiStage:
|
|
|
|
{
|
|
|
|
proMultiStageEventData *eventData = (proMultiStageEventData *)pED;
|
|
|
|
// create event list
|
|
|
|
PyObject* event = PyList_New(4);
|
|
|
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kMultiStage));
|
|
|
|
PyList_SetItem(event, 1, PyLong_FromLong(eventData->fStage));
|
|
|
|
PyList_SetItem(event, 2, PyLong_FromLong(eventData->fEvent));
|
|
|
|
PyList_SetItem(event, 3, pySceneObject::New(eventData->fAvatar, fSelfKey));
|
|
|
|
// add this event record to the main event list (lists within a list)
|
|
|
|
PyList_Append(levents, event);
|
|
|
|
Py_DECREF(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case proEventData::kOfferLinkingBook:
|
|
|
|
{
|
|
|
|
proOfferLinkingBookEventData* eventData = (proOfferLinkingBookEventData*)pED;
|
|
|
|
// create event list
|
|
|
|
PyObject* event = PyList_New(4);
|
|
|
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kOfferLinkingBook));
|
|
|
|
PyList_SetItem(event, 1, pySceneObject::New(eventData->offerer, fSelfKey));
|
|
|
|
PyList_SetItem(event, 2, PyInt_FromLong(eventData->targetAge));
|
|
|
|
PyList_SetItem(event, 3, PyInt_FromLong(eventData->offeree));
|
|
|
|
PyList_Append(levents, event);
|
|
|
|
Py_DECREF(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case proEventData::kBook:
|
|
|
|
{
|
|
|
|
proBookEventData* eventData = (proBookEventData*)pED;
|
|
|
|
// create event list
|
|
|
|
PyObject* event = PyList_New(3);
|
|
|
|
PyList_SetItem(event, 0, PyLong_FromLong((long)proEventData::kBook));
|
|
|
|
PyList_SetItem(event, 1, PyLong_FromUnsignedLong(eventData->fEvent));
|
|
|
|
PyList_SetItem(event, 2, PyLong_FromUnsignedLong(eventData->fLinkID));
|
|
|
|
PyList_Append(levents, event);
|
|
|
|
Py_DECREF(event);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Need to determine which of the Activators sent this plNotifyMsg
|
|
|
|
// and set the ID appropriately
|
|
|
|
int32_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; npm<GetParameterListCount() ; npm++ )
|
|
|
|
{
|
|
|
|
plPythonParameter parameter = GetParameterItem(npm);
|
|
|
|
// is it something that could produce a plNotifiyMsg?
|
|
|
|
if ( parameter.fValueType == plPythonParameter::kActivatorList
|
|
|
|
|| parameter.fValueType == plPythonParameter::kBehavior
|
|
|
|
|| parameter.fValueType == plPythonParameter::kResponderList )
|
|
|
|
{
|
|
|
|
// is there an actual ObjectKey to look at?
|
|
|
|
if (parameter.fObjectKey != nil )
|
|
|
|
{
|
|
|
|
// is it the same as the sender of the notify message?
|
|
|
|
if ( pNtfyMsg->GetSender()->GetUoid() == parameter.fObjectKey->GetUoid() )
|
|
|
|
{
|
|
|
|
// match! Then return that as the ID
|
|
|
|
id = parameter.fID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// call it
|
|
|
|
plProfile_BeginTiming(PythonUpdate);
|
|
|
|
PyObject* retVal = PyObject_CallMethod(
|
|
|
|
fPyFunctionInstances[kfunc_Notify],
|
|
|
|
(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; npm<GetParameterListCount() ; npm++ )
|
|
|
|
{
|
|
|
|
plPythonParameter parameter = GetParameterItem(npm);
|
|
|
|
// is it something that could produce a plNotifiyMsg?
|
|
|
|
if ( parameter.fValueType == plPythonParameter::kGUIDialog || parameter.fValueType == plPythonParameter::kGUIPopUpMenu )
|
|
|
|
{
|
|
|
|
// is there an actual ObjectKey to look at?
|
|
|
|
if (parameter.fObjectKey != nil )
|
|
|
|
{
|
|
|
|
// is it the same of the sender of the notify message?
|
|
|
|
if ( pGUIMsg->GetSender()->GetUoid() == parameter.fObjectKey->GetUoid() )
|
|
|
|
{
|
|
|
|
// match! then set the ID to what the parameter is, so the python programmer can find it
|
|
|
|
id = parameter.fID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure that we found a control to go with this
|
|
|
|
if ( pyControl == nil )
|
|
|
|
{
|
|
|
|
// if none then return a Python None object
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
pyControl = Py_None;
|
|
|
|
}
|
|
|
|
|
|
|
|
// call their OnGUINotify method
|
|
|
|
plProfile_BeginTiming(PythonUpdate);
|
|
|
|
PyObject* retVal = PyObject_CallMethod(
|
|
|
|
fPyFunctionInstances[kfunc_GUINotify],
|
|
|
|
(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<wchar_t> 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);
|
|
|
|
PyObject* retVal = PyObject_CallMethod(
|
|
|
|
fPyFunctionInstances[kfunc_RTChat],
|
|
|
|
(char*)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],
|
|
|
|
(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, (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; i<pPubAgeMsg->ages.Count(); ++i) {
|
|
|
|
plAgeInfoStruct ageInfo;
|
|
|
|
ageInfo.CopyFrom(pPubAgeMsg->ages[i]);
|
|
|
|
unsigned nPlayers = pPubAgeMsg->ages[i].currentPopulation;
|
|
|
|
unsigned nOwners = pPubAgeMsg->ages[i].population;
|
|
|
|
|
|
|
|
PyObject* t = PyTuple_New(3);
|
|
|
|
PyTuple_SetItem(t, 0, pyAgeInfoStruct::New(&ageInfo));
|
|
|
|
PyTuple_SetItem(t, 1, PyLong_FromUnsignedLong(nPlayers));
|
|
|
|
PyTuple_SetItem(t, 2, PyLong_FromUnsignedLong(nOwners));
|
|
|
|
PyList_SetItem(pyEL, i, t); // steals the ref
|
|
|
|
}
|
|
|
|
|
|
|
|
PyObject* retVal = PyObject_CallMethod(
|
|
|
|
fPyFunctionInstances[kfunc_gotPublicAgeList],
|
|
|
|
(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; m<nRcvs; m++ )
|
|
|
|
{
|
|
|
|
fReceivers.Append(mgr->ReadKey(stream));
|
|
|
|
}
|
|
|
|
|
|
|
|
// then read in the list of parameters
|
|
|
|
int nParms = stream->ReadLE32();
|
|
|
|
fParameters.SetCountAndZero(nParms);
|
|
|
|
int i;
|
|
|
|
for( i=0; i<nParms; i++ )
|
|
|
|
{
|
|
|
|
plPythonParameter parm;
|
|
|
|
parm.Read(stream,mgr);
|
|
|
|
fParameters[i] = parm;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void plPythonFileMod::Write(hsStream* stream, hsResMgr* mgr)
|
|
|
|
{
|
|
|
|
plMultiModifier::Write(stream, mgr);
|
|
|
|
|
|
|
|
stream->WriteSafeString(fPythonFile);
|
|
|
|
|
|
|
|
// then write out the list of receivers that want to be notified
|
|
|
|
stream->WriteLE32(fReceivers.GetCount());
|
|
|
|
int m;
|
|
|
|
for( m=0; m<fReceivers.GetCount(); m++ )
|
|
|
|
mgr->WriteKey(stream, fReceivers[m]);
|
|
|
|
|
|
|
|
// then write out the list of parameters
|
|
|
|
stream->WriteLE32(fParameters.GetCount());
|
|
|
|
int i;
|
|
|
|
for( i=0; i<fParameters.GetCount(); i++ )
|
|
|
|
fParameters[i].Write(stream,mgr);
|
|
|
|
}
|
|
|
|
|
|
|
|
//// kGlobalNameKonstant /////////////////////////////////////////////////
|
|
|
|
// My continued attempt to spread the CORRECT way to spell konstant. -mcn
|
|
|
|
|
|
|
|
plString plPythonFileMod::kGlobalNameKonstant("VeryVerySpecialPythonFileMod");
|