mirror of
https://bitbucket.org/theswgsource/src-1.2.git
synced 2026-10-19 09:02:53 -04:00
1317 lines
41 KiB
C++
Executable File
1317 lines
41 KiB
C++
Executable File
// ======================================================================
|
|
//
|
|
// ServerController.cpp
|
|
// copyright (c) 2001 Sony Online Entertainment
|
|
//
|
|
// ======================================================================
|
|
|
|
#include "serverGame/FirstServerGame.h"
|
|
#include "serverGame/ServerController.h"
|
|
|
|
#include "LocalizationManager.h"
|
|
#include "UnicodeUtils.h"
|
|
#include "serverGame/CellObject.h"
|
|
#include "serverGame/Client.h"
|
|
#include "serverGame/ConfigServerGame.h"
|
|
#include "serverGame/ContainerInterface.h"
|
|
#include "serverGame/CreatureObject.h"
|
|
#include "serverGame/GameServer.h"
|
|
#include "serverGame/ServerCreatureObjectTemplate.h"
|
|
#include "serverGame/ServerMessageForwarding.h"
|
|
#include "serverGame/ServerObject.h"
|
|
#include "serverGame/ServerWorld.h"
|
|
#include "serverNetworkMessages/MessageQueueScriptTrigger.h"
|
|
#include "serverNetworkMessages/MessageQueueTeleportObject.h"
|
|
#include "serverScript/GameScriptObject.h"
|
|
#include "serverScript/ScriptParameters.h"
|
|
#include "serverUtility/ChatLogManager.h"
|
|
#include "sharedCollision/CollisionProperty.h"
|
|
#include "sharedCollision/CollisionWorld.h"
|
|
#include "sharedDebug/Profiler.h"
|
|
#include "sharedFoundation/DynamicVariableList.h"
|
|
#include "sharedFoundation/DynamicVariableLocationData.h"
|
|
#include "sharedFoundation/GameControllerMessage.h"
|
|
#include "sharedFoundation/Timer.h"
|
|
#include "sharedGame/GameObjectTypes.h"
|
|
#include "sharedLog/Log.h"
|
|
#include "sharedNetworkMessages/ControllerMessageFactory.h"
|
|
#include "sharedNetworkMessages/GenericValueTypeMessage.h"
|
|
#include "sharedNetworkMessages/MessageQueueCombatSpam.h"
|
|
#include "sharedNetworkMessages/MessageQueueDataTransform.h"
|
|
#include "sharedNetworkMessages/MessageQueueDataTransformWithParent.h"
|
|
#include "sharedNetworkMessages/MessageQueueNetworkIdAndTransform.h"
|
|
#include "sharedNetworkMessages/MessageQueueSocial.h"
|
|
#include "sharedNetworkMessages/MessageQueueSpatialChat.h"
|
|
#include "sharedNetworkMessages/MessageQueueString.h"
|
|
#include "sharedNetworkMessages/ObjectChannelMessages.h"
|
|
#include "sharedNetworkMessages/UpdateTransformMessage.h"
|
|
#include "sharedNetworkMessages/UpdateTransformWithParentMessage.h"
|
|
#include "sharedObject/AlterResult.h"
|
|
#include "sharedObject/CellProperty.h"
|
|
#include "sharedObject/NetworkIdManager.h"
|
|
#include "swgServerNetworkMessages/MessageQueueScriptTransferMoney.h"
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
CellProperty const * getCell(Object const * obj)
|
|
{
|
|
if(obj == nullptr) return nullptr;
|
|
|
|
return obj->getCellProperty();
|
|
}
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// ----------
|
|
// This isn't being used yet...
|
|
|
|
Vector movePointBetweenCells ( Object const * oldCellObject, Object const * newCellObject, Vector position )
|
|
{
|
|
if(oldCellObject == newCellObject) return position;
|
|
|
|
// ----------
|
|
|
|
Transform toWorld = Transform::identity;
|
|
Transform toCell = Transform::identity;
|
|
|
|
if(oldCellObject != nullptr)
|
|
{
|
|
CellProperty const * oldCell = getCell(oldCellObject);
|
|
|
|
if(oldCell)
|
|
{
|
|
toWorld = oldCell->getOwner().getTransform_o2w();
|
|
}
|
|
}
|
|
|
|
if(newCellObject != nullptr)
|
|
{
|
|
CellProperty const * newCell = getCell(newCellObject);
|
|
|
|
if(newCell)
|
|
{
|
|
toCell = newCell->getOwner().getTransform_o2w();
|
|
}
|
|
}
|
|
|
|
// ----------
|
|
|
|
Vector worldPos = toWorld.rotateTranslate_l2p(position);
|
|
|
|
Vector newCellPos = toCell.rotateTranslate_p2l(worldPos);
|
|
|
|
return newCellPos;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
// This isn't being used yet...
|
|
|
|
Transform moveTransformBetweenCells ( Object const * oldCellObject, Object const * newCellObject, Transform const & inTransform )
|
|
{
|
|
if(oldCellObject == newCellObject) return inTransform;
|
|
|
|
// ----------
|
|
|
|
Transform toWorld = Transform::identity;
|
|
Transform toCell = Transform::identity;
|
|
|
|
if(oldCellObject != nullptr)
|
|
{
|
|
CellProperty const * oldCell = getCell(oldCellObject);
|
|
|
|
if(oldCell)
|
|
{
|
|
toWorld = oldCell->getOwner().getTransform_o2w();
|
|
}
|
|
}
|
|
|
|
if(newCellObject != nullptr)
|
|
{
|
|
CellProperty const * newCell = getCell(newCellObject);
|
|
|
|
if(newCell)
|
|
{
|
|
toCell = newCell->getOwner().getTransform_o2w();
|
|
}
|
|
}
|
|
|
|
// ----------
|
|
|
|
// Out transform = toCell * toWorld * inTransform
|
|
|
|
Transform temp;
|
|
|
|
temp.multiply(toCell,toWorld);
|
|
|
|
Transform out;
|
|
|
|
out.multiply(temp,inTransform);
|
|
|
|
return out;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
ServerController::MessageQueueNotification::MessageQueueNotification() :
|
|
Notification(),
|
|
m_serverController(0)
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
ServerController::MessageQueueNotification::~MessageQueueNotification()
|
|
{
|
|
m_serverController = 0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void ServerController::MessageQueueNotification::setController(ServerController* serverController)
|
|
{
|
|
m_serverController = serverController;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void ServerController::MessageQueueNotification::onChanged() const
|
|
{
|
|
NOT_NULL(m_serverController);
|
|
m_serverController->onAppendMessage();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
ServerController::ServerController(Object *newOwner) :
|
|
NetworkController (newOwner),
|
|
m_sendReliableTransformThisFrame(true),
|
|
m_moveSequenceNumber (0),
|
|
m_currentVelocity (Vector::zero),
|
|
m_oldVelocity (Vector::zero),
|
|
m_goalTransform (Transform::identity),
|
|
m_goalCellObject (),
|
|
m_bProcessingMessages (false),
|
|
m_bHasGoal (false),
|
|
m_bAtGoal (false),
|
|
m_bTeleport (false),
|
|
m_alteredSinceConclude (false),
|
|
m_notification ()
|
|
{
|
|
m_notification.setController (this);
|
|
setMessageQueueNotification (&m_notification);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
ServerController::~ServerController(void)
|
|
{
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
void ServerController::endBaselines()
|
|
{
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
void ServerController::setAuthoritative(bool newAuthoritative)
|
|
{
|
|
if (!newAuthoritative && m_bHasGoal && m_goalCellObject)
|
|
{
|
|
m_goalCellObject = nullptr;
|
|
m_bHasGoal = false;
|
|
m_bAtGoal = true;
|
|
}
|
|
|
|
NetworkController::setAuthoritative(newAuthoritative);
|
|
} // ServerController::setAuthoritative
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
void ServerController::setOwner(Object *newOwner)
|
|
{
|
|
NOT_NULL(safe_cast<ServerObject*>(newOwner));
|
|
Controller::setOwner(newOwner);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
int ServerController::elevatorMove( int nFloors )
|
|
{
|
|
CollisionProperty * collision = getOwner()->getCollisionProperty();
|
|
|
|
if(collision)
|
|
{
|
|
Transform elevatorTransform;
|
|
|
|
int movedFloors = collision->elevatorMove(nFloors,elevatorTransform);
|
|
|
|
if(movedFloors)
|
|
{
|
|
ServerObject * cellObject = dynamic_cast<ServerObject *>(&(getOwner()->getParentCell()->getOwner()));
|
|
teleport(elevatorTransform,cellObject);
|
|
}
|
|
|
|
return movedFloors;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
float ServerController::realAlter(float time)
|
|
{
|
|
PROFILER_AUTO_BLOCK_DEFINE("ServerController::realAlter");
|
|
|
|
int message;
|
|
real value;
|
|
MessageQueue::Data* data;
|
|
uint32 flags;
|
|
|
|
ServerObject *target = static_cast<ServerObject *>(getOwner());
|
|
|
|
// ----------
|
|
|
|
m_bProcessingMessages = true;
|
|
|
|
int i;
|
|
int const messageCount = getNumberOfMessages();
|
|
for (i = 0; i < messageCount; ++i)
|
|
{
|
|
getMessage(i, &message, &value, &data, &flags);
|
|
if (message)
|
|
{
|
|
// if the message is for an authoritative/proxy, make sure we are
|
|
// the right type
|
|
bool processMessage = false;
|
|
if (flags & GameControllerMessageFlags::DEST_AUTH_SERVER)
|
|
{
|
|
if (target->isAuthoritative())
|
|
processMessage = true;
|
|
else
|
|
{
|
|
if(ConfigServerGame::getEnableDebugControllerMessageSpam())
|
|
{
|
|
if(messageCount > 1000)
|
|
{
|
|
if(message == CM_scriptTrigger)
|
|
{
|
|
const MessageQueueScriptTrigger * const triggerMessage = dynamic_cast<const MessageQueueScriptTrigger *>(data);
|
|
if(triggerMessage)
|
|
{
|
|
const Scripting::TrigId trigId = static_cast<const Scripting::TrigId>(triggerMessage->getTriggerId());
|
|
LOG("ObjControllerMessageSTORM:CM_scriptTrigger", ("(%s:%s) received a CM_scriptTrigger. The object is not authoritative and there are over 1000 messages pending in the queue! script TrigId=%d", target->getObjectTemplateName(), target->getNetworkId().getValueString().c_str(), trigId));
|
|
if (!target->isPlayerControlled() && target->asCreatureObject())
|
|
target->unload();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (flags & GameControllerMessageFlags::DEST_PROXY_SERVER)
|
|
{
|
|
if (!target->isAuthoritative())
|
|
processMessage = true;
|
|
}
|
|
if (flags & GameControllerMessageFlags::DEST_SERVER)
|
|
{
|
|
processMessage = true;
|
|
}
|
|
if (processMessage)
|
|
{
|
|
handleMessage(message, value, data, flags);
|
|
//@todo clear if flags are not SEND messageQueue->clearMessage(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(i > 0)
|
|
{
|
|
safe_cast<ServerObject *>(getOwner())->addObjectToConcludeList();
|
|
}
|
|
|
|
m_bProcessingMessages = false;
|
|
|
|
moveToGoal();
|
|
|
|
// ----------
|
|
|
|
m_alteredSinceConclude = true;
|
|
|
|
// No reason to force an alter next frame here. Controller ensures
|
|
// we get an alter() if there are any messages in the message queue.
|
|
float alterResult = NetworkController::realAlter(time);
|
|
float defaultAlterTime = safe_cast<ServerObject *>(getOwner())->getDefaultAlterTime();
|
|
if (defaultAlterTime == AlterResult::cms_alterQuickly)
|
|
defaultAlterTime = Random::randomReal(0.25f, 0.45f);
|
|
AlterResult::incorporateExactAlterResult(alterResult, defaultAlterTime);
|
|
return alterResult;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
void ServerController::teleport(Transform const &goal, ServerObject *goalObject)
|
|
{
|
|
setGoal(goal, goalObject, true);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
void ServerController::setGoal ( Transform const & newGoal, ServerObject * goalCellObject, bool teleport )
|
|
{
|
|
m_goalTransform = newGoal;
|
|
m_goalCellObject = goalCellObject;
|
|
|
|
m_bHasGoal = true;
|
|
m_bAtGoal = false;
|
|
m_bTeleport = teleport;
|
|
|
|
// If setGoal isn't called while we're processing our message queue,
|
|
// set the creature to the goal position immediately instead of
|
|
// waiting until after all messages have been handled.
|
|
|
|
if(!m_bProcessingMessages)
|
|
{
|
|
moveToGoal();
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool changeCells(ServerObject &object, ServerObject *newCellObject)
|
|
{
|
|
bool result = false;
|
|
|
|
if (!object.isInWorld())
|
|
{
|
|
if (!newCellObject)
|
|
{
|
|
Container::ContainerErrorCode tmp = Container::CEC_Success;
|
|
result = ContainerInterface::transferItemToWorld(
|
|
object,
|
|
ContainerInterface::getTopmostContainer(object)->getTransform_o2p(),
|
|
0,
|
|
tmp);
|
|
}
|
|
else
|
|
{
|
|
Container::ContainerErrorCode tmp = Container::CEC_Success;
|
|
result = ContainerInterface::transferItemToCell(
|
|
*newCellObject,
|
|
object,
|
|
Transform::identity,
|
|
0,
|
|
tmp);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
Object * const oldCellObject = object.getAttachedTo();
|
|
|
|
if (oldCellObject == newCellObject)
|
|
return true;
|
|
|
|
// ----------
|
|
|
|
if (newCellObject == nullptr)
|
|
{
|
|
// Object was in a cell and is moving to the world, transfer from cell container to world
|
|
|
|
Transform const objectTransform = object.getTransform_o2p();
|
|
Transform const &newTransform = oldCellObject->getTransform_o2w().rotateTranslate_l2p(objectTransform);
|
|
|
|
Container::ContainerErrorCode tmp = Container::CEC_Success;
|
|
result = ContainerInterface::transferItemToWorld(object, newTransform, nullptr, tmp);
|
|
|
|
if (!result)
|
|
{
|
|
DEBUG_REPORT_LOG(true, ("Object %s (id=%s) transfer to world was denied via ContainerInterface::transferItemToWorld()\n", object.getObjectTemplateName(), object.getNetworkId().getValueString().c_str()));
|
|
|
|
// The failed transfer may have mucked up the transform, so restore it now.
|
|
object.setTransform_o2p(objectTransform);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Object is moving to a different cell
|
|
|
|
CellProperty * const pCell = ContainerInterface::getCell(*newCellObject);
|
|
|
|
DEBUG_REPORT_LOG(pCell == nullptr, ("changeCells - Received transform with parent to a non-cell object. This should only happen from the DB\n"));
|
|
|
|
if (pCell)
|
|
{
|
|
Transform objectTransform = object.getTransform_o2p();
|
|
Container::ContainerErrorCode tmp = Container::CEC_Success;
|
|
result = ContainerInterface::transferItemToCell(*newCellObject, object, nullptr, tmp);
|
|
|
|
if (!result)
|
|
{
|
|
DEBUG_REPORT_LOG(true, ("Object %s (id=%s) transfer to cell (id=%s) was denied via ContainerInterface::transferItemToCell()\n", object.getObjectTemplateName(), object.getNetworkId().getValueString().c_str(), newCellObject->getNetworkId().getValueString().c_str()));
|
|
|
|
// The failed transfer may have mucked up the transform, so restore it now.
|
|
object.setTransform_o2p(objectTransform);
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
bool ServerController::setObjectCell(ServerObject *pCellObject)
|
|
{
|
|
ServerObject * const object = NON_NULL(static_cast<ServerObject *>(getOwner()));
|
|
|
|
return changeCells(*object, pCellObject);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
void ServerController::moveToGoal( void )
|
|
{
|
|
if((m_bAtGoal) || (!m_bHasGoal))
|
|
{
|
|
return;
|
|
}
|
|
|
|
//@todo - This really needs to try and move the object to the goal first, and then
|
|
// if doing so doesn't put the object in the right cell, teleport the object to
|
|
// the correct cell. Same sort of thing as RemoteCreatureController.
|
|
ServerObject *owner = static_cast<ServerObject *>(getOwner());
|
|
if (m_goalCellObject)
|
|
{
|
|
if (!m_goalCellObject->isAuthoritative() && owner->isAuthoritative())
|
|
{
|
|
GenericValueTypeMessage<std::pair<NetworkId, NetworkId> > const rssMessage(
|
|
"RequestSameServer",
|
|
std::make_pair(
|
|
ContainerInterface::getTopmostContainer(*owner)->getNetworkId(),
|
|
ContainerInterface::getTopmostContainer(*m_goalCellObject)->getNetworkId()));
|
|
GameServer::getInstance().sendToPlanetServer(rssMessage);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!setObjectCell(m_goalCellObject))
|
|
{
|
|
m_bHasGoal = false;
|
|
m_bAtGoal = true;
|
|
m_bTeleport = false;
|
|
onMoveFailed();
|
|
return;
|
|
}
|
|
|
|
Transform oldTransform = owner->getTransform_o2p();
|
|
|
|
if(oldTransform != m_goalTransform)
|
|
{
|
|
owner->setTransform_o2p(m_goalTransform);
|
|
}
|
|
|
|
if(m_bTeleport)
|
|
{
|
|
CollisionWorld::objectWarped(getOwner());
|
|
}
|
|
|
|
m_bHasGoal = false;
|
|
m_bAtGoal = true;
|
|
m_bTeleport = false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void ServerController::handleNetUpdateTransform(const MessageQueueDataTransform& message)
|
|
{
|
|
if (!getServerOwner()->isInitialized())
|
|
{
|
|
getServerOwner()->setTransform_o2p(message.getTransform());
|
|
return;
|
|
}
|
|
|
|
setGoal( message.getTransform(), nullptr );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void ServerController::handleNetUpdateTransformWithParent(const MessageQueueDataTransformWithParent& message)
|
|
{
|
|
if (!getServerOwner()->isInitialized())
|
|
{
|
|
getServerOwner()->setTransform_o2p(message.getTransform());
|
|
return;
|
|
}
|
|
|
|
const NetworkId &cellNetworkId = message.getParent();
|
|
|
|
Object *cellObject = NetworkIdManager::getObjectById(cellNetworkId);
|
|
ServerObject * serverCellObject = safe_cast<ServerObject*>(cellObject);
|
|
|
|
// ----------
|
|
//@todo remove after we have depersisting to interiors
|
|
//We don't want to depersist into non existant cell objects
|
|
|
|
if(!cellObject)
|
|
{
|
|
WARNING_STRICT_FATAL(true, ("WARNING: db or authoritative player says to depersist %s into a cell %s but we cannot because cell does not exist.", getOwner()->getNetworkId().getValueString().c_str(), cellNetworkId.getValueString().c_str()));
|
|
|
|
//@todo big demo hack. If depersisting into a cell, set the transform to start lcoation
|
|
Transform start = Transform::identity;
|
|
start.setPosition_p(ConfigServerGame::getStartingPosition());
|
|
setGoal( start, nullptr );
|
|
|
|
return;
|
|
}
|
|
setGoal( message.getTransform(), serverCellObject );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void ServerController::handleMessage (const int message, const float value, const MessageQueue::Data* const data, const uint32 flags)
|
|
{
|
|
ServerObject* const owner = static_cast<ServerObject*>(getOwner());
|
|
|
|
switch(message)
|
|
{
|
|
case CM_spatialChatSend:
|
|
{
|
|
const MessageQueueSpatialChat * const spatialChat = dynamic_cast<const MessageQueueSpatialChat *>(data);
|
|
NOT_NULL (spatialChat);
|
|
|
|
if (spatialChat->getSourceId () != getOwner ()->getNetworkId ())
|
|
{
|
|
WARNING (true, ("Received a CM_spatialChatSend message on object %s from object %s",
|
|
owner->getNetworkId ().getValueString ().c_str (), spatialChat->getSourceId ().getValueString ().c_str ()));
|
|
break;
|
|
}
|
|
|
|
owner->speakText (*spatialChat);
|
|
}
|
|
break;
|
|
|
|
case CM_spatialChatReceive:
|
|
{
|
|
const MessageQueueSpatialChat * const spatialChat = dynamic_cast<const MessageQueueSpatialChat *>(data);
|
|
NOT_NULL (spatialChat);
|
|
ServerObject * const sourceObject = safe_cast<ServerObject *>(NetworkIdManager::getObjectById(spatialChat->getSourceId()));
|
|
if (sourceObject)
|
|
owner->hearText(*sourceObject, *spatialChat, ChatLogManager::getNextMessageIndex());
|
|
}
|
|
break;
|
|
|
|
case CM_socialSend:
|
|
{
|
|
const MessageQueueSocial * const socialMsg = NON_NULL (dynamic_cast<const MessageQueueSocial *>(data));
|
|
|
|
if (socialMsg->getSourceId () != owner->getNetworkId ())
|
|
{
|
|
WARNING (true, ("Received a CM_spatialChatSend message on object %s from object %s",
|
|
owner->getNetworkId ().getValueString ().c_str (), socialMsg->getSourceId ().getValueString ().c_str ()));
|
|
break;
|
|
}
|
|
|
|
owner->performSocial (*socialMsg);
|
|
}
|
|
break;
|
|
|
|
case CM_socialReceive:
|
|
{
|
|
const MessageQueueSocial * const socialMsg = NON_NULL (dynamic_cast<const MessageQueueSocial *>(data));
|
|
owner->seeSocial (*socialMsg);
|
|
}
|
|
break;
|
|
|
|
case CM_scriptTrigger:
|
|
{
|
|
const MessageQueueScriptTrigger * const triggerMessage = dynamic_cast<const MessageQueueScriptTrigger *>(data);
|
|
if(triggerMessage)
|
|
{
|
|
ServerObject * object = getServerOwner();
|
|
if(object)
|
|
{
|
|
GameScriptObject * scriptObject = object->getScriptObject();
|
|
if(scriptObject)
|
|
{
|
|
const Archive::ByteStream & paramData = triggerMessage->getScriptParamData();
|
|
const Scripting::TrigId trigId = static_cast<const Scripting::TrigId>(triggerMessage->getTriggerId());
|
|
ScriptParams p;
|
|
Archive::ReadIterator ri = paramData.begin();
|
|
Archive::get(ri, p);
|
|
scriptObject->trigAllScripts(trigId, p);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
break;
|
|
case CM_attachScript:
|
|
{
|
|
if(data)
|
|
{
|
|
const MessageQueueString * const msg = static_cast<const MessageQueueString *>(data);
|
|
owner->getScriptObject()->attachScript(msg->getString(), true);
|
|
}
|
|
}
|
|
break;
|
|
case CM_detachScript:
|
|
{
|
|
if(data)
|
|
{
|
|
const MessageQueueString * const msg = static_cast<const MessageQueueString *>(data);
|
|
owner->getScriptObject()->detachScript(msg->getString());
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CM_scriptTransferMoney:
|
|
{
|
|
const MessageQueueScriptTransferMoney * const msg = safe_cast<const MessageQueueScriptTransferMoney *>(data);
|
|
if(msg)
|
|
{
|
|
ServerObject * owner = safe_cast<ServerObject *>(getOwner());
|
|
if(owner)
|
|
switch (msg->getTypeId())
|
|
{
|
|
case MessageQueueScriptTransferMoney::TT_bankTransfer:
|
|
owner->scriptTransferBankCreditsTo(msg->getTarget(), msg->getAmount(), msg->getReplyTo(),
|
|
msg->getSuccessCallback(), msg->getFailCallback(), msg->getPackedDictionary());
|
|
break;
|
|
case MessageQueueScriptTransferMoney::TT_cashTransfer:
|
|
owner->scriptTransferCashTo(msg->getTarget(), msg->getAmount(), msg->getReplyTo(),
|
|
msg->getSuccessCallback(), msg->getFailCallback(), msg->getPackedDictionary());
|
|
break;
|
|
case MessageQueueScriptTransferMoney::TT_bankWithdrawal:
|
|
owner->scriptWithdrawCashFromBank(msg->getAmount(), msg->getReplyTo(),
|
|
msg->getSuccessCallback(), msg->getFailCallback(), msg->getPackedDictionary());
|
|
break;
|
|
case MessageQueueScriptTransferMoney::TT_bankDeposit:
|
|
owner->scriptDepositCashToBank(msg->getAmount(), msg->getReplyTo(),
|
|
msg->getSuccessCallback(), msg->getFailCallback(), msg->getPackedDictionary());
|
|
break;
|
|
case MessageQueueScriptTransferMoney::TT_bankTransferToNamedAccount:
|
|
owner->scriptTransferBankCreditsTo(msg->getNamedAccount(), msg->getAmount(), msg->getReplyTo(),
|
|
msg->getSuccessCallback(), msg->getFailCallback(), msg->getPackedDictionary());
|
|
break;
|
|
case MessageQueueScriptTransferMoney::TT_bankTransferFromNamedAccount:
|
|
owner->scriptTransferBankCreditsFrom(msg->getNamedAccount(), msg->getAmount(), msg->getReplyTo(),
|
|
msg->getSuccessCallback(), msg->getFailCallback(), msg->getPackedDictionary());
|
|
break;
|
|
default:
|
|
DEBUG_FATAL(true,("MessageQueueScriptTransferMoney transaction type %i was not recognized. Object is %s",
|
|
msg->getTypeId(), owner->getNetworkId().getValueString().c_str()));
|
|
}
|
|
}
|
|
}
|
|
case CM_persistObject:
|
|
{
|
|
owner->persist();
|
|
}
|
|
break;
|
|
case CM_setCacheVersion:
|
|
{
|
|
const MessageQueueGenericValueType<int> * const msg = safe_cast<const MessageQueueGenericValueType<int> *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setCacheVersion(msg->getValue());
|
|
}
|
|
}
|
|
break;
|
|
case CM_transferAuthority:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<uint32, bool> > * const msg = safe_cast<const MessageQueueGenericValueType<std::pair<uint32, bool> > *>(data);
|
|
if(msg)
|
|
{
|
|
owner->transferAuthority(msg->getValue().first, msg->getValue().second, false, false);
|
|
}
|
|
}
|
|
break;
|
|
case CM_setObjectName:
|
|
{
|
|
const MessageQueueGenericValueType<Unicode::String> * const msg = safe_cast<const MessageQueueGenericValueType<Unicode::String> *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setObjectName(msg->getValue());
|
|
}
|
|
}
|
|
break;
|
|
case CM_setObjectNameStringId:
|
|
{
|
|
const MessageQueueGenericValueType<StringId> * const msg = safe_cast<const MessageQueueGenericValueType<StringId> *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setObjectNameStringId(msg->getValue());
|
|
}
|
|
}
|
|
break;
|
|
case CM_teleportObject:
|
|
{
|
|
const MessageQueueTeleportObject * const msg = safe_cast<const MessageQueueTeleportObject *>(data);
|
|
if(msg)
|
|
{
|
|
owner->teleportObject(msg->getPosition_w(), msg->getTargetContainerId(), msg->getTargetCellName(), msg->getPosition_p(), msg->getScriptCallback());
|
|
}
|
|
}
|
|
break;
|
|
case CM_updatePositionOnPlanetServer:
|
|
{
|
|
const MessageQueueGenericValueType<bool> * const msg = safe_cast<const MessageQueueGenericValueType<bool> *>(data);
|
|
if(msg)
|
|
{
|
|
owner->updatePositionOnPlanetServer(msg->getValue());
|
|
}
|
|
}
|
|
break;
|
|
case CM_setPlayerControlled:
|
|
{
|
|
const MessageQueueGenericValueType<bool> * const msg = safe_cast<const MessageQueueGenericValueType<bool> *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setPlayerControlled(msg->getValue());
|
|
}
|
|
}
|
|
break;
|
|
case CM_customize:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, int> > * const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, int> > *>(data);
|
|
if(msg)
|
|
{
|
|
owner->customize(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
}
|
|
break;
|
|
case CM_permanentlyDestroy:
|
|
{
|
|
const MessageQueueGenericValueType<int> * const msg = safe_cast<const MessageQueueGenericValueType<int> *>(data);
|
|
if (msg)
|
|
{
|
|
owner->permanentlyDestroy(msg->getValue());
|
|
}
|
|
}
|
|
break;
|
|
case CM_setIntDynamicVariable:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, int> >* const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, int> > *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
}
|
|
break;
|
|
case CM_setIntArrayDynamicVariable:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, std::vector<int> > >* const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, std::vector<int> > > *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
}
|
|
break;
|
|
case CM_setFloatDynamicVariable:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, float> >* const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, float> > *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
}
|
|
break;
|
|
case CM_setFloatArrayDynamicVariable:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, std::vector<float> > >* const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, std::vector<float> > > *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
}
|
|
break;
|
|
case CM_setStringDynamicVariable:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, Unicode::String> >* const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, Unicode::String> > *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
}
|
|
break;
|
|
case CM_setStringArrayDynamicVariable:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, std::vector<Unicode::String> > >* const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, std::vector<Unicode::String> > > *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
}
|
|
break;
|
|
case CM_setObjIdDynamicVariable:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, NetworkId> >* const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, NetworkId> > *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
}
|
|
break;
|
|
case CM_setObjIdArrayDynamicVariable:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, std::vector<NetworkId> > >* const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, std::vector<NetworkId> > > *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
}
|
|
break;
|
|
case CM_setLocationDynamicVariable:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, DynamicVariableLocationData> >* const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, DynamicVariableLocationData> > *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
}
|
|
break;
|
|
case CM_setLocationArrayDynamicVariable:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, std::vector<DynamicVariableLocationData> > >* const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, std::vector<DynamicVariableLocationData> > > *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
}
|
|
break;
|
|
case CM_setStringIdDynamicVariable:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, StringId> >* const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, StringId> > *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
}
|
|
break;
|
|
case CM_setStringIdArrayDynamicVariable:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, std::vector<StringId> > >* const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, std::vector<StringId> > > *>(data);
|
|
if(msg)
|
|
{
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
}
|
|
break;
|
|
case CM_setTransformDynamicVariable:
|
|
{
|
|
MessageQueueGenericValueType<std::pair<std::string, Transform> > const * msg = safe_cast<MessageQueueGenericValueType<std::pair<std::string, Transform> > const *>(data);
|
|
if (msg)
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
break;
|
|
case CM_setTransformArrayDynamicVariable:
|
|
{
|
|
MessageQueueGenericValueType<std::pair<std::string, std::vector<Transform> > > const * msg = safe_cast<MessageQueueGenericValueType<std::pair<std::string, std::vector<Transform> > > const *>(data);
|
|
if (msg)
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
break;
|
|
case CM_setVectorDynamicVariable:
|
|
{
|
|
MessageQueueGenericValueType<std::pair<std::string, Vector> > const * msg = safe_cast<MessageQueueGenericValueType<std::pair<std::string, Vector> > const *>(data);
|
|
if (msg)
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
break;
|
|
case CM_setVectorArrayDynamicVariable:
|
|
{
|
|
MessageQueueGenericValueType<std::pair<std::string, std::vector<Vector> > > const * msg = safe_cast<MessageQueueGenericValueType<std::pair<std::string, std::vector<Vector> > > const *>(data);
|
|
if (msg)
|
|
owner->setObjVarItem(msg->getValue().first, msg->getValue().second);
|
|
}
|
|
break;
|
|
case CM_copyDynamicVariable:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, NetworkId> > * const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, NetworkId> > *>(data);
|
|
if(msg)
|
|
{
|
|
ServerObject* fromObject = dynamic_cast<ServerObject*>(NetworkIdManager::getObjectById(msg->getValue().second));
|
|
if(fromObject)
|
|
{
|
|
owner->copyObjVars(msg->getValue().first, *fromObject, msg->getValue().first);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case CM_copyDynamicVariableToSubList:
|
|
{
|
|
const MessageQueueGenericValueType<std::pair<std::string, std::pair<std::string, NetworkId> > > * const msg = safe_cast<const MessageQueueGenericValueType<std::pair<std::string, std::pair<std::string, NetworkId> > > *>(data);
|
|
if(msg)
|
|
{
|
|
ServerObject* fromObject = dynamic_cast<ServerObject*>(NetworkIdManager::getObjectById(msg->getValue().second.second));
|
|
if(fromObject)
|
|
{
|
|
owner->copyObjVars(msg->getValue().first, *fromObject, msg->getValue().second.first);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case CM_addNestedObjVarList:
|
|
{
|
|
const MessageQueueGenericValueType<std::string>* const msg = safe_cast<const MessageQueueGenericValueType<std::string> *>(data);
|
|
if(msg)
|
|
{
|
|
//owner->addNestedObjVarList(msg->getValue()); // This operation is now a no-op
|
|
}
|
|
}
|
|
break;
|
|
case CM_removeObjVarItem:
|
|
{
|
|
const MessageQueueGenericValueType<std::string>* const msg = safe_cast<const MessageQueueGenericValueType<std::string> *>(data);
|
|
if(msg)
|
|
{
|
|
owner->removeObjVarItem(msg->getValue());
|
|
}
|
|
}
|
|
break;
|
|
case CM_eraseObjVarListEntries:
|
|
{
|
|
const MessageQueueGenericValueType<std::string>* const msg = safe_cast<const MessageQueueGenericValueType<std::string> *>(data);
|
|
if(msg)
|
|
{
|
|
owner->eraseObjVarListEntries(msg->getValue());
|
|
}
|
|
}
|
|
break;
|
|
case CM_setObjVarItemVar:
|
|
{
|
|
}
|
|
break;
|
|
|
|
case CM_disconnect:
|
|
owner->disconnect();
|
|
break;
|
|
|
|
case CM_updateObserversCount:
|
|
{
|
|
const MessageQueueGenericValueType<int>* const msg = safe_cast<const MessageQueueGenericValueType<int> *>(data);
|
|
if(msg)
|
|
{
|
|
owner->updateObserversCount(msg->getValue());
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CM_cancelMessageTo:
|
|
{
|
|
const MessageQueueGenericValueType<std::string>* const msg = safe_cast<const MessageQueueGenericValueType<std::string> *>(data);
|
|
if(msg)
|
|
{
|
|
NetworkId const possibleNetworkId = NetworkId(msg->getValue());
|
|
if (possibleNetworkId.getValueString() == msg->getValue())
|
|
owner->cancelMessageToByMessageId(possibleNetworkId);
|
|
else
|
|
owner->cancelMessageTo(msg->getValue());
|
|
}
|
|
}
|
|
break;
|
|
|
|
case CM_combatSpam:
|
|
{
|
|
const MessageQueueCombatSpam * const msg = safe_cast<const MessageQueueCombatSpam *>(data);
|
|
if (msg)
|
|
{
|
|
owner->seeCombatSpam(*msg);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
NetworkController::handleMessage(message, value, data, flags);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void ServerController::conclude()
|
|
{
|
|
PROFILER_AUTO_BLOCK_DEFINE("ServerController::conclude");
|
|
|
|
{
|
|
PROFILER_AUTO_BLOCK_DEFINE("updateTransform");
|
|
updateTransform();
|
|
}
|
|
|
|
ServerObject * const netObject = NON_NULL(getOwner())->asServerObject();
|
|
netObject->sendDeltas();
|
|
|
|
if (m_alteredSinceConclude)
|
|
{
|
|
PROFILER_AUTO_BLOCK_DEFINE("NetworkController::conclude");
|
|
NetworkController::conclude();
|
|
m_alteredSinceConclude = false;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
void ServerController::onClientReady()
|
|
{
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
void ServerController::onClientLost()
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void ServerController::onAppendMessage()
|
|
{
|
|
ServerObject *owner = static_cast<ServerObject *>(getOwner());
|
|
if(owner)
|
|
owner->addObjectToConcludeList();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Send a controller message to wherever it is supposed to go.
|
|
*
|
|
* @param msg the message to send
|
|
*/
|
|
void ServerController::sendControllerMessage(ObjControllerMessage const &msg)
|
|
{
|
|
uint32 const destFlags = (msg.getFlags() & GameControllerMessageFlags::DESTINATIONS);
|
|
bool const reliable = ((msg.getFlags() & GameControllerMessageFlags::RELIABLE) > 0);
|
|
|
|
ServerObject * const owner = static_cast<ServerObject *>(getOwner());
|
|
|
|
// Note: in the case where we are sending to both auth and proxy clients,
|
|
// sendToAuthClients is NOT set, because the sendToProxyClients handling
|
|
// also covers the auth client, and can do so potentially with fewer messages.
|
|
|
|
bool const sendToAuthClients = ( owner->isAuthoritative()
|
|
&& (destFlags & GameControllerMessageFlags::DEST_AUTH_CLIENT)
|
|
&& !(destFlags & GameControllerMessageFlags::DEST_PROXY_CLIENT));
|
|
bool const sendToProxyClients = (destFlags & GameControllerMessageFlags::DEST_PROXY_CLIENT);
|
|
bool const sendToAuthServer = ( !owner->isAuthoritative()
|
|
&& ( (destFlags & GameControllerMessageFlags::DEST_AUTH_SERVER)
|
|
|| ( (destFlags & GameControllerMessageFlags::DEST_AUTH_CLIENT)
|
|
&& !(destFlags & GameControllerMessageFlags::DEST_PROXY_CLIENT))));
|
|
bool const sendToProxyServers = ( owner->isAuthoritative()
|
|
&& (destFlags & (GameControllerMessageFlags::DEST_PROXY_CLIENT|GameControllerMessageFlags::DEST_PROXY_SERVER)));
|
|
|
|
if (sendToAuthClients)
|
|
{
|
|
std::set<Client const *> authClients;
|
|
owner->getAuthClients(authClients);
|
|
|
|
// need to do special handling for CM_combatSpam controller
|
|
// message to determine if the client should get the message
|
|
bool isCombatSpamMessage = false;
|
|
NetworkId combatSpamAttacker, combatSpamDefender;
|
|
Vector combatSpamAttackerPosition_w, combatSpamDefenderPosition_w;
|
|
if (!authClients.empty())
|
|
{
|
|
if (msg.getMessage() == CM_combatSpam)
|
|
{
|
|
MessageQueueCombatSpam const * mqcs = static_cast<MessageQueueCombatSpam const *>(msg.getData());
|
|
|
|
if (mqcs)
|
|
{
|
|
isCombatSpamMessage = true;
|
|
combatSpamAttacker = mqcs->m_attacker;
|
|
combatSpamAttackerPosition_w = mqcs->m_attackerPosition_w;
|
|
combatSpamDefender = mqcs->m_defender;
|
|
combatSpamDefenderPosition_w = mqcs->m_defenderPosition_w;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (std::set<Client const *>::const_iterator i = authClients.begin(); i != authClients.end(); ++i)
|
|
{
|
|
if (isCombatSpamMessage && !(*i)->shouldReceiveCombatSpam(combatSpamAttacker, combatSpamAttackerPosition_w, combatSpamDefender, combatSpamDefenderPosition_w))
|
|
continue;
|
|
|
|
(*i)->send(msg, reliable);
|
|
}
|
|
}
|
|
|
|
if (sendToProxyClients)
|
|
{
|
|
// NOTE: This will not behave correctly if a DEST_PROXY_CLIENT message is sent from a non-authoritative object!
|
|
// Currently we do not need this behavior, but if we do at some point, this will need to be changed.
|
|
bool const sendToAuthoritativeClient = (destFlags & GameControllerMessageFlags::DEST_AUTH_CLIENT) != 0;
|
|
owner->sendToClientsInUpdateRange(msg, reliable, sendToAuthoritativeClient);
|
|
}
|
|
|
|
if (sendToAuthServer || sendToProxyServers)
|
|
{
|
|
std::vector<uint32> serverList;
|
|
if (sendToAuthServer)
|
|
serverList.push_back(owner->getAuthServerProcessId());
|
|
if (sendToProxyServers)
|
|
{
|
|
ProxyList const &proxyList = owner->getExposedProxyList();
|
|
for (ProxyList::const_iterator i = proxyList.begin(); i != proxyList.end(); ++i)
|
|
serverList.push_back(*i);
|
|
}
|
|
if (!serverList.empty())
|
|
{
|
|
ServerMessageForwarding::begin(serverList);
|
|
|
|
ServerMessageForwarding::send(msg);
|
|
|
|
ServerMessageForwarding::end();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
/**
|
|
* Sets an object's name.
|
|
*
|
|
* @param name the new name
|
|
*/
|
|
void ServerController::setObjectName(const Unicode::String &name)
|
|
{
|
|
ServerObject* owner = static_cast<ServerObject *>(getOwner());
|
|
|
|
if (!owner->isAuthoritative())
|
|
{
|
|
// @todo: what to do here
|
|
DEBUG_WARNING(true, ("setObjectName on non-authoritative object!\n"));
|
|
return;
|
|
}
|
|
|
|
owner->setObjectName(name);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void ServerController::updateTransform()
|
|
{
|
|
// Note: only the auth server sends updates from here. Non-creatures use DEST_PROXY_CLIENT controller messages
|
|
// to get the messages to all clients, and CreatureControllers receiving transforms from other servers forward
|
|
// to local clients, since creatures don't use controller messages to the clients.
|
|
ServerObject * const owner = static_cast<ServerObject *>(getOwner());
|
|
|
|
if (!owner->getTransformChanged() && m_oldVelocity == getCurrentVelocity())
|
|
return;
|
|
|
|
DEBUG_FATAL(owner->getCellProperty() && !owner->getKill(), ("A cell object is trying to update its transform! Cells aren't EVER supposed to do that!"));
|
|
|
|
if (owner->getClient())
|
|
owner->getClient()->resetIdleTime();
|
|
|
|
owner->setTransformChanged(false);
|
|
m_oldVelocity = getCurrentVelocity();
|
|
|
|
if (!owner->isAuthoritative())
|
|
return;
|
|
|
|
// bail out if we're not in the world --- no reason to send updates.
|
|
if (!owner->isInWorld())
|
|
return;
|
|
|
|
synchronizeTransform();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|
|
|
|
void ServerController::synchronizeTransform()
|
|
{
|
|
ServerObject * const owner = safe_cast<ServerObject *>(getOwner());
|
|
NOT_NULL(owner);
|
|
|
|
m_moveSequenceNumber = owner->getAndIncrementMoveSequenceNumber();
|
|
|
|
Transform const & tr = getOwner()->getTransform_o2p();
|
|
|
|
bool isCreature = owner->getObjectTemplate()->getId() == ServerCreatureObjectTemplate::ServerCreatureObjectTemplate_tag;
|
|
ServerObject *attachedTo = safe_cast<ServerObject*>(owner->getAttachedTo());
|
|
|
|
int flags = GameControllerMessageFlags::SEND | GameControllerMessageFlags::DEST_PROXY_SERVER;
|
|
|
|
if (m_sendReliableTransformThisFrame || owner->alwaysSendReliableTransform())
|
|
{
|
|
flags |= GameControllerMessageFlags::RELIABLE;
|
|
m_sendReliableTransformThisFrame = false;
|
|
}
|
|
|
|
// If we're contained by something other than what we're attached to, then transforms are
|
|
// not relevant to clients since they will be pulling their positions purely from their parent.
|
|
bool sendPositionUpdateToClients = ContainerInterface::getContainedByObject(*owner) == attachedTo;
|
|
|
|
// We only send the controller message to clients if the position update is useful to clients
|
|
// and it is also not a creature, as creatures have it sent to clients in a different message.
|
|
if (sendPositionUpdateToClients && !isCreature)
|
|
flags |= GameControllerMessageFlags::DEST_PROXY_CLIENT;
|
|
|
|
float lookAtYaw = 0.f;
|
|
bool useLookAtYaw = false;
|
|
if(isCreature)
|
|
{
|
|
CreatureObject *creatureObject = safe_cast<CreatureObject *>(owner);
|
|
lookAtYaw = creatureObject->getLookAtYaw();
|
|
useLookAtYaw = creatureObject->getUseLookAtYaw();
|
|
}
|
|
if (attachedTo)
|
|
{
|
|
MessageQueueDataTransformWithParent message(0, m_moveSequenceNumber, attachedTo->getNetworkId(), tr, getCurrentVelocity ().magnitude (), lookAtYaw, useLookAtYaw);
|
|
|
|
ObjControllerMessage c(owner->getNetworkId(),
|
|
CM_netUpdateTransformWithParent,
|
|
0.0f,
|
|
flags,
|
|
&message);
|
|
|
|
sendControllerMessage(c);
|
|
if (sendPositionUpdateToClients && isCreature)
|
|
{
|
|
//Special smaller packet for updating creature movement.
|
|
UpdateTransformWithParentMessage utm(owner->getNetworkId(), m_moveSequenceNumber, attachedTo->getNetworkId(), tr, static_cast<int8>(getCurrentVelocity().magnitude()), lookAtYaw, useLookAtYaw);
|
|
owner->sendToClientsInUpdateRange(utm, flags & GameControllerMessageFlags::RELIABLE, false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MessageQueueDataTransform message(0, m_moveSequenceNumber, tr, getCurrentVelocity ().magnitude (), lookAtYaw, useLookAtYaw);
|
|
|
|
ObjControllerMessage c(owner->getNetworkId(),
|
|
CM_netUpdateTransform,
|
|
0.0f,
|
|
flags,
|
|
&message);
|
|
|
|
sendControllerMessage(c);
|
|
if (sendPositionUpdateToClients && isCreature)
|
|
{
|
|
//Special smaller packet for updating creature movement.
|
|
UpdateTransformMessage utm(owner->getNetworkId(), m_moveSequenceNumber, tr, static_cast<int8>(getCurrentVelocity().magnitude()), lookAtYaw, useLookAtYaw);
|
|
owner->sendToClientsInUpdateRange(utm, flags & GameControllerMessageFlags::RELIABLE, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
int ServerController::getMoveSequenceNumber() const
|
|
{
|
|
return m_moveSequenceNumber;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
void ServerController::onMoveFailed()
|
|
{
|
|
}
|
|
|
|
//-----------------------------------------------------------------------
|