You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

388 lines
10 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
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 "../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"
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)
{
hsAssert(pSMsg->GetType() != plServerReplyMsg::kUnInit, "uninit server reply msg");
#if 1
char str[256];
sprintf(str, "LM: LogicModifier %s recvd trigger request reply:%s, wasRequesting=%d, t=%f\n", GetKeyName(),
pSMsg->GetType() == plServerReplyMsg::kDeny ? "denied" : "confirmed",
HasFlag(kRequestingTrigger), hsTimer::GetSysSeconds());
plNetClientApp::GetInstance()->DebugMsg(str);
#endif
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
{
hsBool netRequest=false; // we're triggering as a result of a local activation
PreTrigger(netRequest);
IUpdateSharedState(false /* untriggering */);
}
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::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