/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ #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