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.
443 lines
13 KiB
443 lines
13 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/>. |
|
|
|
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==*/ |
|
///////////////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// INCLUDES |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
// singular |
|
#include "plCoopCoordinator.h" |
|
|
|
// local |
|
#include "plAvBrainCoop.h" |
|
#include "plAvatarMgr.h" |
|
#include "plAvTaskBrain.h" |
|
#include "plAvTaskSeek.h" |
|
|
|
// global |
|
#include "hsUtils.h" |
|
|
|
// other |
|
#include "plMessage/plAvCoopMsg.h" |
|
#include "plMessage/plAvatarMsg.h" |
|
#include "plMessage/plInputIfaceMgrMsg.h" |
|
#include "pnMessage/plNotifyMsg.h" |
|
#include "pnNetCommon/plNetApp.h" |
|
#include "plNetClient/plNetClientMgr.h" |
|
#include "plPhysical.h" |
|
#include "pnTimer/plTimerCallbackManager.h" |
|
#include "plMessage/plTimerCallbackMsg.h" |
|
|
|
const unsigned kAbortTimer = 1; |
|
const float kAbortTimerDuration = 15; // 15 seconds |
|
|
|
///////////////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// CONSTRUCTORS |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
plCoopCoordinator::plCoopCoordinator() |
|
: fHostBrain(nil), |
|
fGuestBrain(nil), |
|
fInitiatorID(0), |
|
fInitiatorSerial(0), |
|
fHostOfferStage(0), |
|
fGuestAcceptStage(0), |
|
fGuestAcceptMsg(nil), |
|
fAutoStartGuest(nil), |
|
fGuestAccepted(false) |
|
{ |
|
} |
|
|
|
// plCoopCoordinator ---------------------------------------- |
|
// ------------------ |
|
plCoopCoordinator::plCoopCoordinator(plKey host, plKey guest, |
|
plAvBrainCoop *hostBrain, plAvBrainCoop *guestBrain, |
|
const char *synchBone, |
|
UInt32 hostOfferStage, UInt32 guestAcceptStage, |
|
plMessage *guestAcceptMsg, |
|
bool autoStartGuest) |
|
: fHostKey(host), |
|
fGuestKey(guest), |
|
fHostBrain(hostBrain), |
|
fGuestBrain(guestBrain), |
|
fInitiatorID(hostBrain->GetInitiatorID()), |
|
fInitiatorSerial(hostBrain->GetInitiatorSerial()), |
|
fHostOfferStage(hostOfferStage), |
|
fGuestAcceptStage(guestAcceptStage), |
|
fGuestAcceptMsg(guestAcceptMsg), |
|
fAutoStartGuest(autoStartGuest), |
|
fGuestAccepted(false), |
|
fGuestLinked(false) |
|
{ |
|
const char * hostName = host->GetName(); |
|
const char * guestName = guest->GetName(); |
|
static int serial = 0; |
|
|
|
int len = strlen(hostName) + strlen(guestName) + 3 /* serial num */ + 1; |
|
|
|
char *newName = TRACKED_NEW char[len]; |
|
|
|
serial = serial % 999; |
|
|
|
sprintf(newName, "%s%s%3i\x000", hostName, guestName, serial++); |
|
|
|
plKey newKey = hsgResMgr::ResMgr()->NewKey(newName, this, host->GetUoid().GetLocation()); |
|
|
|
delete[] newName; |
|
|
|
fSynchBone = hsStrcpy(synchBone); |
|
|
|
plKey avMgrKey = plAvatarMgr::GetInstance()->GetKey(); |
|
|
|
guestBrain->SetRecipient(avMgrKey); |
|
hostBrain->SetRecipient(avMgrKey); |
|
// disable our clickability here if we are the guest |
|
if (plNetClientMgr::GetInstance()->GetLocalPlayerKey() == guest) |
|
{ |
|
plInputIfaceMgrMsg* pMsg = TRACKED_NEW plInputIfaceMgrMsg(plInputIfaceMgrMsg::kGUIDisableAvatarClickable); |
|
pMsg->SetAvKey(guest); |
|
pMsg->SetBCastFlag(plMessage::kNetPropagate); |
|
pMsg->SetBCastFlag(plMessage::kNetForce); |
|
pMsg->Send(); |
|
} |
|
} |
|
|
|
// plCoopCoordinator ------------------ |
|
// ------------------ |
|
plCoopCoordinator::~plCoopCoordinator() |
|
{ |
|
delete[] fSynchBone; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////////////////// |
|
// |
|
// CONSTRUCTORS |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
// MsgReceive -------------------------------------- |
|
// ----------- |
|
hsBool plCoopCoordinator::MsgReceive(plMessage *msg) |
|
{ |
|
plNotifyMsg *notify = plNotifyMsg::ConvertNoRef(msg); |
|
if(notify) |
|
{ |
|
proMultiStageEventData * mtevt = static_cast<proMultiStageEventData *>(notify->FindEventRecord(proEventData::kMultiStage)); |
|
if(mtevt) |
|
{ |
|
int stageNum = mtevt->fStage; |
|
UInt32 stageState = mtevt->fEvent; |
|
|
|
plKey noteSender = notify->GetSender(); |
|
bool isFromHost = (noteSender == fHostKey); |
|
bool isFromGuest = (noteSender == fGuestKey); |
|
|
|
DebugMsg("COOP: Received multi-stage callback - stageNum = %d, stageState = %d, isFromHost = %d", stageNum, stageState, isFromHost ? 1 : 0); |
|
|
|
if(isFromHost) |
|
{ |
|
if(!fGuestAccepted) |
|
{ |
|
// we've just entered the host offer stage (i.e., the offer is ready) |
|
if(stageNum == fHostOfferStage && stageState == proEventData::kEnterStage) |
|
{ |
|
if(fAutoStartGuest) |
|
{ |
|
IStartGuest(); |
|
IStartTimeout(); |
|
} else { |
|
fHostBrain->EnableGuestClick(); |
|
} |
|
fGuestAccepted = true; |
|
} |
|
} |
|
|
|
} else if(isFromGuest) |
|
{ |
|
if(stageNum == fGuestAcceptStage && stageState == proEventData::kEnterStage) |
|
{ |
|
plKey localPlayer = plNetClientApp::GetInstance()->GetLocalPlayerKey(); |
|
|
|
// we only actually fire off the guest accept message if we're on the guest machine. |
|
// if it needs to be netpropped, the client can set that up when they set up the coop. |
|
if(fGuestAcceptMsg && localPlayer == fGuestKey) |
|
{ |
|
fGuestAcceptMsg->Send(); |
|
} |
|
// kill the message (along with being active) |
|
fGuestAcceptMsg = nil; |
|
fGuestLinked = true; |
|
IAdvanceParticipant(true); // advance the host |
|
// IAdvanceParticipant(false); // advance the guest |
|
} |
|
} else { |
|
// not from host; not from guest |
|
// let's assume for the moment it's from a trigger. |
|
IStartHost(); |
|
} |
|
} |
|
} |
|
|
|
plAvCoopMsg *coop = plAvCoopMsg::ConvertNoRef(msg); |
|
if(coop) |
|
{ |
|
DebugMsg("COOP: Received coop message: %d", coop->fCommand); |
|
switch(coop->fCommand) |
|
{ |
|
case plAvCoopMsg::kGuestAccepted: |
|
IStartGuest(); |
|
IStartTimeout(); |
|
break; |
|
|
|
case plAvCoopMsg::kGuestSeeked: |
|
// if they did make it to their target, then continue |
|
IContinueGuest(); |
|
break; |
|
|
|
case plAvCoopMsg::kGuestSeekAbort: |
|
// if they aborted then just advance the host |
|
// kill the message (along with being active) |
|
fGuestAcceptMsg = nil; |
|
fGuestLinked = true; |
|
IAdvanceParticipant(true); // advance the host |
|
break; |
|
|
|
} |
|
} |
|
|
|
plAvTaskSeekDoneMsg *seekDone = plAvTaskSeekDoneMsg::ConvertNoRef(msg); |
|
if (seekDone) |
|
{ |
|
DebugMsg("COOP: Received avatar seek finished msg: aborted = %d", seekDone->fAborted ? 1 : 0); |
|
if ( seekDone->fAborted ) |
|
{ |
|
plAvCoopMsg *coopM = TRACKED_NEW plAvCoopMsg(plAvCoopMsg::kGuestSeekAbort,fInitiatorID,(UInt16)fInitiatorSerial); |
|
coopM->SetBCastFlag(plMessage::kNetPropagate); |
|
coopM->SetBCastFlag(plMessage::kNetForce); |
|
coopM->AddReceiver(GetKey()); |
|
coopM->Send(); |
|
|
|
} |
|
else |
|
{ |
|
plAvCoopMsg *coopM = TRACKED_NEW plAvCoopMsg(plAvCoopMsg::kGuestSeeked,fInitiatorID,(UInt16)fInitiatorSerial); |
|
coopM->SetBCastFlag(plMessage::kNetPropagate); |
|
coopM->SetBCastFlag(plMessage::kNetForce); |
|
coopM->AddReceiver(GetKey()); |
|
coopM->Send(); |
|
} |
|
} |
|
|
|
plTimerCallbackMsg* timerMsg = plTimerCallbackMsg::ConvertNoRef(msg); |
|
if (timerMsg) |
|
{ |
|
if (timerMsg->fID == kAbortTimer && !fGuestLinked) |
|
ITimeout(); |
|
} |
|
return false; |
|
} |
|
|
|
// Run ---------------------- |
|
// ---- |
|
void plCoopCoordinator::Run() |
|
{ |
|
IStartHost(); |
|
} |
|
|
|
bool plCoopCoordinator::IsActiveForReal() |
|
{ |
|
return fGuestAcceptMsg ? true : false; |
|
} |
|
|
|
// GetInitiatorID ------------------------ |
|
// --------------- |
|
UInt32 plCoopCoordinator::GetInitiatorID() |
|
{ |
|
return fInitiatorID; |
|
} |
|
|
|
// GetInitiatorSerial ------------------------ |
|
UInt16 plCoopCoordinator::GetInitiatorSerial() |
|
{ |
|
return (UInt16)fInitiatorSerial; |
|
} |
|
|
|
// IStartHost ---------------------- |
|
// ----------- |
|
void plCoopCoordinator::IStartHost() |
|
{ |
|
DebugMsg("COOP: IStartHost()"); |
|
plArmatureMod *guestAv = plAvatarMgr::FindAvatar(fGuestKey); |
|
plArmatureMod *hostAv = plAvatarMgr::FindAvatar(fHostKey); |
|
if (guestAv && hostAv) |
|
{ |
|
plAvSeekMsg *msg = TRACKED_NEW plAvSeekMsg(nil, hostAv->GetKey(), nil, 1.f, true); |
|
hsClearBits(msg->fFlags, plAvSeekMsg::kSeekFlagForce3rdPersonOnStart); |
|
guestAv->GetPositionAndRotationSim(&msg->fTargetLookAt, nil); |
|
hostAv->GetPositionAndRotationSim(&msg->fTargetPos, nil); |
|
msg->Send(); |
|
} |
|
|
|
// now tell the host to initiate the thing. |
|
plAvTaskBrain *brainT = TRACKED_NEW plAvTaskBrain(fHostBrain); |
|
plAvTaskMsg *brainM = TRACKED_NEW plAvTaskMsg(GetKey(), fHostKey, brainT); |
|
brainM->SetBCastFlag(plMessage::kPropagateToModifiers); |
|
brainM->Send(); |
|
} |
|
|
|
// IStartGuest ---------------------- |
|
// ------------ |
|
void plCoopCoordinator::IStartGuest() |
|
{ |
|
DebugMsg("COOP: IStartGuest()"); |
|
plSceneObject *avSO = plSceneObject::ConvertNoRef(fHostKey->ObjectIsLoaded()); |
|
if ( !avSO ) |
|
return; |
|
|
|
const plArmatureMod *hostAv = (plArmatureMod*)avSO->GetModifierByType(plArmatureMod::Index()); |
|
if ( hostAv ) |
|
{ |
|
const plSceneObject *targetBone = hostAv->FindBone(fSynchBone); |
|
if(targetBone) |
|
{ |
|
plAvSeekMsg *seekMsg = TRACKED_NEW plAvSeekMsg( nil, nil,targetBone->GetKey(), 0, true, kAlignHandle, nil, false, plAvSeekMsg::kSeekFlagNoWarpOnTimeout, GetKey()); |
|
plAvTaskSeek *seekT = TRACKED_NEW plAvTaskSeek(seekMsg); |
|
plAvTaskMsg *seekM = TRACKED_NEW plAvTaskMsg(GetKey(), fGuestKey, seekT); |
|
seekM->SetBCastFlag(plMessage::kPropagateToModifiers); |
|
seekM->Send(); |
|
} |
|
} |
|
} |
|
|
|
// IContinueGuest ---------------------- |
|
// ------------ |
|
void plCoopCoordinator::IContinueGuest() |
|
{ |
|
DebugMsg("COOP: IContinueGuest()"); |
|
plAvTaskBrain *brainT = TRACKED_NEW plAvTaskBrain(fGuestBrain); |
|
plAvTaskMsg *brainM = TRACKED_NEW plAvTaskMsg(GetKey(), fGuestKey, brainT); |
|
brainM->SetBCastFlag(plMessage::kPropagateToModifiers); |
|
brainM->Send(); |
|
fGuestBrain = nil; // the armature will destroy the brain when done. |
|
} |
|
|
|
// IContinueHost ---------------------- |
|
// -------------- |
|
void plCoopCoordinator::IAdvanceParticipant(bool host) |
|
{ |
|
DebugMsg("COOP: IAdvanceParticipant(%d)", host ? 1 : 0); |
|
plKey &who = host ? fHostKey : fGuestKey; |
|
|
|
plAvBrainGenericMsg* pMsg = TRACKED_NEW plAvBrainGenericMsg(nil, who, |
|
plAvBrainGenericMsg::kNextStage, 0, false, 0.0, |
|
false, false, 0.0); |
|
|
|
pMsg->SetBCastFlag(plMessage::kPropagateToModifiers); |
|
|
|
pMsg->Send(); |
|
} |
|
|
|
// IStartTimeout ---------------------- |
|
// -------------- |
|
void plCoopCoordinator::IStartTimeout() |
|
{ |
|
plTimerCallbackMsg* timerMsg = TRACKED_NEW plTimerCallbackMsg(GetKey(), kAbortTimer); |
|
plgTimerCallbackMgr::NewTimer(kAbortTimerDuration, timerMsg); |
|
} |
|
|
|
// ITimeout --------------------------- |
|
// -------------- |
|
void plCoopCoordinator::ITimeout() |
|
{ |
|
fGuestAcceptMsg = nil; |
|
IAdvanceParticipant(true); // advance the host |
|
} |
|
|
|
// Read ------------------------------------------------------------- |
|
// ----- |
|
void plCoopCoordinator::Read(hsStream *stream, hsResMgr *mgr) |
|
{ |
|
fHostKey = mgr->ReadKey(stream); |
|
fGuestKey = mgr->ReadKey(stream); |
|
|
|
fHostBrain = plAvBrainCoop::ConvertNoRef(mgr->ReadCreatable(stream)); |
|
fGuestBrain = plAvBrainCoop::ConvertNoRef(mgr->ReadCreatable(stream)); |
|
|
|
fHostOfferStage = stream->ReadByte(); |
|
fGuestAcceptStage = stream->ReadBool(); |
|
|
|
if(stream->Readbool()) |
|
fGuestAcceptMsg = plMessage::ConvertNoRef(mgr->ReadCreatable(stream)); |
|
else |
|
fGuestAcceptMsg = nil; |
|
|
|
fSynchBone = stream->ReadSafeString(); |
|
fAutoStartGuest = stream->Readbool(); |
|
|
|
fInitiatorID = fHostBrain->GetInitiatorID(); |
|
fInitiatorSerial = fHostBrain->GetInitiatorSerial(); |
|
} |
|
|
|
// Write ------------------------------------------------------------- |
|
// ------ |
|
void plCoopCoordinator::Write(hsStream *stream, hsResMgr *mgr) |
|
{ |
|
mgr->WriteKey(stream, fHostKey); |
|
mgr->WriteKey(stream, fGuestKey); |
|
|
|
mgr->WriteCreatable(stream, fHostBrain); |
|
mgr->WriteCreatable(stream, fGuestBrain); |
|
|
|
stream->WriteByte((UInt8)fHostOfferStage); |
|
stream->WriteByte((UInt8)fGuestAcceptStage); |
|
|
|
stream->Writebool(fGuestAcceptMsg != nil); |
|
if(fGuestAcceptMsg) |
|
mgr->WriteCreatable(stream, fGuestAcceptMsg); |
|
|
|
stream->WriteSafeString(fSynchBone); |
|
stream->Writebool(fAutoStartGuest); |
|
} |
|
|
|
|