|
|
|
/*==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==*/
|
|
|
|
#include "hsTypes.h"
|
|
|
|
#include "plLogicModBase.h"
|
|
|
|
#include "plgDispatch.h"
|
|
|
|
#include "hsResMgr.h"
|
|
|
|
#include "hsTimer.h"
|
|
|
|
#include "../pnTimer/plTimerCallbackManager.h"
|
|
|
|
#include "../pnSceneObject/plSceneObject.h"
|
|
|
|
#include "../pnNetCommon/plGenericVar.h"
|
|
|
|
#include "../pnNetCommon/plNetApp.h"
|
|
|
|
#include "../pnNetCommon/plNetSharedState.h"
|
|
|
|
#include "../../PubUtilLib/plNetMessage/plNetMessage.h" // breaks project dependancy levels
|
|
|
|
#include "../pnMessage/plNotifyMsg.h"
|
|
|
|
#include "../pnMessage/plEnableMsg.h"
|
|
|
|
#include "../pnMessage/plServerReplyMsg.h"
|
|
|
|
|
|
|
|
uint32_t plLogicModBase::sArbitrationDelayMs = 0;
|
|
|
|
|
|
|
|
void plLogicModBase::ConsoleTrigger(plKey playerKey)
|
|
|
|
{
|
|
|
|
// Setup the event data in case this is a OneShot responder that needs it
|
|
|
|
proPickedEventData *ed = TRACKED_NEW proPickedEventData;
|
|
|
|
ed->fPicker = playerKey;
|
|
|
|
ed->fPicked = nil;
|
|
|
|
fNotify->AddEvent(ed);
|
|
|
|
|
|
|
|
Trigger(false);
|
|
|
|
|
|
|
|
// Whoops, trigger and untrigger use the same message, so if we do this right away
|
|
|
|
// it will just untrigger twice. So...uhh, we don't untrigger!
|
|
|
|
// UnTrigger();
|
|
|
|
}
|
|
|
|
|
|
|
|
void plLogicModBase::ConsoleRequestTrigger()
|
|
|
|
{
|
|
|
|
RequestTrigger();
|
|
|
|
}
|
|
|
|
|
|
|
|
plLogicModBase::plLogicModBase() :
|
|
|
|
fCounter(0),
|
|
|
|
fCounterLimit(0),
|
|
|
|
fTimer(0.0f),
|
|
|
|
fNotify(nil),
|
|
|
|
fDisabled(false)
|
|
|
|
{
|
|
|
|
fNotify = TRACKED_NEW plNotifyMsg;
|
|
|
|
}
|
|
|
|
|
|
|
|
plLogicModBase::~plLogicModBase()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < fCommandList.Count(); i++ )
|
|
|
|
{
|
|
|
|
hsRefCnt_SafeUnRef(fCommandList[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
hsRefCnt_SafeUnRef(fNotify);
|
|
|
|
}
|
|
|
|
|
|
|
|
void plLogicModBase::AddTarget(plSceneObject* so)
|
|
|
|
{
|
|
|
|
plSingleModifier::AddTarget(so);
|
|
|
|
}
|
|
|
|
|
|
|
|
void plLogicModBase::RegisterForMessageType(UInt16 hClass)
|
|
|
|
{
|
|
|
|
plgDispatch::Dispatch()->RegisterForExactType( hClass, GetKey() );
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Update generic shared state (which reflects trigger state) on server
|
|
|
|
// by sending TestAndSet request. By locking and unlocking the sharedState,
|
|
|
|
// we can guarantee that only one logicMod instance can trigger at a time.
|
|
|
|
// The server will confirm or deny our request to lock and set the state.
|
|
|
|
//
|
|
|
|
void plLogicModBase::IUpdateSharedState(bool triggered) const
|
|
|
|
{
|
|
|
|
plNetSharedState ss("TrigState");
|
|
|
|
plGenericVar* sv = TRACKED_NEW plGenericVar("Triggered");
|
|
|
|
sv->Value().SetBool(triggered); // attempting to set trig state to true
|
|
|
|
ss.AddVar(sv);
|
|
|
|
|
|
|
|
bool lock = triggered;
|
|
|
|
|
|
|
|
// if unlocking, then the server does not need to store this state, since it's back to its default state
|
|
|
|
ss.SetServerMayDelete(!lock);
|
|
|
|
|
|
|
|
plNetMsgTestAndSet ts;
|
|
|
|
ts.SetNetProtocol(kNetProtocolCli2Game);
|
|
|
|
ts.CopySharedState(&ss);
|
|
|
|
ts.ObjectInfo()->SetFromKey(GetKey());
|
|
|
|
ts.SetLockRequest(lock); // if triggering, lock state, else unlock state
|
|
|
|
plNetClientApp::GetInstance()->SendMsg(&ts);
|
|
|
|
plNetClientApp::GetInstance()->DebugMsg("\tLM: Attempting to set logic mod shared lock to %s, t=%f\n",
|
|
|
|
triggered ? "Triggered" : "UnTriggered", hsTimer::GetSysSeconds());
|
|
|
|
}
|
|
|
|
|
|
|
|
hsBool plLogicModBase::MsgReceive(plMessage* msg)
|
|
|
|
{
|
|
|
|
// read messages:
|
|
|
|
plServerReplyMsg* pSMsg = plServerReplyMsg::ConvertNoRef(msg);
|
|
|
|
if (pSMsg)
|
|
|
|
{
|
|
|
|
if (sArbitrationDelayMs == 0 || pSMsg->GetWasDelayed()) {
|
|
|
|
IHandleArbitration(pSMsg);
|
|
|
|
} else {
|
|
|
|
pSMsg->SetWasDelayed(true);
|
|
|
|
pSMsg->Ref(); // timer callback manager steals this reference
|
|
|
|
plgTimerCallbackMgr::NewTimer(static_cast<float>(sArbitrationDelayMs) / 1000, pSMsg);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
plEnableMsg* pEnable = plEnableMsg::ConvertNoRef(msg);
|
|
|
|
if (pEnable)
|
|
|
|
{
|
|
|
|
if (pEnable->Cmd(plEnableMsg::kDisable))
|
|
|
|
fDisabled = true;
|
|
|
|
else
|
|
|
|
if (pEnable->Cmd(plEnableMsg::kEnable))
|
|
|
|
{
|
|
|
|
ClearFlag(kTriggered);
|
|
|
|
ClearFlag(kRequestingTrigger);
|
|
|
|
|
|
|
|
fDisabled = false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return plSingleModifier::MsgReceive(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void plLogicModBase::IHandleArbitration(plServerReplyMsg* pSMsg)
|
|
|
|
{
|
|
|
|
hsAssert(pSMsg->GetType() != plServerReplyMsg::kUnInit, "uninit server reply msg");
|
|
|
|
plNetClientApp::GetInstance()->DebugMsg("LM: LogicModifier {} recvd trigger request reply:{}, wasRequesting={}, t={f}\n",
|
|
|
|
GetKeyName(),
|
|
|
|
pSMsg->GetType() == plServerReplyMsg::kDeny ? "denied" : "confirmed",
|
|
|
|
HasFlag(kRequestingTrigger), hsTimer::GetSysSeconds());
|
|
|
|
|
|
|
|
if (pSMsg->GetType() == plServerReplyMsg::kDeny) {
|
|
|
|
if (HasFlag(kRequestingTrigger)) {
|
|
|
|
plNetClientApp::GetInstance()->DebugMsg("\tLM: Denied, clearing requestingTrigger");
|
|
|
|
ClearFlag(kRequestingTrigger);
|
|
|
|
} else {
|
|
|
|
plNetClientApp::GetInstance()->DebugMsg("\tLM: Denied, but not requesting?");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bool netRequest=false; // we're triggering as a result of a local activation
|
|
|
|
PreTrigger(netRequest);
|
|
|
|
IUpdateSharedState(false /* untriggering */);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void plLogicModBase::RequestTrigger(hsBool netRequest)
|
|
|
|
{
|
|
|
|
if (HasFlag(kTriggered))
|
|
|
|
{
|
|
|
|
#if 1
|
|
|
|
char str[256];
|
|
|
|
sprintf(str, "LM: %s ignoring RequestTrigger(), already triggered, t=%f\n", GetKeyName(),
|
|
|
|
hsTimer::GetSysSeconds());
|
|
|
|
plNetClientApp::GetInstance()->DebugMsg(str);
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HasFlag(kRequestingTrigger))
|
|
|
|
{
|
|
|
|
#if 1
|
|
|
|
char str[256];
|
|
|
|
sprintf(str, "LM: %s ignoring RequestTrigger(), already requesting trigger, t=%f\n", GetKeyName(),
|
|
|
|
hsTimer::GetSysSeconds());
|
|
|
|
plNetClientApp::GetInstance()->DebugMsg(str);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if ( plNetApp::GetInstance()->GetFlagsBit(plNetClientApp::kLocalTriggers))
|
|
|
|
{
|
|
|
|
PreTrigger(false);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IUpdateSharedState(true /* triggering */); // request arbitration from server
|
|
|
|
SetFlag(kRequestingTrigger);
|
|
|
|
|
|
|
|
#if 1
|
|
|
|
char str[256];
|
|
|
|
sprintf(str, "LM: %s Setting RequestingTriggert=%f\n", GetKeyName(), hsTimer::GetSysSeconds());
|
|
|
|
plNetClientApp::GetInstance()->DebugMsg(str);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// return false is counter test fails
|
|
|
|
//
|
|
|
|
hsBool plLogicModBase::IEvalCounter()
|
|
|
|
{
|
|
|
|
if (fCounterLimit > 0)
|
|
|
|
{
|
|
|
|
fCounter = fCounter + 1;
|
|
|
|
if (fCounter != fCounterLimit)
|
|
|
|
{
|
|
|
|
Reset(false);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void plLogicModBase::PreTrigger(hsBool netRequest)
|
|
|
|
{
|
|
|
|
if (fDisabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Trigger(netRequest);
|
|
|
|
}
|
|
|
|
|
|
|
|
void plLogicModBase::Trigger(hsBool netRequest)
|
|
|
|
{
|
|
|
|
#if 1
|
|
|
|
char str[256];
|
|
|
|
sprintf(str, "LogicModifier %s is triggering, activatorType=%d\n",
|
|
|
|
GetKeyName(), HasFlag(kTypeActivator));
|
|
|
|
plNetClientApp::GetInstance()->DebugMsg(str);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
ClearFlag(kRequestingTrigger);
|
|
|
|
if (!HasFlag(kMultiTrigger))
|
|
|
|
SetFlag(kTriggered);
|
|
|
|
fNotify->SetSender(this->GetKey());
|
|
|
|
fNotify->SetState(1.0f);
|
|
|
|
fNotify->AddActivateEvent(true);
|
|
|
|
// hsRefCnt_SafeRef(fNotify);
|
|
|
|
plgDispatch::MsgSend( fNotify );
|
|
|
|
CreateNotifyMsg();
|
|
|
|
if (HasFlag(kOneShot))
|
|
|
|
fDisabled = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void plLogicModBase::UnTrigger()
|
|
|
|
{
|
|
|
|
if (!HasFlag(kTriggered))
|
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef HS_DEBUGGING
|
|
|
|
char str[256];
|
|
|
|
sprintf(str, "LogicModifier %s is Un-triggering, activatorType=%d\n",
|
|
|
|
GetKeyName(), HasFlag(kTypeActivator));
|
|
|
|
plNetClientApp::GetInstance()->DebugMsg(str);
|
|
|
|
#endif
|
|
|
|
fNotify->SetSender(this->GetKey());
|
|
|
|
fNotify->SetState(0.0f);
|
|
|
|
fNotify->AddActivateEvent(false);
|
|
|
|
// hsRefCnt_SafeRef(fNotify);
|
|
|
|
plgDispatch::MsgSend( fNotify );
|
|
|
|
CreateNotifyMsg();
|
|
|
|
Reset(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void plLogicModBase::Reset(bool bCounterReset)
|
|
|
|
{
|
|
|
|
ClearFlag(kTriggered);
|
|
|
|
if (bCounterReset)
|
|
|
|
fCounter = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void plLogicModBase::CreateNotifyMsg()
|
|
|
|
{
|
|
|
|
fNotify = TRACKED_NEW plNotifyMsg;
|
|
|
|
for (int i = 0; i < fReceiverList.Count(); i++)
|
|
|
|
fNotify->AddReceiver(fReceiverList[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void plLogicModBase::AddNotifyReceiver(plKey receiver)
|
|
|
|
{
|
|
|
|
fReceiverList.Append(receiver);
|
|
|
|
fNotify->AddReceiver(receiver);
|
|
|
|
}
|
|
|
|
|
|
|
|
void plLogicModBase::Read(hsStream* stream, hsResMgr* mgr)
|
|
|
|
{
|
|
|
|
plSingleModifier::Read(stream, mgr);
|
|
|
|
int n = stream->ReadSwap32();
|
|
|
|
fCommandList.SetCountAndZero(n);
|
|
|
|
for(int i = 0; i < n; i++ )
|
|
|
|
{
|
|
|
|
plMessage* pMsg = plMessage::ConvertNoRef(mgr->ReadCreatable(stream));
|
|
|
|
fCommandList[i] = pMsg;
|
|
|
|
}
|
|
|
|
if (fNotify)
|
|
|
|
delete fNotify;
|
|
|
|
plNotifyMsg* pNMsg = plNotifyMsg::ConvertNoRef(mgr->ReadCreatable(stream));
|
|
|
|
fNotify = pNMsg;
|
|
|
|
|
|
|
|
fFlags.Read(stream);
|
|
|
|
fDisabled = stream->Readbool();
|
|
|
|
for (int d = 0; d < fNotify->GetNumReceivers(); d++)
|
|
|
|
fReceiverList.Append(fNotify->GetReceiver(d));
|
|
|
|
}
|
|
|
|
|
|
|
|
void plLogicModBase::Write(hsStream* stream, hsResMgr* mgr)
|
|
|
|
{
|
|
|
|
plSingleModifier::Write(stream, mgr);
|
|
|
|
stream->WriteSwap32(fCommandList.GetCount());
|
|
|
|
for(int i = 0; i < fCommandList.GetCount(); i++ )
|
|
|
|
mgr->WriteCreatable( stream, fCommandList[i] );
|
|
|
|
mgr->WriteCreatable( stream, fNotify );
|
|
|
|
fFlags.Write(stream);
|
|
|
|
stream->Writebool(fDisabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Maintainers Marker Component
|
|
|
|
//
|
|
|
|
//
|
|
|
|
#if 0
|
|
|
|
#include "../plModifier/plMaintainersMarkerModifier.h"
|
|
|
|
|
|
|
|
//Class that accesses the paramblock below.
|
|
|
|
class plMaintainersMarkerComponent : public plComponent
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
plMaintainersMarkerComponent();
|
|
|
|
void DeleteThis() { delete this; }
|
|
|
|
hsBool SetupProperties(plMaxNode* node, plErrorMsg* pErrMsg);
|
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg);
|
|
|
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg);
|
|
|
|
};
|
|
|
|
|
|
|
|
//Max desc stuff necessary.
|
|
|
|
CLASS_DESC(plMaintainersMarkerComponent, gMaintainersDesc, "Maintainers Marker", "MaintainersMarker", COMP_TYPE_TYPE, Class_ID(0x7d7f1f72, 0x405355f5))
|
|
|
|
|
|
|
|
//The MAX paramblock stuff below
|
|
|
|
ParamBlockDesc2 gMaintainersBk
|
|
|
|
(
|
|
|
|
1, _T("maintainersMarker"), 0, &gMaintainersDesc, P_AUTO_CONSTRUCT, plComponent::kRefComp,
|
|
|
|
end
|
|
|
|
);
|
|
|
|
|
|
|
|
plMaintainersMarkerComponent::plMaintainersMarkerComponent()
|
|
|
|
{
|
|
|
|
fClassDesc = &gMaintainersDesc;
|
|
|
|
fClassDesc->MakeAutoParamBlocks(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
hsBool plMaintainersMarkerComponent::SetupProperties(plMaxNode* node, plErrorMsg* pErrMsg)
|
|
|
|
{
|
|
|
|
node->SetForceLocal(true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
hsBool plMaintainersMarkerComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg)
|
|
|
|
{
|
|
|
|
plMaintainersMarkerModifier* pSpawn = TRACKED_NEW plMaintainersMarkerModifier;
|
|
|
|
node->AddModifier(pSpawn);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
hsBool plMaintainersMarkerComponent::PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|