void ScriptSupport::setPlayerPosition(uint64 playerId, uint64 cellId, float posX, float posY, float posZ) { PlayerObject* player = dynamic_cast<PlayerObject*>(gWorldManager->getObjectById(playerId)); if (player) { // Anh_Math::Quaternion direction; glm::vec3 position; position.x = posX; position.y = posY; position.z = posZ; player->mPosition = position; player->setParentId(cellId); if (cellId) { // We are inside a cell. gMessageLib->sendDataTransformWithParent053(player); gMessageLib->sendUpdateTransformMessageWithParent(player); } else { gMessageLib->sendDataTransform053(player); gMessageLib->sendUpdateTransformMessage(player); //If our player is mounted move his mount aswell if(player->checkIfMounted() && player->getMount()) { player->getMount()->mPosition = position; gMessageLib->sendDataTransform053(player->getMount()); gMessageLib->sendUpdateTransformMessage(player->getMount()); } } } }
void ObjectController::_handleDismount(uint64 targetId,Message* message,ObjectControllerCmdProperties* cmdProperties) { // The very idea with using ID's instead of object refs are that you can TEST them without using the object itself. // And some parameter validation... PlayerObject* player = dynamic_cast<PlayerObject*>(mObject); if (player && player->getMount() && (player->getParentId() == 0)) { if (player->checkIfMounted()) { // verify its player's mount MountObject* pet = NULL; if (targetId == 0) { // No object targeted, assume the one we are riding. - what else should we dismount ??? pet = player->getMount(); } else { pet = dynamic_cast<MountObject*>(gWorldManager->getObjectById(targetId)); } if (pet && (pet->owner() == player->getId())) { // get the pets controller for a swoop its the vehicle if(VehicleController* vehicle = dynamic_cast<VehicleController*>(gWorldManager->getObjectById(pet->controller()))) { vehicle->DismountPlayer(); } } } else { gMessageLib->SendSystemMessage(L"You are not mounted to perform this action.", player); } } }
void ObjectController::_handleMount(uint64 targetId,Message* message,ObjectControllerCmdProperties* cmdProperties) { // The very idea with using ID's instead of object refs are that you can TEST them without using the object itself. // And some parameter validation... if (targetId == 0) { DLOG(info) << "ObjectController::_handleMount : Cannot find vehicle ID :("; return; } PlayerObject* player = dynamic_cast<PlayerObject*>(mObject); if (player && player->getMount() && (player->getParentId() == 0)) { // Do we have a valid target? if (!player->checkIfMounted()) { // verify its player's mount MountObject* pet = dynamic_cast<MountObject*>(gWorldManager->getObjectById(targetId)); if (pet && (pet->owner() == player->getId())) { // get the mount Vehicle object by the id (Creature object id - 1 ) if(VehicleController* vehicle = dynamic_cast<VehicleController*>(gWorldManager->getObjectById(pet->controller()))) { //The /mount command can work up to 32m on live if(glm::distance(vehicle->body()->mPosition, player->mPosition) <= 32) { //change locomotion vehicle->MountPlayer(); } else { gMessageLib->SendSystemMessage(L"Your target is too far away to mount.", player); } } else { DLOG(info) << "ObjectController::_handleMount : Cannot find vehicle"; } } } else { gMessageLib->SendSystemMessage(L"You cannot mount this because you are already mounted.", player); } } }
//============================================================================= // // incap // void CreatureObject::incap() { // sanity check if (isIncapacitated() || isDead()) { return; } if (this->getType() == ObjType_Player) { // gLogger->logMsgF("Player incapped, mIncapCount = %u.", MSG_NORMAL, mIncapCount); // first incap, update the initial time uint64 localTime = Anh_Utils::Clock::getSingleton()->getLocalTime(); if(!mIncapCount) { mFirstIncapTime = localTime; } // reset the counter if the reset time has passed else if(mIncapCount != 0 && (localTime - mFirstIncapTime) >= gWorldConfig->getIncapResetTime() * 1000) { // gLogger->logMsgF("Time since first incap = %"PRIu64"", MSG_NORMAL, localTime - mFirstIncapTime); // gLogger->logMsgF("Resetting mFirstIncapTime", MSG_NORMAL); mIncapCount = 0; mFirstIncapTime = localTime; } /* if (mIncapCount != 0) { gLogger->logMsgF("Time since first incap = %"PRIu64"", MSG_NORMAL, localTime - mFirstIncapTime); } */ PlayerObject* player = dynamic_cast<PlayerObject*>(this); if (player) { player->disableAutoAttack(); } //See if our player is mounted -- if so dismount him if(player->checkIfMounted()) { //Get the player's mount if(Vehicle* vehicle = dynamic_cast<Vehicle*>(gWorldManager->getObjectById(player->getMount()->getPetController()))) { //Now dismount vehicle->dismountPlayer(); } } // advance incaps counter if(++mIncapCount < gWorldConfig->getConfiguration("Player_Incapacitation",3)) { // gLogger->logMsgF("Player incapped, mIncapCount set to = %u, setting timer..", MSG_NORMAL, mIncapCount); // update the posture mPosture = CreaturePosture_Incapacitated; // send timer updates mCurrentIncapTime = gWorldConfig->getBaseIncapTime() * 1000; gMessageLib->sendIncapTimerUpdate(this); // schedule recovery event mObjectController.addEvent(new IncapRecoveryEvent(),mCurrentIncapTime); // reset states mState = 0; // reset ham regeneration mHam.updateRegenRates(); gWorldManager->removeCreatureHamToProcess(mHam.getTaskId()); mHam.setTaskId(0); updateMovementProperties(); gMessageLib->sendPostureAndStateUpdate(this); if(PlayerObject* player = dynamic_cast<PlayerObject*>(this)) { gMessageLib->sendUpdateMovementProperties(player); gMessageLib->sendSelfPostureUpdate(player); } } // we hit the max -> death else { // gLogger->logMsgF("Player died.", MSG_NORMAL); die(); } } else if (this->getType() == ObjType_Creature) // A Creature. { die(); } else { gLogger->logMsgF("CreatureObject::incap Incapped unsupported type %u\n", MSG_NORMAL, this->getType()); } }
bool ObjectController::_updateInRangeObjectsOutside() { PlayerObject* player = dynamic_cast<PlayerObject*>(mObject); // We may wan't to limit the amount of messages sent in one session. uint32 updatedObjects = 0; const uint32 objectSendLimit = 50; while ((mObjectSetIt != mInRangeObjects.end()) && (updatedObjects < objectSendLimit)) { //BEWARE Object is at this time possibly not valid anymore! //this actually causes a lot of crashes!!!! Object* object = dynamic_cast<Object*>(*mObjectSetIt); // Just simplified the code a little. Good find Schmunzel. // only add it if its also outside // see if its already observed, if yes, just send a position update out, if its a player if ((object) && (!player->checkKnownObjects(object))) { // send the according create for the type of object #if defined(_MSC_VER) if (object->getId() > 0x0000000100000000) #else if (object->getId() > 0x0000000100000000LLU) #endif { if (object->getPrivateOwner()) { if (object->isOwnedBy(player)) { gMessageLib->sendCreateObject(object,player); player->addKnownObjectSafe(object); object->addKnownObjectSafe(player); //If player has a mount make sure add to its known objects //but is the mount even near us ??? // does this even matter ? if(player->checkIfMountCalled() && player->getMount()) { if(player->getMount()->getId() != object->getId()) { player->getMount()->addKnownObjectSafe(object); object->addKnownObjectSafe(player->getMount()); } } updatedObjects++; } } else { //if(!player->checkKnownObjects(object)) //{ gMessageLib->sendCreateObject(object,player); player->addKnownObjectSafe(object); object->addKnownObjectSafe(player); //If player has a mount make sure add to its known objects if(player->checkIfMountCalled() && player->getMount()) { if(player->getMount()->getId() != object->getId()) { player->getMount()->addKnownObjectSafe(object); object->addKnownObjectSafe(player->getMount()); } } //} updatedObjects++; } } } ++mObjectSetIt; } return (mObjectSetIt == mInRangeObjects.end()); }
bool ObjectController::_destroyOutOfRangeObjects(ObjectSet *inRangeObjects) { //TODO: when a container gets out of range //we need to destroy the children, too!!!!!!! // iterate our knowns PlayerObject* player = dynamic_cast<PlayerObject*>(mObject); ObjectSet* knownObjects = player->getKnownObjects(); ObjectSet::iterator objIt = knownObjects->begin(); PlayerObjectSet* knownPlayers = player->getKnownPlayers(); PlayerObjectSet::iterator playerIt = knownPlayers->begin(); const uint32 objectDestroyLimit = 5000; // update players while(playerIt != knownPlayers->end()) { PlayerObject* playerObject = (*playerIt); // if its not in the current inrange queries result, destroy it if(inRangeObjects->find(playerObject) == inRangeObjects->end()) { // send a destroy to us gMessageLib->sendDestroyObject(playerObject->getId(),player); //If player is mounted destroy his mount too if(playerObject->checkIfMounted() && playerObject->getMount()) { gMessageLib->sendDestroyObject(playerObject->getMount()->getId(),player); player->removeKnownObject(playerObject->getMount()); playerObject->getMount()->removeKnownObject(player); } //send a destroy to him gMessageLib->sendDestroyObject(player->getId(),playerObject); //If we're mounted destroy our mount too if(player->checkIfMounted() && playerObject->getMount()) { gMessageLib->sendDestroyObject(player->getMount()->getId(),playerObject); playerObject->removeKnownObject(player->getMount()); player->getMount()->removeKnownObject(playerObject); } // we don't know each other anymore knownPlayers->erase(playerIt++); playerObject->removeKnownObject(player); continue; } ++playerIt; } // We may want to limit the amount of messages sent in one session. uint32 messageCount = 0; // update objects while(objIt != knownObjects->end()) { Object* object = (*objIt); // if its not in the current inrange queries result, destroy it if(inRangeObjects->find(object) == inRangeObjects->end()) { if(object->getType() == ObjType_Structure) { if(FactoryObject* factory = dynamic_cast<FactoryObject*>(object)) { //delete the hoppers contents TangibleObject* hopper = dynamic_cast<TangibleObject*>(gWorldManager->getObjectById(factory->getIngredientHopper())); if(hopper) { ObjectIDList* ol = hopper->getObjects(); ObjectIDList::iterator it = ol->begin(); while(it != ol->end()) { TangibleObject* tO = dynamic_cast<TangibleObject*>(gWorldManager->getObjectById((*it))); if(!tO) { assert(false && "ObjectController::_destroyOutOfRangeObjects WorldManager unable to find TangibleObject instance"); } tO->removeKnownObject(player); player->removeKnownObject(tO); gMessageLib->sendDestroyObject(tO->getId(),player); it++; } hopper->removeKnownObject(player); player->removeKnownObject(hopper); gMessageLib->sendDestroyObject(hopper->getId(),player); } hopper = dynamic_cast<TangibleObject*>(gWorldManager->getObjectById(factory->getOutputHopper())); if(hopper) { ObjectIDList* ol = hopper->getObjects(); ObjectIDList::iterator it = ol->begin(); while(it != ol->end()) { TangibleObject* tO = dynamic_cast<TangibleObject*>(gWorldManager->getObjectById((*it))); if(!tO) { assert(false && "ObjectController::_destroyOutOfRangeObjects WorldManager unable to find TangibleObject instance"); } //PlayerObject* player = dynamic_cast<PlayerObject*>(gWorldManager->getObjectById(targetObject->getId())); tO->removeKnownObject(player); player->removeKnownObject(tO); gMessageLib->sendDestroyObject(tO->getId(),player); it++; } hopper->removeKnownObject(player); player->removeKnownObject(hopper); gMessageLib->sendDestroyObject(hopper->getId(),player); } } } // send a destroy to us gMessageLib->sendDestroyObject(object->getId(),player); // we don't know each other anymore knownObjects->erase(objIt++); object->removeKnownObject(player); if (++messageCount >= objectDestroyLimit) { // gLogger->logMsg("Pausing sendDestroyObject()-calls."); break; } continue; } ++objIt; } // For test bool allDestroyed = false; if (objIt == knownObjects->end()) { // gLogger->logMsg("Finished sendDestroyObject()-calls."); allDestroyed = true; } return allDestroyed; }
void ObjectController::handleDataTransform(Message* message,bool inRangeUpdate) { PlayerObject* player = dynamic_cast<PlayerObject*>(mObject); if (!player) { gLogger->logMsgF("ObjectController::handleDataTransform Object is NOT A PLAYER, id = %"PRIu64"", MSG_HIGH, mObject->getId()); return; } glm::vec3 pos; glm::quat dir; uint32 inMoveCount; uint32 tickCount; float speed; bool updateAll = false; // get tick and move counters tickCount = message->getUint32(); inMoveCount = message->getUint32(); // gLogger->logMsg("ObjectController::handleDataTransform"); //uint64 localTimeStart = Anh_Utils::Clock::getSingleton()->getLocalTime(); // only process if its in sequence if(player->getInMoveCount() >= inMoveCount) { return; } //uint32 ticks = tickCount - player->getClientTickCount(); // update tick and move counters... player->setLastMoveTick(tickCount); player->setClientTickCount(tickCount); player->setInMoveCount(inMoveCount); if(player->checkIfMounted() && player->getMount()) { //Player is mounted lets update his mount too player->getMount()->setLastMoveTick(tickCount); //player->getMount()->setInMoveCount((inMoveCount+1)); player->getMount()->setInMoveCount((inMoveCount)); // + 1 or nor does not matter, as long as we update inMoveCount. } // get new direction, position and speed dir.x = message->getFloat(); dir.y = message->getFloat(); dir.z = message->getFloat(); dir.w = message->getFloat(); pos.x = message->getFloat(); pos.y = message->getFloat(); pos.z = message->getFloat(); speed = message->getFloat(); // gLogger->logMsgF("Position outside = %.2f, %.2f, %.2f",MSG_NORMAL, pos.x, pos.y, pos.z); /* if (Heightmap::isHeightmapCacheAvaliable()) { gLogger->logMsgF("Heightmap value = %.2f",MSG_NORMAL, Heightmap::Instance()->getCachedHeightAt2DPosition(pos.x, pos.z)); } */ // gLogger->logMsgF("Direction = %f, %f, %f, %f",MSG_NORMAL, dir.x, dir.y, dir.z, dir.w); // stop entertaining, if we were // important is, that if we move we change our posture to NOT skill animating anymore! // so only stop entertaining when we are performing and NOT skillanimationg if(player->getPerformingState() != PlayerPerformance_None && player->getPosture() != CreaturePosture_SkillAnimating) { gEntertainerManager->stopEntertaining(player); } // if we just left a building if(player->getParentId() != 0) { updateAll = true; // Testing with 4 for add and 0 for remove. // Remove us from previous cell. gMessageLib->broadcastContainmentMessage(player->getId(),player->getParentId(),0,player); // remove us from the last cell we were in if(CellObject* cell = dynamic_cast<CellObject*>(gWorldManager->getObjectById(player->getParentId()))) { cell->removeObject(player); } else { gLogger->logMsgF("Error removing %"PRIu64" from cell(%"PRIu64")",MSG_HIGH,player->getId(),player->getParentId()); } // we are outside again player->setParentId(0); player->mPosition = pos; // Add us to the world. gMessageLib->broadcastContainmentMessage(player->getId(),0,4,player); // add us to the qtree if(QTRegion* newRegion = mSI->getQTRegion((double)pos.x,(double)pos.z)) { player->setSubZoneId((uint32)newRegion->getId()); newRegion->mTree->addObject(player); } else { // we should never get here ! gLogger->logMsg("ObjController::handleDataTransform: could not find zone region in map"); gLogger->logMsg("ObjController:: probably a bot : %i64u",static_cast<int>(player->getId())); // hammertime ! //muglies botter sometimes sends us weird positions //however other 3rd party tools might do the same gWorldManager->addDisconnectedPlayer(player); return; } // Inform tutorial about cell change. if (gWorldConfig->isTutorial()) { player->getTutorial()->setCellId(0); } } else //we are not in a building { // we should be in a qt at this point // get the qt of the new position if(QTRegion* newRegion = mSI->getQTRegion((double)pos.x,(double)pos.z)) { // we didnt change so update the old one if((uint32)newRegion->getId() == player->getSubZoneId()) { // this also updates the players position newRegion->mTree->updateObject(player,pos); //If our player is mounted lets update his mount aswell if(player->checkIfMounted() && player->getMount()) { newRegion->mTree->updateObject(player->getMount(),pos); } } else { updateAll = true; gLogger->logMsg("ObjController::DataTransform: Changing subzone"); // remove from old if(QTRegion* oldRegion = gWorldManager->getQTRegion(player->getSubZoneId())) { oldRegion->mTree->removeObject(player); //If our player is mounted lets update his mount aswell if(player->checkIfMounted() && player->getMount()) { oldRegion->mTree->removeObject(player->getMount()); } } // update players position player->mPosition = pos; //If our player is mounted lets update his mount aswell if(player->checkIfMounted() && player->getMount()) { player->getMount()->mPosition = pos; } // put into new player->setSubZoneId((uint32)newRegion->getId()); newRegion->mTree->addObject(player); //If our player is mounted lets update his mount aswell if(player->checkIfMounted() && player->getMount()) { player->getMount()->setSubZoneId((uint32)newRegion->getId()); newRegion->mTree->addObject(player->getMount()); } } } else { // we should never get here ! gLogger->logMsg("ObjController::DataTransform: could not find zone region in map"); gLogger->logMsg("ObjController:: probably a bot : %I64u",static_cast<int>(player->getId())); // hammertime ! // muglies botter sometimes sends us weird positions with X or Y far out of possible regions // however other 3rd party tools might do the same // we need to get rid of the client at this point nad probably should ban the player / add him to // a monitoring list when the coordinates were indeed out of bounds gWorldManager->addDisconnectedPlayer(player); return; } } player->mDirection = dir; player->setCurrentSpeed(speed); //If our player is mounted lets update his mount aswell if(player->checkIfMounted() && player->getMount()) { player->getMount()->mDirection = dir; player->getMount()->setCurrentSpeed(speed); } // destroy the instanced instrument if out of range if (player->getPlacedInstrumentId()) { if (!gWorldManager->objectsInRange(player->getId(), player->getPlacedInstrumentId(), 5.0)) { if (Item* item = dynamic_cast<Item*>(gWorldManager->getObjectById(player->getPlacedInstrumentId()))) { destroyObject(item->getId()); } } } // Terminate active conversation with npc if to far away (trainers only so far). ActiveConversation* ac = gConversationManager->getActiveConversation(player->getId()); if (ac != NULL) { // We do have a npc conversation going. if (!gWorldManager->objectsInRange(player->getId(), (ac->getNpc())->getId(), 11.0)) { // Terminate conversation, since we are out of range. gMessageLib->sendSystemMessage(player,L"","system_msg","out_of_range"); gConversationManager->stopConversation(player, true); // We will get the current dialog text in a chat bubble, only seen by me. Impressive :) } } if (updateAll) { // Update our world. playerWorldUpdate(true); // Speed up the timed update, if any pending. gWorldManager->addPlayerMovementUpdateTime(player, 250); } else { if (!gWorldConfig->isInstance()) { //If player is mounted... move his mount too! if(player->checkIfMounted() && player->getMount()) { //gMessageLib->sendDataTransform(player->getMount()); gMessageLib->sendUpdateTransformMessage(player->getMount()); } else { // send out position updates to known players // please note that these updates mess up our dance performance if(player->getPerformingState() == PlayerPerformance_None) { gMessageLib->sendUpdateTransformMessage(player); } } } else { // send out position updates to known players in group or self only gMessageLib->sendUpdateTransformMessage(player, player); } } //uint64 localTimeEnd = Anh_Utils::Clock::getSingleton()->getLocalTime(); //gLogger->logMsgF("Exec time PRId32",MSG_NORMAL, localTimeEnd - localTimeStart); }
void ObjectController::handleDataTransformWithParent(Message* message,bool inRangeUpdate) { // FIXME: for now assume we only get messages from players PlayerObject* player = dynamic_cast<PlayerObject*>(mObject); glm::vec3 pos; glm::quat dir; uint32 inMoveCount; uint32 tickCount; uint64 parentId; float speed; bool updateAll = false; // get tick and move counters tickCount = message->getUint32(); inMoveCount = message->getUint32(); // only process if its in sequence if (player->getInMoveCount() <= inMoveCount) { uint64 oldParentId = player->getParentId(); //uint32 ticks = tickCount - player->getClientTickCount(); // update tick and move counters player->setClientTickCount(tickCount); player->setInMoveCount(inMoveCount); // get new direction, position, parent and speed parentId = message->getUint64(); dir.x = message->getFloat(); dir.y = message->getFloat(); dir.z = message->getFloat(); dir.w = message->getFloat(); pos.x = message->getFloat(); pos.y = message->getFloat(); pos.z = message->getFloat(); speed = message->getFloat(); // gLogger->logMsgF("Position inside = %f, %f, %f",MSG_NORMAL, pos.x, pos.y, pos.z); // gLogger->logMsgF("Direction = %f, %f, %f, %f",MSG_NORMAL, dir.x, dir.y, dir.z, dir.w); // stop entertaining, if we were if(player->getPerformingState() != PlayerPerformance_None && player->getPosture() != CreaturePosture_SkillAnimating) { gEntertainerManager->stopEntertaining(player); } // if we changed cell if (oldParentId != parentId) { CellObject* cell = NULL; // gLogger->logMsgF("We changed cell from (%"PRIu64") to (%"PRIu64")",MSG_NORMAL, oldParentId, parentId); // Remove us from whatever we where in before. // (4 for add and 0 for remove) gMessageLib->broadcastContainmentMessage(player->getId(),oldParentId,0,player); // only remove us from si, if we just entered the building if (oldParentId != 0) { if((cell = dynamic_cast<CellObject*>(gWorldManager->getObjectById(oldParentId)))) { cell->removeObject(player); // Done above.. gMessageLib->broadcastContainmentMessage(player->getId(),parentId,4,player); } else { gLogger->logMsgF("Error removing %"PRIu64" from cell(%"PRIu64")",MSG_NORMAL,player->getId(),oldParentId); } } else { updateAll = true; // We just entered the building. // remove us from qt if(player->getSubZoneId()) { if(QTRegion* region = gWorldManager->getQTRegion(player->getSubZoneId())) { player->setSubZoneId(0); region->mTree->removeObject(player); //If our player is mounted lets update his mount aswell if(player->checkIfMounted() && player->getMount()) { player->getMount()->setSubZoneId(0); region->mTree->removeObject(player->getMount()); //Can't ride into a building with a mount! :-p //However, its easy to do so we have handling incase the client is tricked. // the vehicle is the INTANGIBLE Datapad Controller // the *vehicle* itself is the BODY if(Vehicle* datapad_pet = dynamic_cast<Vehicle*>(gWorldManager->getObjectById(player->getMount()->getPetController()))) { datapad_pet->dismountPlayer(); datapad_pet->store(); } } } } } // put us into new one gMessageLib->broadcastContainmentMessage(player->getId(),parentId,4,player); if((cell = dynamic_cast<CellObject*>(gWorldManager->getObjectById(parentId)))) { cell->addObjectSecure(player); // Inform tutorial about cell change. if (gWorldConfig->isTutorial()) { player->getTutorial()->setCellId(parentId); // gLogger->logMsgF("handleDataTransformWithParent: Adding %"PRIu64" to cell(%"PRIu64")",MSG_NORMAL,player->getId(),parentId); } } else { gLogger->logMsgF("Error adding %"PRIu64" to cell(%"PRIu64")",MSG_NORMAL,player->getId(),parentId); } } // update the player player->setParentId(parentId); player->mDirection = dir; player->mPosition = pos; player->setCurrentSpeed(speed); // destroy the instanced instrument if out of range if (player->getPlacedInstrumentId()) { if (!gWorldManager->objectsInRange(player->getId(), player->getPlacedInstrumentId(), 5.0)) { if (Item* item = dynamic_cast<Item*>(gWorldManager->getObjectById(player->getPlacedInstrumentId()))) { destroyObject(item->getId()); } } } // Terminate active conversation with npc if to far away (trainers only so far). ActiveConversation* ac = gConversationManager->getActiveConversation(player->getId()); if (ac != NULL) { // We do have a npc conversation going. if (!gWorldManager->objectsInRange(player->getId(), (ac->getNpc())->getId(), 11.0)) { // Terminate conversation, since we are out of range. gMessageLib->sendSystemMessage(player,L"","system_msg","out_of_range"); gConversationManager->stopConversation(player, true); // We will get the current dialog text in a chat bubble, only seen by me. Impressive :) } } if (updateAll) { // Update our world. playerWorldUpdate(true); // Speed up the timed update, if any pending. gWorldManager->addPlayerMovementUpdateTime(player, 250); } else { if (!gWorldConfig->isInstance()) { // send out updates gMessageLib->sendUpdateTransformMessageWithParent(player); } else { // send out position updates to known players in group or self only gMessageLib->sendUpdateTransformMessageWithParent(player, player); } } } }
uint64 ObjectController::playerWorldUpdate(bool forcedUpdate) { PlayerObject* player = dynamic_cast<PlayerObject*>(mObject); // If we already are busy, don't start another update. // ie if this is called by the worldmanager timer because we still have unupdated objects // in our resultmap if (!(mUpdatingObjects || mDestroyOutOfRangeObjects || forcedUpdate)) { // If we have been inactive for too long, let's update the world. if (player->getCurrentSpeed() == 0.0) { //is this the amount of full updates already running ? if (++mFullUpdateTrigger >= 15) // We only check this when we are running idle with low frequency { // gLogger->logMsg("... sitting still to long!"); // Let's update the world forcedUpdate = true; mFullUpdateTrigger = 0; } } else { mFullUpdateTrigger = 0; } } // Are we inside or outside? if (player->getParentId() != 0) { // We are inside. if (mUpdatingObjects || forcedUpdate) { // Just entered the building? // if (!mUpdatingObjects) // We need to abort any pending operation if we get a forcedUpdate (meaning entered, changed or left a cell or subzone). if (forcedUpdate) { // Update all. // gLogger->logMsg("ObjController::handleDataTransformWithParent: _findInRangeObjectsInside(true)"); _findInRangeObjectsInside(true); } } else { // This is the faster update, stil based on SI though. _findInRangeObjectsInside(false); } // Update some of the objects we found. mUpdatingObjects = !_updateInRangeObjectsInside(); } else { // We are outside. bool OutOfUpdateRange = false; // If we "just stopped" and not busy with updating, make a full update. if (!mUpdatingObjects && !mDestroyOutOfRangeObjects) { // We are not "busy" processing anything from previous sessions. if (player->getCurrentSpeed() == 0.0) { if (mMovementInactivityTrigger > 0) { if (--mMovementInactivityTrigger == 0) { // gLogger->logMsg("We are not moving..."); // We are not moving, but how far are we from last full update pos? if (glm::distance(player->mPosition, player->getLastUpdatePosition()) < 16) { // Force a full update, inclusive of saving current "update pos". // gLogger->logMsg("... forced update!"); OutOfUpdateRange = true; } else { // gLogger->logMsgF("... but to close to last update pos, %.1f",MSG_NORMAL, player->mPosition.distance2D(player->getLastUpdatePosition())); } } } } else { mMovementInactivityTrigger = 2; // We only check this when we are running idle with slow frequency // Need to be standstill for this amount of seconds * 5 (or whatever time we use for slow updates) before we update. } } // Position check for SI-update. OutOfUpdateRange |= !(glm::distance(player->mPosition, player->getLastUpdatePosition()) < 64.0f); //OutOfUpdateRange |= !(player->mPosition.inRange2D(player->getLastUpdatePosition(),64.0f)); // gLogger->logMsgF("Distance = %f",MSG_NORMAL, player->mPosition.distance2D(player->getLastUpdatePosition())); if (mUpdatingObjects || forcedUpdate || OutOfUpdateRange) { // More than 64 m from where we loaded SI, reload it. // We need to abort any pending operation if we get a forcedUpdate (meaning entered, changed or left a cell or subzone). if ((forcedUpdate) || OutOfUpdateRange) { // Save these coordinates // gLogger->logMsg("forcedUpdate"); mDestroyOutOfRangeObjects = false; // Stop the destroy-messages, in case we already have started to send them. if (OutOfUpdateRange) { // gLogger->logMsg("Out of 64m range"); player->setLastUpdatePosition(player->mPosition); //If our player is mounted let's update his mount if(player->checkIfMounted() && player->getMount()) { player->getMount()->setLastUpdatePosition(player->mPosition); } // We shall destroy out of range objects when we are done with the update of known objects. mDestroyOutOfRangeObjects = true; } _findInRangeObjectsOutside(true); } } else if (!mDestroyOutOfRangeObjects) { // This is the fast update, based on qt. // gLogger->logMsg("_findInRangeObjectsOutside(false)"); _findInRangeObjectsOutside(false); } // Update some of the objects we found. mUpdatingObjects = !_updateInRangeObjectsOutside(); if (!mUpdatingObjects) { // We are not updating new objects. if (mDestroyOutOfRangeObjects) { // We are ready to destroy objects out of range. if (_destroyOutOfRangeObjects(&mInRangeObjects)) { // All objects are now destroyed. mDestroyOutOfRangeObjects = false; // If active target out of range, clear. if (player->getTarget()) { // gLogger->logMsgF("playerWorldUpdate have a Target of type %d", MSG_NORMAL, player->getTarget()->getType()); // The list of objects we shall check for untargeting consist of all objects that we can "interact with". if ((player->getTarget()->getType() & (ObjType_Player | ObjType_NPC | ObjType_Creature)) || ((player->getTarget()->getType() == ObjType_Tangible) && (dynamic_cast<TangibleObject*>(player->getTarget())->getTangibleGroup() == TanGroup_TicketCollector))) { if (!(player->checkKnownObjects(player->getTarget()))) { player->setTarget(NULL); gMessageLib->sendTargetUpdateDeltasCreo6(player); // gLogger->logMsg("playerWorldUpdate clear Target"); } } } } } } } uint64 msToWait = 4900; // Will give 5 sec. if (mUpdatingObjects || mDestroyOutOfRangeObjects) { // We are busy, need to continue processing asap. msToWait = 900; // This should make us tick every second, since that's the base time for the timer we use. } return msToWait; }
bool ObjectController::_destroyOutOfRangeObjects(ObjectSet *inRangeObjects) { //TODO: when a container gets out of range //we need to destroy the children, too!!!!!!! // iterate our knowns PlayerObject* player = dynamic_cast<PlayerObject*>(mObject); ObjectSet* knownObjects = player->getKnownObjects(); ObjectSet::iterator objIt = knownObjects->begin(); PlayerObjectSet* knownPlayers = player->getKnownPlayers(); PlayerObjectSet::iterator playerIt = knownPlayers->begin(); const uint32 objectDestroyLimit = 5000; // update players while(playerIt != knownPlayers->end()) { PlayerObject* playerObject = (*playerIt); // if its not in the current inrange queries result, destroy it if(inRangeObjects->find(playerObject) == inRangeObjects->end()) { // send a destroy to us gMessageLib->sendDestroyObject(playerObject->getId(),player); //If player is mounted destroy his mount too if(playerObject->checkIfMounted() && playerObject->getMount()) { gMessageLib->sendDestroyObject(playerObject->getMount()->getId(),player); player->removeKnownObject(playerObject->getMount()); playerObject->getMount()->removeKnownObject(player); } //send a destroy to him gMessageLib->sendDestroyObject(player->getId(),playerObject); //If we're mounted destroy our mount too if(player->checkIfMounted() && playerObject->getMount()) { gMessageLib->sendDestroyObject(player->getMount()->getId(),playerObject); playerObject->removeKnownObject(player->getMount()); player->getMount()->removeKnownObject(playerObject); } // we don't know each other anymore knownPlayers->erase(playerIt++); playerObject->removeKnownObject(player); continue; } ++playerIt; } // We may want to limit the amount of messages sent in one session. uint32 messageCount = 0; // update objects //for(ObjectSet::const_iterator objIt = knownObjects->begin(); objIt != knownObjects->end(); objIt++) //we access the list above so it needs to be reset to the beginning objIt = knownObjects->begin(); while(objIt != knownObjects->end()) { Object* object = (*objIt); // if its not in the current inrange queries result, destroy it if(inRangeObjects->find(object) == inRangeObjects->end()) { if(object->getType() == ObjType_Structure)//ObjType_Tangible { } // send a destroy to us gMessageLib->sendDestroyObject(object->getId(),player); // we don't know each other anymore knownObjects->erase(objIt++); object->removeKnownObject(player); if (++messageCount >= objectDestroyLimit) { break; } continue; } ++objIt; } // For test bool allDestroyed = false; if (objIt == knownObjects->end()) { allDestroyed = true; } return allDestroyed; }
void ObjectController::handleDataTransform(Message* message,bool inRangeUpdate) { PlayerObject* player = dynamic_cast<PlayerObject*>(mObject); if (!player) { return; } glm::vec3 pos; glm::quat dir; uint32 inMoveCount; uint32 tickCount; float speed; bool updateAll = false; // get tick and move counters tickCount = message->getUint32(); inMoveCount = message->getUint32(); // only process if its in sequence if(player->getInMoveCount() >= inMoveCount) { return; } //uint32 ticks = tickCount - player->getClientTickCount(); // update tick and move counters... player->setLastMoveTick(tickCount); player->setClientTickCount(tickCount); player->setInMoveCount(inMoveCount); // get new direction, position and speed dir.x = message->getFloat(); dir.y = message->getFloat(); dir.z = message->getFloat(); dir.w = message->getFloat(); pos.x = message->getFloat(); pos.y = message->getFloat(); pos.z = message->getFloat(); speed = message->getFloat(); // stop entertaining ??? // important is, that if we move we change our posture to NOT skill animating anymore! // so only stop entertaining when we are performing and NOT skillanimationg if(player->getPerformingState() != PlayerPerformance_None && player->states.getPosture() != CreaturePosture_SkillAnimating) { gEntertainerManager->stopEntertaining(player); } // if we just left a building if(player->getParentId() != 0) { updateAll = true; // Testing with 4 for add and 0 for remove. // Remove us from previous cell. gMessageLib->broadcastContainmentMessage(player->getId(),player->getParentId(),0,player); // remove us from the last cell we were in if(CellObject* cell = dynamic_cast<CellObject*>(gWorldManager->getObjectById(player->getParentId()))) { cell->removeObject(player); } else { DLOG(INFO) << "Error removing" << player->getId() << " from cell " << player->getParentId(); } // we are outside again player->setParentId(0); player->mPosition = pos; // Add us to the world. gMessageLib->broadcastContainmentMessage(player->getId(),0,4,player); // add us to the qtree if(QTRegion* newRegion = mSI->getQTRegion((double)pos.x,(double)pos.z)) { player->setSubZoneId((uint32)newRegion->getId()); player->setSubZone(newRegion); newRegion->mTree->addObject(player); } else { // we should never get here ! // it basically means we left the map DLOG(INFO) << "ObjController::handleDataTransform: could not find zone region in map"; DLOG(INFO) << "ObjController:: probably a bot : " << player->getId(); // hammertime ! //muglies botter sometimes sends us weird positions //however other 3rd party tools might do the same gWorldManager->addDisconnectedPlayer(player); return; } // Inform tutorial about cell change. if (gWorldConfig->isTutorial()) { player->getTutorial()->setCellId(0); } } else //we are not in a building { // we should be in a qt at this point check our qt if we still are inside its bounds // please note, that there is exactly *one* qtregion per planet and qtregions do *not* overlap // so there is no need to search the region everytime even if we should decide to add more qtregions // subzone is NULL however, when we just left a building if(player->getSubZone() && player->getSubZone()->checkPlayerPosition(pos.x, pos.z)) { // this also updates the players position player->getSubZone()->mTree->updateObject(player,pos); //If our player is mounted lets update his mount aswell if(player->checkIfMounted() && player->getMount()) { player->getSubZone()->mTree->updateObject(player->getMount(),pos); } } else //do an intersectsWithQuery of objects in the si to find our new region - //CAVE shouldnt it be a contains query ? //what do we do if several regions overlap ? if(QTRegion* newRegion = mSI->getQTRegion((double)pos.x,(double)pos.z)) { updateAll = true; // remove from old if(QTRegion* oldRegion = player->getSubZone()) { oldRegion->mTree->removeObject(player); //If our player is mounted lets update his mount aswell if(player->checkIfMounted() && player->getMount()) { oldRegion->mTree->removeObject(player->getMount()); } } // update players position player->mPosition = pos; //If our player is mounted lets update his mount aswell if(player->checkIfMounted() && player->getMount()) { player->getMount()->mPosition = pos; } // put into new player->setSubZoneId((uint32)newRegion->getId()); player->setSubZone(newRegion); newRegion->mTree->addObject(player); //If our player is mounted lets update his mount aswell if(player->checkIfMounted() && player->getMount()) { player->getMount()->setSubZoneId((uint32)newRegion->getId()); newRegion->mTree->addObject(player->getMount()); } } else { // we should never get here ! DLOG(INFO) << "ObjController::handleDataTransform: could not find zone region in map"; DLOG(INFO) << "ObjController:: probably a bot : " << player->getId(); // hammertime ! // muglies botter sometimes sends us weird positions with X or Y far out of possible regions // however other 3rd party tools might do the same // we need to get rid of the client at this point nad probably should ban the player / add him to // a monitoring list when the coordinates were indeed out of bounds gWorldManager->addDisconnectedPlayer(player); return; } } player->mDirection = dir; player->setCurrentSpeed(speed); // destroy the instanced instrument if out of range if (player->getPlacedInstrumentId()) { if (!gWorldManager->objectsInRange(player->getId(), player->getPlacedInstrumentId(), 5.0)) { if (Item* item = dynamic_cast<Item*>(gWorldManager->getObjectById(player->getPlacedInstrumentId()))) { destroyObject(item->getId()); } } } // Terminate active conversation with npc if to far away (trainers only so far). ActiveConversation* ac = gConversationManager->getActiveConversation(player->getId()); if (ac != NULL) { // We do have a npc conversation going. if (!gWorldManager->objectsInRange(player->getId(), (ac->getNpc())->getId(), 11.0)) { // Terminate conversation, since we are out of range. gMessageLib->SendSystemMessage(::common::OutOfBand("system_msg", "out_of_range"), player); gConversationManager->stopConversation(player, true); // We will get the current dialog text in a chat bubble, only seen by me. Impressive :) } } if (updateAll) { // Update our world. playerWorldUpdate(true); // Speed up the timed update, if any pending. gWorldManager->addPlayerMovementUpdateTime(player, 250); } else { if (!gWorldConfig->isInstance()) { //If player is mounted... move his mount too! if(player->checkIfMounted() && player->getMount()) { //gMessageLib->sendDataTransform(player->getMount()); player->getMount()->mDirection = dir; player->getMount()->setCurrentSpeed(speed); player->getMount()->setLastMoveTick(tickCount); player->getMount()->setInMoveCount((inMoveCount)); // + 1 or nor does not matter, as long as we update inMoveCount. gMessageLib->sendUpdateTransformMessage(player->getMount()); } else { // send out position updates to known players // please note that these updates mess up our dance performance /*if(player->getPerformingState() == PlayerPerformance_None) {*/ gMessageLib->sendUpdateTransformMessage(player); //} } } else { // send out position updates to known players in group or self only gMessageLib->sendUpdateTransformMessage(player, player); } } }