// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . //----------------------------------------------------------------------------- // includes //----------------------------------------------------------------------------- #include "stdpch.h" #include "server_animation_module.h" #include "nel/net/unified_network.h" #include "nel/net/module_message.h" #include "nel/net/module_socket.h" #include "nel/net/module_builder_parts.h" #include "nel/net/module_manager.h" #include "nel/misc/command.h" #include "nel/misc/path.h" #include "nel/misc/types_nl.h" #include "nel/misc/sstring.h" #include "nel/misc/string_conversion.h" #include "nel/ligo/primitive.h" #include "nel/ligo/ligo_config.h" #include "nel/ligo/primitive_utils.h" #include "game_share/utils.h" #include "game_share/persistent_data.h" #include "game_share/chat_group.h" #include "game_share/misc_const.h" #include "game_share/ring_session_manager_itf.h" #include "game_share/object.h" #include "game_share/scenario.h" #include "game_share/r2_messages.h" #include "game_share/r2_ligo_config.h" #include "game_share/scenario_entry_points.h" #include "game_share/ring_access.h" // TEMP //#include "r2_modules/server_edition_module.h" //#include "r2_modules/server_admin_module.h" #include "ai_wrapper.h" #include "dms.h" using namespace std; using namespace NLMISC; using namespace NLLIGO; using namespace NLNET; using namespace R2; // Debug CVariable WriteScenarioDebugDataToFile( "DSS", "WriteScenarioDebugDataToFile", "Set to true to write scenario rtdata and xml primitive to file", false, 0, true ); CVariable DelayBeforeStartAct ("DSS", "DelayBeforeStartAct", "The delay wait by player/dm between the moment a dm/ai has decided the change of act and the moment of the real change", 30, 0, true ); CVariable DelayBeforeNewLocation ("DSS", "DelayBeforeNewLocation", "The min delay between 2 change of location", 25, 0, true ); CVariable UseSheetClientWithLevel( "DSS", "UseSheetClientWithLevel", "use sheet client like basic_fyros_male_f2.creature instead of basic_fyros_male_f2.creature", true, 0, true ); //std::vector Pdrs; static CPersistentDataRecordRyzomStore Pdr; NLNET_REGISTER_MODULE_FACTORY(CServerAnimationModule, "ServerAnimationModule"); namespace R2 { class CRtNpc : public NLMISC::CRefCount { public: CRtNpc(TAIAlias alias, CObject* objectData, TAIAlias grpAlias, uint32 dmProperty) { Alias = alias; ObjectData = objectData; GrpAlias = grpAlias; NpcAnimationProp = dmProperty; NameId = 0; Alived = true; } NLMISC::CEntityId EntityId; TAIAlias Alias; TAIAlias GrpAlias; TDataSetRow DataSetRow; CObject* ObjectData; uint32 NpcAnimationProp; uint32 NameId; bool Alived; }; class CRtGrp: public NLMISC::CRefCount { public: CRtGrp(TAIAlias alias, CObject* objectData, const std::string& fullName) { Alias = alias; ObjectData = objectData; FullName = fullName; //EntityId = NLMISC::CEntityId::Unknown; (default) } NLMISC::CEntityId EntityId; TAIAlias Alias; std::string FullName; CObject* ObjectData; }; class CRtUserTrigger { public: std::string FullName; std::string Grp; std::string Name; }; class CRtAct : public NLMISC::CRefCount { public: typedef std::map > TRtNpcs; typedef std::map > TRtGrps; typedef std::vector TRtUserTriggers; typedef uint32 TEggId; typedef std::string TFullGrpName; typedef std::map TActiveEasterEggs; public: R2::CRtGrp* getRtGrpByName(const std::string& name) const; void addUserTrigger(const CRtUserTrigger& userTrigger); bool activateEasterEgg(uint32 easterEggId, const std::string & grpControler) { TRtGrps::const_iterator first(RtGrps.begin()), last(RtGrps.end()); for ( ; first != last && first->second->FullName != grpControler ; ++first) { } if ( first == last) { nlwarning("SAM: Error while activating easter egg. The controler grp is not valid."); return false; } return ActiveEasterEggs.insert(std::make_pair(easterEggId, grpControler)).second; } bool deactivateEasterEgg(uint32 easterEggId); public: TRtNpcs RtNpcs; TRtGrps RtGrps; uint16 WeatherValue; // 0 for auto weather //uint8 Season; // 0 for auto season uint32 LocationId; std::string Name; TRtUserTriggers UserTriggers; TActiveEasterEggs ActiveEasterEggs; std::string ActDescription; std::string PreActDescription; }; bool CRtAct::deactivateEasterEgg(uint32 easterEggId) { TActiveEasterEggs::iterator found(ActiveEasterEggs.find(easterEggId)); if (found == ActiveEasterEggs.end()) return false; ActiveEasterEggs.erase(found); return true; } R2::CRtGrp* CRtAct::getRtGrpByName(const std::string& name) const { TRtGrps::const_iterator first(RtGrps.begin()), last(RtGrps.end()); for ( ; first != last ; ++first) { CObject* object = first->second->ObjectData; if ( object && object->isString("Id") ) { std::string data = object->toString("Id"); if (data == name) { return first->second; } } } return 0; } void CRtAct::addUserTrigger(const CRtUserTrigger& userTrigger) { CRtGrp * rtGrp = getRtGrpByName(userTrigger.Grp); if (rtGrp) { UserTriggers.push_back(userTrigger); UserTriggers.back().FullName = rtGrp->FullName; } else { nlwarning("Try to create undef user trigger '%s'", userTrigger.Grp.c_str()); } } class CRtLocation { public: uint8 Season; std::string Island; std::string EntryPoint; }; class CBotControler { public: typedef NLMISC::CTwinMap< uint32, NLMISC::CEntityId > TControlledEntities; typedef std::map TControlledEntitiesList; // public: CBotControler(){} bool add(const NLMISC::CEntityId& eid, const NLMISC::CEntityId& creatureId); bool remove(const NLMISC::CEntityId& eid, const NLMISC::CEntityId& creatureId); NLMISC::CEntityId getEntity(const NLMISC::CEntityId& eid, uint32 id) const; void getBots(const NLMISC::CEntityId& eid, std::map& bots); void getBots(uint32 playerId, std::map& bots); void removeChar(const NLMISC::CEntityId& eid); uint32 getBotsCount(uint32 charId) const; private: TControlledEntitiesList _List; }; void CBotControler::getBots(const NLMISC::CEntityId& eid, std::map& bots) { TCharId charId = static_cast(eid.getShortId()); getBots(charId, bots); } void CBotControler::getBots(uint32 charId, std::map& bots) { TControlledEntitiesList::iterator found(_List.find(charId)); if ( found == _List.end()) { return; } const std::map& entities =found->second.getAToBMap(); bots = entities; } uint32 CBotControler::getBotsCount(uint32 charId) const { TControlledEntitiesList::const_iterator found(_List.find(charId)); if ( found == _List.end()) { return 0; } const std::map& entities =found->second.getAToBMap(); return entities.size(); } void CBotControler::removeChar(const NLMISC::CEntityId& eid) { TCharId charId = static_cast(eid.getShortId()); TControlledEntitiesList::iterator found(_List.find(charId)); if ( found != _List.end()) { _List.erase(found); } } bool CBotControler::add(const NLMISC::CEntityId& eid, const NLMISC::CEntityId& creatureId) { TCharId charId = static_cast(eid.getShortId()); TControlledEntitiesList::iterator found = _List.find(charId); if (found == _List.end()) { found = _List.insert( std::make_pair(charId, CTwinMap() ) ).first; } TControlledEntities & twin = found->second; const uint32* id = twin.getA(creatureId); if ( id ) { return false; } const std::map & entities = twin.getAToBMap(); uint32 last = 1; if (!entities.empty()) { uint32 f = entities.rbegin()->first; last += f; } twin.add(last, creatureId); return true; } bool CBotControler::remove(const NLMISC::CEntityId& eid, const NLMISC::CEntityId& creatureId) { TCharId charId = static_cast(eid.getShortId()); TControlledEntitiesList::iterator found = _List.find(charId); if (found == _List.end()) { return false; } TControlledEntities & twin = found->second; const uint32* id = twin.getA(creatureId); if ( !id ) { return false; } twin.removeWithB(creatureId); if (twin.getAToBMap().empty()){ _List.erase(found); } return true; } NLMISC::CEntityId CBotControler::getEntity(const NLMISC::CEntityId& eid, uint32 id) const { TCharId charId = static_cast(eid.getShortId()); TControlledEntitiesList::const_iterator found = _List.find(charId); // As the player disconnected? if (found == _List.end()) { return NLMISC::CEntityId(); } const NLMISC::CTwinMap & twin = found->second; const NLMISC::CEntityId * entity = twin.getB(id); if (!entity) { return NLMISC::CEntityId(); } return *entity; } struct TCharacterInfo { public: NLMISC::CEntityId TargetId; }; class CAnimationSession { public: typedef std::vector< NLMISC::CSmartPtr > TActs; typedef std::vector TLocations; typedef uint32 TActId; typedef uint32 TEasterEggId; typedef std::map TActiveEasterEggs; typedef uint32 TAiInstance; typedef std::map TCharacterInfos; public: std::auto_ptr RtData; TScenarioHeaderSerializer ScenarioHeader; TSessionId SessionId; //vector std::vector ConnectedChars; std::vector Pdrs; TActs Acts; uint32 CurrentAct; //if 0 <=> no act uint16 WeatherValue; // current weather in the [1, 1023] range, or 0 for auto weather // weather value can come from the scenario description, or may have been changed by an animator uint8 CurrSeason; // current season or ~0 for no season set yet bool StartingAct; // 1 if a player/ia has schedule a startAct uint32 InitialAct; //act at wich begin the scenario (1) for animation currentAct for test uint32 ScenarioScore; NLMISC::TTime ScenarioTime; bool TimingIsFinished; std::vector MissionItems; TLocations Locations; TActiveEasterEggs ActiveEasterEggs; CBotControler IncarningBots; CBotControler TalkingAsBots; TAiInstance AiInstance; NLMISC::TTime DateOfLastNewLocation; sint32 InitialX; sint32 InitialY; uint8 InitialSeason; std::set CharacternValidePosition; bool InitialTp; TCharacterInfos CharacterInfos; public: CAnimationSession() { WeatherValue = 0; // auto weather CurrSeason = ~0; StartingAct = false; InitialAct = 1; AiInstance = ~0;//wrong value DateOfLastNewLocation = 0; InitialX = 0; InitialY = 0; InitialSeason = 0; InitialTp = false; TimingIsFinished = false; ScenarioScore = 0; } void setStartParams(sint32 x, sint32 y, uint8 season) { InitialX = x; InitialY = y; InitialSeason = season; } void setWeatherValue(uint16 value); void setSeason(uint8 value); void sendWeatherValueToChar(uint32 charId, uint16 weatherValue) const; void sendSeasonToChar(uint32 charId, uint8 season) const; uint32 getActCount() const { return Pdrs.size(); } void updateUserTriggerDescriptions(TUserTriggerDescriptions& userTriggerDescriptions); void updateActPositionDescriptions(TActPositionDescriptions& actPositionDescriptions); void easterEggLooted(uint32 easterEggId, TSessionId scenarioId); }; void CAnimationSession::easterEggLooted(uint32 easterEggId, TSessionId /* scenarioId */) { TActiveEasterEggs::const_iterator found = ActiveEasterEggs.find(easterEggId); DROP_IF(found == ActiveEasterEggs.end(), "Error try to loot an unactive easter egg" ,return); uint32 actId = found->second; DROP_IF(actId >= Acts.size(), "Error try to loot an unactive easter egg", return); CRtAct* rtAct = Acts[actId]; CRtAct::TActiveEasterEggs::const_iterator found2 = rtAct->ActiveEasterEggs.find(easterEggId); DROP_IF(found2 == rtAct->ActiveEasterEggs.end(), "Error try to loot an unactive easter egg", return); std::string fullname = found2->second; CAiWrapper::getInstance().triggerUserTrigger(fullname, 2); } void CAnimationSession::setWeatherValue(uint16 weatherValue) { WeatherValue = weatherValue; // update weather on EGS for all players connected to that map for (uint k = 0; k < ConnectedChars.size(); ++k) { sendWeatherValueToChar(ConnectedChars[k], weatherValue); } } void CAnimationSession::setSeason(uint8 season) { if (season == CurrSeason) return; CurrSeason = season; // update season on EGS for all players connected to that map for (uint k = 0; k < ConnectedChars.size(); ++k) { sendSeasonToChar(ConnectedChars[k], season); } } void CAnimationSession::sendWeatherValueToChar(uint32 charId, uint16 weatherValue) const { CMessage msgout("SET_PLAYER_WEATHER"); msgout.serial(charId); uint16 weatherValue16 = (uint16) weatherValue; msgout.serial(weatherValue16); CUnifiedNetwork::getInstance()->send("EGS", msgout); } void CAnimationSession::sendSeasonToChar(uint32 charId, uint8 season) const { CMessage msgout("SET_PLAYER_SEASON"); msgout.serial(charId); msgout.serial(season); CUnifiedNetwork::getInstance()->send("EGS", msgout); } void CAnimationSession::updateUserTriggerDescriptions(TUserTriggerDescriptions& userTriggerDescriptions) { userTriggerDescriptions.clear(); //Act0 trigger uint32 actIndex = 0; uint32 actCount = Acts.size(); for ( ; actIndex != actCount; ++actIndex) { CRtAct* act = Acts[actIndex]; uint32 userTriggerCount = act->UserTriggers.size(); uint32 index = 0; for ( ; index != userTriggerCount; ++index) { TUserTriggerDescription userTriggerDescription; userTriggerDescription.Name = act->UserTriggers[index].Name; userTriggerDescription.Act = actIndex; userTriggerDescription.Id = index; userTriggerDescriptions.push_back(userTriggerDescription); } } } void CAnimationSession::updateActPositionDescriptions(TActPositionDescriptions& actPositionDescriptions) { actPositionDescriptions.clear(); uint32 actIndex = 0; uint32 actCount = Acts.size(); for ( ; actIndex != actCount; ++actIndex) { CRtAct* act = Acts[actIndex]; TActPositionDescription actPositionDescription; if ( act->LocationId <= this->Locations.size()) { actPositionDescription.Name = act->Name; actPositionDescription.Season = this->Locations[act->LocationId ].Season; actPositionDescription.Island = this->Locations[ act->LocationId].Island; actPositionDescription.LocationId = act->LocationId; } else { actPositionDescription.Name = act->Name; actPositionDescription.Season = 0; actPositionDescription.Island = ""; actPositionDescription.LocationId = 0; } actPositionDescriptions.push_back(actPositionDescription); } } class CAttributeToProperty { public: CAttributeToProperty(CObject* object, IPrimitive* prim) { _Object = object; _Primitive = prim; } void setAttributeAsString(const std::string & attrName, const std::string& propName) { CObject* attr = _Object->getAttr(attrName); if (attr && attr->isString()) { std::string str = attr->toString(); _Primitive->addPropertyByName(propName.c_str(), new CPropertyString(str)); } } void setAttributeAsStringWithPrefix(const std::string & attrName, const std::string& propName, const std::string& prefix) { CObject* attr = _Object->getAttr(attrName); if (attr && attr->isString()) { std::string str = attr->toString(); _Primitive->addPropertyByName(propName.c_str(), new CPropertyString(prefix+str)); } } void setAiStateName( const std::string& prefix); void setAttributeAsStringArray(const std::string & attrName, const std::string& propName); void setAttributeAsStringArrayWithPrefix(const std::string & attrName, const std::string& propName, const std::string& prefix) { CObject* attr = _Object->getAttr(attrName); if (attr && attr->isString()) { string str = attr->toString(); vector result; NLMISC::splitString(str, "\n", result); uint32 first(0), last(result.size()); for ( ; first != last ; ++first) { result[first] = prefix + result[first] ; } _Primitive->addPropertyByName(propName.c_str(), new CPropertyStringArray(result)); } } void setAttributeAsBool(const std::string & attrName, const std::string& propName) { CObject* attr = _Object->getAttr(attrName); if (attr && attr->isNumber()) { sint value = static_cast(attr->toNumber()); _Primitive->addPropertyByName(propName.c_str(), new CPropertyString(value?"true":"false")); } } void setPrimPoint() { CObject* attr = 0; CPrimPoint* point = dynamic_cast(_Primitive); nlassert(point); CObject* pt = _Object->getAttr("Pt"); if (pt) { attr = pt->getAttr("x"); if (attr && attr->isNumber()) { point->Point.x = static_cast(attr->toNumber()); } attr = pt->getAttr("y"); if (attr && attr->isNumber()) { point->Point.y = static_cast(attr->toNumber()); } attr = pt->getAttr("z"); if (attr && attr->isNumber()) { point->Point.z = static_cast(0.0); } } attr = _Object->getAttr("Angle"); if (attr && attr->isNumber()) { point->Angle = static_cast(attr->toNumber()); } } void setPrimPath(); void setPrimZone(); private: CObject* _Object; IPrimitive* _Primitive; }; void CAttributeToProperty::setAttributeAsStringArray(const std::string & attrName, const std::string& propName) { CObject* attr = _Object->getAttr(attrName); if (attr && attr->isString()) { string str = attr->toString(); vector result; NLMISC::splitString(str, "\n", result); _Primitive->addPropertyByName(propName.c_str(), new CPropertyStringArray(result)); } } void CAttributeToProperty::setAiStateName(const std::string& prefix) { std::string ai_movement, ai_activity; std::string name; CObject* tmp=_Object->getAttr("Id"); if( !(tmp&&tmp->isString())&&((name = tmp->toString()).length()!=0)) { nlwarning("R2Ani: invalide rtData"); return; } _Primitive->addPropertyByName("name", new CPropertyString(prefix + name)); } void CAttributeToProperty::setPrimPath() { CObject* attr = 0; CPrimPath* points = dynamic_cast(_Primitive); nlassert(points); CObject* pts = _Object->getAttr("Pts"); if (pts) { uint32 first(0), last( pts->getSize() ); points->VPoints.resize(last); for ( ; first != last ; ++first ) { CObject* pt = pts->getValue(first); attr = pt->getAttr("x"); if (attr && attr->isNumber()) { points->VPoints[first].x = static_cast(attr->toNumber()); } attr = pt->getAttr("y"); if (attr && attr->isNumber()) { points->VPoints[first].y = static_cast(attr->toNumber()); } attr = pt->getAttr("z"); if (attr && attr->isNumber()) { points->VPoints[first].z = static_cast(attr->toNumber()); } } } } void CAttributeToProperty::setPrimZone() { CObject* attr = 0; CPrimZone* points = dynamic_cast(_Primitive); nlassert(points); CObject* pts = _Object->getAttr("Pts"); if (pts) { uint32 first(0), last( pts->getSize() ); points->VPoints.resize(last); for ( ; first != last ; ++first ) { CObject* pt = pts->getValue(first); attr = pt->getAttr("x"); if (attr && attr->isNumber()) { points->VPoints[first].x = static_cast(attr->toNumber()); } attr = pt->getAttr("y"); if (attr && attr->isNumber()) { points->VPoints[first].y = static_cast(attr->toNumber()); } attr = pt->getAttr("z"); if (attr && attr->isNumber()) { points->VPoints[first].z = static_cast(attr->toNumber()); } } } } //-------------------------------------------------------------------------------------------- class CTaskStopTest : public CTask { public: CTaskStopTest(CServerAnimationModule* animationModule, TSessionId sessionId) :_AnimationModule(animationModule), _SessionId(sessionId) { } void doOperation() { uint32 unused; _AnimationModule->stopTestImpl(_SessionId, unused); } private: CServerAnimationModule* _AnimationModule; TSessionId _SessionId; }; class CTaskBroadcast : public CTask { public: // Take ownership of the message CTaskBroadcast(CServerAnimationModule* animationModule, TSessionId sessionId, CMessage& msg) :_AnimationModule(animationModule), _SessionId(sessionId) { _Msg.swap(msg); } void doOperation() { _AnimationModule->broadcastMsg(_SessionId, _Msg); } private: CServerAnimationModule* _AnimationModule; TSessionId _SessionId; CMessage _Msg; }; class CTaskStartAct : public CTask { public: CTaskStartAct(NLMISC::TTime t, CServerAnimationModule* animationModule, TSessionId sessionId, uint32 actId, bool mustTp) : CTask(t), _AnimationModule(animationModule), _SessionId(sessionId),_ActId(actId), _MustTp(mustTp){} void doOperation() { CAnimationSession* session = _AnimationModule->getSession(_SessionId); if (session && session->StartingAct) { session->StartingAct = false; _AnimationModule->startAct(_SessionId, _ActId); if (_MustTp) { session->DateOfLastNewLocation = NLMISC::CTime::getLocalTime (); session->CharacternValidePosition.clear(); // we invalidate all player; std::vector::const_iterator first(session->ConnectedChars.begin()), last(session->ConnectedChars.end()); for ( ; first != last ; ++first) { session->CharacternValidePosition.insert(*first); } } } } private: CServerAnimationModule* _AnimationModule; TSessionId _SessionId; uint32 _ActId; bool _MustTp; }; class CTaskScheduleStartSession: public CTask { public: CTaskScheduleStartSession( CServerAnimationModule* animationModule, const CAnimationMessageAnimationStart& msg) :_AnimationModule(animationModule), _Msg(msg) {} void doOperation() { _AnimationModule->scheduleStartSessionImpl(_Msg); } private: CServerAnimationModule* _AnimationModule; CAnimationMessageAnimationStart _Msg; }; //-------------------------------------------------------------------------------------------- void CServerAnimationModule::broadcastMessage(CAnimationSession* session, const NLNET::CMessage& msg) { if (!session->ConnectedChars.empty()) { std::vector::const_iterator first(session->ConnectedChars.begin()), last(session->ConnectedChars.end()); for ( ; first != last ; ++first) { const NLNET::TModuleProxyPtr* ptr = getEditionModule()->getClientProxyPtr(*first); if (ptr) { (*ptr)->sendModuleMessage(this, msg); } } } } void CServerAnimationModule::scheduleStartAct(TSessionId sessionId, uint32 actId) { CAnimationSession* session = getSession(sessionId); if (session) { CMessage msg; if (!session->StartingAct) { if (0getActCount() ) { session->StartingAct = true; uint32 currentAct = session->CurrentAct; uint32 nextLocationId = session->Acts[actId]->LocationId; uint32 currentLoctionId = session->Acts[currentAct]->LocationId; DROP_IF( nextLocationId >= session->Locations.size(), "Invalid Location", return); DROP_IF( currentLoctionId >= session->Locations.size(), "Invalid Location", return); bool mustTp = nextLocationId != currentLoctionId; NLMISC::TTime delay = mustTp ? 3000 // Tp with jump : 1000; // Normal TP if (!session->Acts[actId]->PreActDescription.empty()) { delay = 3000; } if (session->InitialTp ) { session->InitialTp = false; mustTp = true; delay = 0; } // if act change in the last 20 second add a wait effect. if (session->DateOfLastNewLocation != 0) { NLMISC::TTime now = CTime::getLocalTime(); NLMISC::TTime wait = now - session->DateOfLastNewLocation; if ( wait < NLMISC::TTime(DelayBeforeNewLocation)*1000) { delay += NLMISC::TTime(DelayBeforeNewLocation)*1000 - wait; } } _Tasks.addTask( new CTaskStartAct( NLMISC::CTime::getLocalTime () + delay, this, sessionId, actId, mustTp)); if (mustTp) { broadcastMessage(session, CShareClientEditionItfProxy::buildMessageFor_scheduleStartAct(msg, 0, actId, uint32(delay/1000)) ); } if (!session->Acts[actId]->PreActDescription.empty()) { NLNET::CMessage msg; CShareClientEditionItfProxy::buildMessageFor_systemMsg(msg, "BC_ML", "", session->Acts[actId]->PreActDescription); _Tasks.addTaskAt(NLMISC::CTime::getLocalTime () + delay - 3000 , new CTaskBroadcast(this, sessionId, msg)); } } else { broadcastMessage(session, CShareClientEditionItfProxy::buildMessageFor_scheduleStartAct(msg, 2, actId, DelayBeforeStartAct) ); } } else { broadcastMessage(session, CShareClientEditionItfProxy::buildMessageFor_scheduleStartAct(msg, 1, actId, DelayBeforeStartAct) ); } } } void CServerAnimationModule::init(NLNET::IModuleSocket* gateway, CDynamicMapService* server) { _Server = server; CAiWrapper::getInstance().init( CPrimitiveContext::instance().CurrentLigoConfig); this->plugModule(gateway); _Emotes.get("");//force lazy initialization // check if the AI service is up const std::vector &connectionList = CUnifiedNetwork::getInstance()->getConnectionList(); for( uint i = connectionList.size(); i > 0; --i ) { nldebug( "R2An: %s is already up", CUnifiedNetwork::getInstance()->getServiceName(connectionList[i-1]).c_str() ); if( "AIS" == CUnifiedNetwork::getInstance()->getServiceName(connectionList[i-1]) ) { _ReadyForNextSession = true; } } } CServerAnimationModule::CServerAnimationModule() : _ReadyForNextSession( false ) { CServerAnimationItfSkel::init(this); CShareServerAnimationItfSkel::init(this); _Server = 0; } CServerAnimationModule::~CServerAnimationModule() { while( !_QueuedSessions.empty() ) { CAnimationSession *animSession = _QueuedSessions.front(); _QueuedSessions.pop_front(); delete animSession; } } IPrimitive* CServerAnimationModule::getAction(CObject* action, const std::string& prefix,TSessionId scenarioId) { if (!action) { nlwarning("Error while generating primitives in scenario '%u'", scenarioId.asInt()); return 0; } IPrimitive* pAction= dynamic_cast (CClassRegistry::create ("CPrimNode")); pAction->addPropertyByName("class", new CPropertyString("npc_event_handler_action")); pAction->addPropertyByName("ai_type", new CPropertyString("NPC_EVENT_ACTION")); // AJM pAction->addPropertyByName("weight", new CPropertyString("1")); // AJM CAttributeToProperty a2pAction(action, pAction); a2pAction.setAttributeAsString("Action","action"); a2pAction.setAttributeAsString("Action","name"); // AJM: default value for name <- action CObject* tmp=action->getAttr("Action"); if(tmp&&tmp->isString()&&tmp->toString()=="npc_say") { CObject* tmp2 = action->getAttr("Parameters"); if(tmp2&&tmp2->isString()) { NLMISC::CSString param (tmp2->toString()); NLMISC::CVectorSString result; if(param.splitLines(result) ) { if (result.size() == 0) { nlwarning("ERROR: npc_say but no parameters !!! %d in session ", scenarioId.asInt()); } if(result.size()>=1) { NLMISC::CSString name(result[0]); if(name.find(":",0)!=string::npos) { result[0] = prefix+result[0]; } } if(result.size()>=2) result[1] = "DSS_"+toString(scenarioId)+" "+result[1]; if(result.size()>=3) { for(uint32 i=2;iaddPropertyByName("parameters", new CPropertyStringArray( (std::vector &)result )); } } } else { if (!action->isString("Action") ) { nlwarning("Invalid rtData: no action found"); return 0; } CSString caction(action->toString("Action")); if (caction == "begin_state" || caction.left(14)=="trigger_event_" || caction == "facing") { a2pAction.setAttributeAsStringArrayWithPrefix("Parameters","parameters", prefix); } else if (caction == "emot") { std::string attrName("Parameters"), propName("parameters"); CObject* attr = action->getAttr(attrName); if (attr && attr->isString()) { string str = attr->toString(); vector result; NLMISC::splitString(str, "\n", result); uint32 first(0), last(result.size()); for ( ; first != last ; ++first) { if (first == 0) { result[first] = _Emotes.get(result[first]); } else { result[first] = prefix + result[first] ; } } pAction->addPropertyByName(propName.c_str(), new CPropertyStringArray(result)); } } else if(caction == "modify_variable" || caction=="condition_if" || caction=="condition_if_else" || caction == "dynamic_if") { CSString str = action->toString("Parameters"); if(str.find(":")!=string::npos) { a2pAction.setAttributeAsStringArrayWithPrefix("Parameters","parameters", prefix); } else { a2pAction.setAttributeAsStringArray("Parameters","parameters"); } } else { a2pAction.setAttributeAsStringArray("Parameters","parameters"); } } CObject* weight = action->getAttr("Weight"); if(weight) { uint32 w = (int)weight->toNumber(); std::string weightStr = toString(w); pAction->addPropertyByName("Weight", new CPropertyString(weightStr)); } CObject* children= action->getAttr("Children"); uint32 nb =children->getSize(); for(uint32 i=0;igetValue(i), prefix,scenarioId); if (!tmp) { nlwarning("Error in action %s nb: %u", action->toString("Name").c_str(), i); return 0; } pAction->insertChild(tmp); } return pAction; } bool CServerAnimationModule::queueSession(CAnimationSession* session, bool /* runTest */) { // write scenario rtdata to a file for debugging try { if( WriteScenarioDebugDataToFile ) { // binary COFile output; output.open("outpout.rt.bin"); CObjectSerializerServer serializer( session->RtData.get()); serializer.serial(output); output.flush(); output.close(); } if( WriteScenarioDebugDataToFile ) { // text COFile output; //std::stringstream ss; std::string ss; output.open("outpout.rt"); session->RtData->serialize(ss); output.serialBuffer((uint8*)ss.c_str(), ss.size()); output.flush(); output.close(); } } catch (const std::exception& e ) { nlwarning("Exception while writing debug files %s", e.what() ); } catch(...) { nlwarning("Undefined Exception while writing debug files"); } { requestLoadTable(session); } //std::vector pdrs; session->Pdrs.clear(); if (!makeAnimationSession(session, true)) { nlwarning("R2An: Invalid Session"); return false; } return true; } void CServerAnimationModule::startTest(TSessionId sessionId, CPersistentDataRecord& pdr) { CAnimationSession* session = getSession(sessionId); if (!session) { return ; } uint32 aiInstance = session->AiInstance; nlinfo( "R2An: startTest for sessionId %u in ai instance %u", sessionId.asInt(), aiInstance ); if (! _CharacterControlProxy.isNull() ) { CCharacterControlItfProxy proxy(_CharacterControlProxy); proxy.sendItemDescription(this, sessionId, session->MissionItems); } if (_IOSRingProxy != NULL) { CIOSRingItfProxy proxy(_IOSRingProxy); vector itemInfos; for (uint i=0; iMissionItems.size(); ++i) { R2::TCharMappedInfo itemInfo; itemInfo.setItemSheet(session->MissionItems[i].SheetId); itemInfo.setName(session->MissionItems[i].Name); itemInfos.push_back(itemInfo); } proxy.storeItemNamesForAIInstance(this, aiInstance, itemInfos); } //Use initial sessionId in case of linked session CAiWrapper::getInstance().startTest(session->SessionId, aiInstance, pdr); } void CServerAnimationModule::startAct(TSessionId sessionId, uint32 actId) { nlinfo( "R2An: startAct for sessionId %u", sessionId.asInt() ); bool isLocal = !_Server->useNetwork(); CAnimationSession* animSession = getSession(sessionId); DROP_IF(!animSession, "Invalid Session", return); uint32 aiInstance = animSession->AiInstance; DROP_IF(actId < 1 || animSession->Pdrs.size() <= actId, "Invalid Act", return); if ( !isLocal ) { deactivateEasterEggsFromAct(sessionId, actId); } uint32 currentAct = animSession->CurrentAct; uint32 nextLocationId = animSession->Acts[actId]->LocationId; uint32 currentLoctionId = animSession->Acts[currentAct]->LocationId; bool mustTp = nextLocationId != currentLoctionId; if (animSession->InitialTp ) { animSession->InitialTp = false; mustTp = true; } animSession->CurrentAct = actId; // update entry point IServerEditionModule *svEditionModule = _Server->getEditionModule(); // note: in the future the modules could be in two distinct process, thus they would need an interface/proxy communication BOMB_IF(!svEditionModule, "Server edition module not found", return); // Can not happend CScenario *scenarioSession = svEditionModule->getScenarioById( sessionId ); BOMB_IF(!scenarioSession, NLMISC::toString("Scenario Session not found for session %u", sessionId.asInt()) , return); CObject* scenario = scenarioSession->getHighLevel(); if (!scenario) { nlwarning("ERROR that previously lead to crash"); CAnimationSession* session = getSession(sessionId); if (session) { for(uint32 i = 0; i < session->ConnectedChars.size(); ++i) { nlwarning("Error: connected user %u", session->ConnectedChars[i]); } } if ( scenarioSession->getRtData()) { nlwarning("ERROR: The corrupted scenario has RTDATA but no HL."); } nlwarning("ERROR: you must check the backup : session_%d_?.r2", sessionId.asInt()); BOMB( NLMISC::toString("BIG ERROR: Scenario was not found for session %u, it previously lead to dss crash", sessionId.asInt()), return); return; } double x, y, orient; uint8 season; _Server->getAnimationModule()->getPosition( sessionId, x, y, orient, season ); CFarPosition entryPoint; entryPoint.SessionId = sessionId; entryPoint.PosState.X = (sint32)(x*1000.0); entryPoint.PosState.Y = (sint32)(y*1000.0); entryPoint.PosState.Z = 0; // ?? entryPoint.PosState.Heading = 0; // ?? if (!isLocal) { if (animSession->WeatherValue != animSession->Acts[actId]->WeatherValue) { animSession->setWeatherValue(animSession->Acts[actId]->WeatherValue); } uint32 location = animSession->Acts[actId]->LocationId; season = animSession->Locations[ location ].Season; animSession->setSeason(season); } { NLNET::CMessage msg; CShareClientEditionItfProxy::buildMessageFor_scheduleStartAct(msg, 0, actId, 0) ; _Tasks.addTaskAt(NLMISC::CTime::getLocalTime () + 3000 , new CTaskBroadcast(this, sessionId, msg)); } if (!animSession->Acts[actId]->ActDescription.empty()) { NLNET::CMessage msg; CShareClientEditionItfProxy::buildMessageFor_systemMsg(msg, "BC_ML", "", animSession->Acts[actId]->ActDescription); _Tasks.addTaskAt(NLMISC::CTime::getLocalTime () + 3000 , new CTaskBroadcast(this, sessionId, msg)); } // send position to connected users CAnimationSession* session = getSession(sessionId); BOMB_IF(!session, NLMISC::toString( "Session not found for session %u", sessionId.asInt() ), return); for(uint32 i = 0; i < session->ConnectedChars.size(); ++i) { uint32 charId = session->ConnectedChars[i]; const NLNET::TModuleProxyPtr * pUserModuleProxy = getEditionModule()->getClientProxyPtr(charId); if (pUserModuleProxy) { if ( !_CharacterControlProxy.isNull()) { CCharacterControlItfProxy ccip( _CharacterControlProxy ); ccip.setUserCharActPosition(this, charId, entryPoint, season); } addPioneer(sessionId, charId); if (mustTp) { getEditionModule()->tpToEntryPoint(*pUserModuleProxy, actId); } } else { nlinfo("The user %u has quit the animation session %u before its start", charId, sessionId.asInt()); } } // Use Initial session in case of linked act CAiWrapper::getInstance().startAct(session->SessionId, aiInstance, animSession->Pdrs[actId]); } void CServerAnimationModule::setWeatherValue(TSessionId sessionId, uint16 weatherValue) { if (!_Server->useNetwork()) { nlwarning("simulate setWeatherValue : %d", (int) weatherValue); return; } CAnimationSession *session = getSession(sessionId); if (!session) { nlwarning("R2An: Invalid session %d", sessionId.asInt()); return; } if (weatherValue == session->WeatherValue) return; session->setWeatherValue(weatherValue); } void CServerAnimationModule::setSeasonValue(TSessionId sessionId, uint8 seasonValue) { if (!_Server->useNetwork()) { nlwarning("simulate setWeatherValue : %d", (int) seasonValue); return; } CAnimationSession *session = getSession(sessionId); if (!session) { nlwarning("R2An: Invalid session %d", sessionId.asInt()); return; } if (seasonValue == session->CurrSeason) return; session->setSeason(seasonValue); } bool CServerAnimationModule::translateActToPrimitive(CInstanceMap& components, CAnimationSession* animSession, CObject* act, uint32 actId, NLLIGO::CPrimitives& primDoc) { H_AUTO( translateActToPrimitive ); CRtAct* rtAct = new CRtAct(); animSession->Acts[actId] = rtAct; if ( act->isNumber("LocationId") && act->isString("Name") && act->isString("ActDescription") && act->isString("PreActDescription") ) { rtAct->Name = act->toString("Name"); rtAct->ActDescription = act->toString("ActDescription"); rtAct->PreActDescription = act->toString("PreActDescription"); rtAct->LocationId = static_cast(act->toNumber("LocationId")); } else { nlwarning("Error in session '%u' data Corrupted", animSession->SessionId.asInt()); return false; } nlassert(primDoc.RootNode != NULL); primDoc.RootNode->addPropertyByName("class", new CPropertyString("root")); // AJM primDoc.RootNode->addPropertyByName("name", new CPropertyString("")); // AJM primDoc.RootNode->addPropertyByName("path", new CPropertyString("")); // AJM CPrimitiveContext::instance().CurrentPrimitive = &primDoc; CLigoConfig* cfg = CPrimitiveContext::instance().CurrentLigoConfig; if (cfg) { CR2LigoConfig * r2Cfg = dynamic_cast(cfg); if (r2Cfg) { CR2LigoConfig::TScenarioType type; if (actId == 0) { type = CR2LigoConfig::Base; } else { type = CR2LigoConfig::Act; } primDoc.setAliasStaticPart( r2Cfg->getStaticAliasMapping(animSession->AiInstance, type)); } } CObject* aiStates = act->getAttr("AiStates"); uint32 firstAiState = 0; uint32 lastAiState = aiStates->getSize(); std::string managerPrefix = toString("r2.%04d.", animSession->SessionId.asInt()); std::string prefix = toString("r2_%04d_", animSession->SessionId.asInt()); // Content Manager IPrimitive *npcManager = 0; { IPrimitive *npc_manager = dynamic_cast (CClassRegistry::create ("CPrimZone")); npc_manager->addPropertyByName("class", new CPropertyString("npc_manager")); std::string managerName = managerPrefix + (actId==0? "base": "act"); npc_manager->addPropertyByName("name", new CPropertyString(managerName)); npc_manager->addPropertyByName("ai_type", new CPropertyString("MANAGER")); // AJM npc_manager->addPropertyByName("ai_manager_type", new CPropertyString("NPC")); // AJM npc_manager->addPropertyByName("trigger_type", new CPropertyString("npc_zone")); // AJM primDoc.RootNode->insertChild(npc_manager); CPrimAlias *npc_manager_alias = dynamic_cast (CClassRegistry::create ("CPrimAlias")); npc_manager_alias->addPropertyByName("class", new CPropertyString("alias")); npc_manager_alias->addPropertyByName("name", new CPropertyString("alias")); npc_manager->insertChild(npc_manager_alias); npcManager = npc_manager; } IPrimitive *zoneTriggerManager = 0; // Trigger Manager { IPrimitive *npc_manager = dynamic_cast (CClassRegistry::create ("CPrimZone")); npc_manager->addPropertyByName("class", new CPropertyString("npc_manager")); std::string managerName = managerPrefix + (actId==0? "base.zone_trigger": "act.zone_trigger"); npc_manager->addPropertyByName("name", new CPropertyString(managerName)); npc_manager->addPropertyByName("ai_type", new CPropertyString("MANAGER")); // AJM npc_manager->addPropertyByName("ai_manager_type", new CPropertyString("NPC")); // AJM npc_manager->addPropertyByName("trigger_type", new CPropertyString("npc_zone")); // AJM primDoc.RootNode->insertChild(npc_manager); CPrimAlias *npc_manager_alias = dynamic_cast (CClassRegistry::create ("CPrimAlias")); npc_manager_alias->addPropertyByName("class", new CPropertyString("alias")); npc_manager_alias->addPropertyByName("name", new CPropertyString("alias")); npc_manager->insertChild(npc_manager_alias); zoneTriggerManager = npc_manager; } for ( ; firstAiState != lastAiState ; ++firstAiState) { CObject* aiState = aiStates->getValue(firstAiState); std::string aiMovement = aiState->toString("AiMovement"); IPrimitive *state = 0; if (aiMovement == "follow_route") { state = dynamic_cast (CClassRegistry::create ("CPrimPath")); state->addPropertyByName("class", new CPropertyString("npc_route")); state->addPropertyByName("ai_type", new CPropertyString("NPC_STATE_ROUTE")); // AJM state->addPropertyByName("ai_profile_params", new CPropertyStringArray()); // AJM state->addPropertyByName("vertical_pos", new CPropertyString("auto")); // AJM } else { state = dynamic_cast (CClassRegistry::create ("CPrimZone")); state->addPropertyByName("class", new CPropertyString("npc_zone")); state->addPropertyByName("ai_type", new CPropertyString("NPC_STATE_ZONE")); // AJM state->addPropertyByName("ai_profile_params", new CPropertyStringArray()); // AJM state->addPropertyByName("vertical_pos", new CPropertyString("auto")); // AJM state->addPropertyByName("keywords", new CPropertyStringArray()); // AJM } CAttributeToProperty a2pAiState(aiState, state); if (aiMovement == "follow_route") { a2pAiState.setPrimPath(); } else { a2pAiState.setPrimZone(); } a2pAiState.setAttributeAsStringWithPrefix("Id", "name", prefix); a2pAiState.setAttributeAsString("AiActivity", "ai_activity"); a2pAiState.setAttributeAsString("AiMovement", "ai_movement"); a2pAiState.setAttributeAsStringArray("AiProfilesParams", "ai_profiles_params"); a2pAiState.setAttributeAsStringArray("Keywords", "keywords"); bool isTriggerZone = false; if ( aiState->isNumber("IsTriggerZone") ) { isTriggerZone = static_cast(aiState->toNumber("IsTriggerZone")) == 1; } if (isTriggerZone) { zoneTriggerManager->insertChild(state); } else { npcManager->insertChild(state); } CPrimAlias *state_alias = dynamic_cast (CClassRegistry::create ("CPrimAlias")); state_alias->addPropertyByName("class", new CPropertyString("alias")); state_alias->addPropertyByName("name", new CPropertyString("alias")); state->insertChild(state_alias); CObject* children = aiState->getAttr("Children"); uint32 firstChild(0), lastChild(children->getSize()); for ( ; firstChild != lastChild ; ++firstChild) { CObject* childName = children->getValue(firstChild); CObject* component = components.find(childName->toString()); CObject* oName = component->getAttr("Id"); if (!oName || !oName->isString()) { nlwarning("Error data corrupt: Invalid group"); return false; } std::string fullName = prefix+component->toString("Id"); IPrimitive *npc_group = dynamic_cast (CClassRegistry::create ("CPrimNode")); npc_group->addPropertyByName("class", new CPropertyString("npc_group")); npc_group->addPropertyByName("name", new CPropertyString(prefix+component->toString("Id"))); npc_group->addPropertyByName("ai_type", new CPropertyString("GROUP_NPC")); // AJM if (component->isNumber("AutoSpawn") && component->toNumber("AutoSpawn")==0) { npc_group->addPropertyByName("autoSpawn", new CPropertyString("false")); } else { npc_group->addPropertyByName("autoSpawn", new CPropertyString("true")); // AJM } npc_group->addPropertyByName("grp_keywords", new CPropertyStringArray()); // AJM npc_group->addPropertyByName("count", new CPropertyString("0")); // AJM npc_group->addPropertyByName("bot_keywords", new CPropertyStringArray()); // AJM npc_group->addPropertyByName("bot_equipment", new CPropertyStringArray()); // AJM npc_group->addPropertyByName("bot_chat_parameters", new CPropertyStringArray()); // AJM npc_group->addPropertyByName("bot_sheet_client", new CPropertyString("")); // AJM npc_group->addPropertyByName("bot_vertical_pos", new CPropertyString("auto")); // AJM state->insertChild(npc_group); IPrimitive *npc_group_parameters = 0; { npc_group_parameters = dynamic_cast (CClassRegistry::create ("CPrimNode")); CAttributeToProperty a2p(component, npc_group_parameters); npc_group_parameters->addPropertyByName("class", new CPropertyString("npc_group_parameters")); npc_group_parameters->addPropertyByName("name", new CPropertyString("parameters")); npc_group_parameters->addPropertyByName("ai_type", new CPropertyString("GRP_PARAMETERS")); // AJM a2p.setAttributeAsStringArray("AiProfilParams", "ai_profile_params"); a2p.setAttributeAsStringArray("GrpParameters", "grp_parameters"); } npc_group->insertChild(npc_group_parameters); CPrimAlias *npc_group_alias = dynamic_cast (CClassRegistry::create ("CPrimAlias")); npc_group_alias->addPropertyByName("class", new CPropertyString("alias")); npc_group_alias->addPropertyByName("name", new CPropertyString("alias")); npc_group->insertChild(npc_group_alias); // nlinfo("R2Anim: Group %u %s", npc_group_alias->getFullAlias(), std::string(prefix+component->toString("Id")).c_str()); CRtGrp* rtGrp = new CRtGrp(npc_group_alias->getFullAlias(), component, fullName); animSession->Acts[actId]->RtGrps[rtGrp->Alias] = rtGrp; CObject* npcChild = component->getAttr("Children"); uint32 firstNpc(0), lastNpc(npcChild->getSize()); for ( ; firstNpc != lastNpc ; ++firstNpc) { CObject* objectNpcId = npcChild->getValue(firstNpc); std::string npcId ( objectNpcId->toString() ); CObject* objectNpc = components.find(npcId); if (!objectNpc || !objectNpc->isString("Name") || !objectNpc->isString("ChatParameters") || !objectNpc->isString("Keywords") || !objectNpc->isString("SheetClient") || !objectNpc->isString("Sheet") ) { nlwarning("Error in session '%u' data Corrupted", animSession->SessionId.asInt()); return false; } CPrimPoint *npc_bot = dynamic_cast (CClassRegistry::create ("CPrimPoint")); CAttributeToProperty a2p(objectNpc, npc_bot); a2p.setPrimPoint(); npc_bot->addPropertyByName("class", new CPropertyString("npc_bot")); npc_bot->addPropertyByName("ai_type", new CPropertyString("BOT_NPC")); // AJM npc_bot->addPropertyByName("vertical_pos", new CPropertyString("auto")); // AJM std::string botname = objectNpc->toString("Name"); if (botname.length()==0) { //npc_bot->addPropertyByName("name",new CPropertyString(npcId)); a2p.setAttributeAsStringWithPrefix("Id", "name", prefix); } else { a2p.setAttributeAsString("Name", "name"); } a2p.setAttributeAsStringArray("ChatParameters", "chat_parameters"); a2p.setAttributeAsStringArray("Keywords", "keywords"); std::string sheet_client = objectNpc->toString("SheetClient"); { uint32 len = sheet_client.length(); //9=".creature".length() if(len>9) { std::string right = sheet_client.substr(len-9, 9); if(right == ".creature") sheet_client = sheet_client.substr(0,len-9); } } std::string sheet = objectNpc->toString("Sheet"); { uint32 len = sheet.length(); //9=".creature".length() if(len>9) { std::string right = sheet.substr(len-9, 9); if(right == ".creature") sheet = sheet.substr(0,len-9); } } if (UseSheetClientWithLevel) { static std::string basic="basic_"; static uint32 basicSize = basic.size(); static std::string female = "_female"; static uint32 femaleSize = female.size(); static std::string male = "_male"; static uint32 maleSize = male.size(); uint32 sheetClientSize = sheet_client.size(); // Special case of basic_*_female or basic_*_female if ( (sheetClientSize > basicSize && sheet_client.substr(0, basicSize) == basic) && !sheet.empty() && ( (sheetClientSize > femaleSize && sheet_client.substr(sheetClientSize - femaleSize) == female) || (sheetClientSize > maleSize && sheet_client.substr(sheetClientSize - maleSize) == male) ) ) { std::string::size_type pos = sheet.rfind('_'); if (pos != std::string::npos) { std::string level = sheet.substr(pos); if (level.size() == 3 && 'a' <= level[1] && level[1] <= 'f' && '1' <= level[2] && level[2] <= '4') { sheet_client += level; } } } } /* add an SHEET_CLIENT:SheetClient into the equipment if a alterantiv sheet_client is given */ if (sheet.empty()) { a2p.setAttributeAsStringArray("Equipment", "equipment"); npc_bot->addPropertyByName("sheet_client", new CPropertyString(sheet_client)); } else { CObject* attr = objectNpc->getAttr("Equipment"); if (attr && attr->isString()) { string str = attr->toString(); vector result; NLMISC::splitString(str, "\n", result); result.push_back(NLMISC::toString("CLIENT_SHEET:%s", sheet_client.c_str())); npc_bot->addPropertyByName("equipment", new CPropertyStringArray(result)); } npc_bot->addPropertyByName("sheet_client", new CPropertyString(sheet)); } a2p.setAttributeAsBool("IsStuck", "is_stuck"); npc_group->insertChild(npc_bot); CPrimAlias *npc_bot_alias = dynamic_cast (CClassRegistry::create ("CPrimAlias")); npc_bot_alias->addPropertyByName("class", new CPropertyString("alias")); npc_bot_alias->addPropertyByName("name", new CPropertyString("alias")); npc_bot->insertChild(npc_bot_alias); // nlinfo("R2Anim: Bot %u %s", npc_bot_alias->getFullAlias(), std::string(prefix+objectNpc->toString("Id")).c_str()); uint32 dmProperty = 0; if (objectNpc->isNumber("DmProperty")) { dmProperty = static_cast< uint32 > (objectNpc->toNumber("DmProperty")); } CRtNpc* rtNpc = new CRtNpc(npc_bot_alias->getFullAlias(), objectNpc, npc_group_alias->getFullAlias(), dmProperty); animSession->Acts[actId]->RtNpcs[rtNpc->Alias] = rtNpc; } } } CObject* events = act->getAttr("Events"); uint32 firstEvent=0,lastEvent=0; if(events)lastEvent=events->getSize(); //for each event for(;firstEvent!=lastEvent;++firstEvent) { //create the primitive event and its associated actions IPrimitive* pEvent = getEvent(events->getValue(firstEvent), components, prefix, animSession->SessionId); if (!pEvent) { nlwarning("Error while generating primitive"); return false; } //insert the primitive event CObject* eventObject = events->getValue(firstEvent); bool isTriggerZone = false; if ( eventObject->isNumber("IsTriggerZone") ) { isTriggerZone = static_cast(eventObject->toNumber("IsTriggerZone")) == 1; } if (isTriggerZone) { zoneTriggerManager->insertChild(pEvent); } else { npcManager->insertChild(pEvent); } } animSession->Acts[actId]->WeatherValue = 0; CObject *weatherValue = act->getAttr("WeatherValue"); if (weatherValue) { animSession->Acts[actId]->WeatherValue = (uint16) weatherValue->toNumber(); } // nodeId { CObject* tree = act->getAttr("UserTriggers"); if (!tree || !tree->isTable()) { nlwarning("R2An: Data corrupted"); return false; } uint32 lastnode = tree->getSize(); uint32 firstnode = 0; for (; firstnode != lastnode; ++firstnode) { CObject* node = tree->getValue(firstnode); if (!node || !node->isTable() || !node->isString("Name") || !node->isString("Grp") ) { nlwarning("R2An: Data corrupted"); return false; } CRtUserTrigger userTrigger; userTrigger.Grp = node->toString("Grp"); userTrigger.Name = node->toString("Name"); animSession->Acts[actId]->addUserTrigger(userTrigger); } } return true; } bool CServerAnimationModule::makeAnimationSession(CAnimationSession* animSession, bool /* runTest */) { if( !animSession ) { nlwarning("R2An: Null animation session received!"); return false; } // add session to queue _QueuedSessions.push_back( animSession ); if (!_Server->useNetwork()) { _ReadyForNextSession = true; } nldebug( "R2An: animation session %u received, %u in queue", animSession->SessionId.asInt(), _QueuedSessions.size() ); return true; } bool CServerAnimationModule::doMakeAnimationSession(CAnimationSession* animSession) { H_AUTO( makeAnimationSession ); if (!animSession) { nlwarning("R2An: No animation session to make"); return false; } TSessionId sessionId = animSession->SessionId; bool sessionOk =_Sessions.insert(std::make_pair(sessionId, animSession)).second; if (!sessionOk) { nlwarning("R2An: Can't start test, previous session (%u) not closed and trying to start another one", sessionId.asInt()); return false; } nlinfo("R2An: makeAnimationSession %u", sessionId.asInt()); std::vector primDocs; CObject* rtScenario = animSession->RtData.get(); uint32 aiInstance = animSession->AiInstance; if (!rtScenario) { nlwarning("R2An: Can't make animation session, no RtScenario"); return false; } // build instance map CInstanceMap components("Id"); components.set(animSession->RtData.get());//default + act courant //Create Plot items CObject* plotItems = rtScenario->getAttr("PlotItems"); if (!plotItems || !plotItems->isTable()) { nlwarning("R2An: Data corrupted:session '%u'",sessionId.asInt()); return false; } uint32 lastPlotItem = plotItems->getSize(); uint32 firstPlotItem = 0; for (; firstPlotItem != lastPlotItem; ++firstPlotItem) { CObject* plotItem = plotItems->getValue(firstPlotItem); if (!plotItem || !plotItem->isTable() || !plotItem->isNumber("SheetId") || !plotItem->isString("Name") || !plotItem->isString("Description") || !plotItem->isString("Comment") ) { nlwarning("R2An: Data corrupted:session '%u'",sessionId.asInt()); return false; } uint32 sheetIdAsInt = static_cast(plotItem->toNumber("SheetId")); CSheetId plotItemSheetId( sheetIdAsInt ); if ( !CRingAccess::getInstance().isPlotItemSheetId(plotItemSheetId) ) { nlwarning("!!!!!!!!!!!!"); nlwarning("!!!!!!!!!!!! Someone is trying to hack us?"); nlwarning("!!!!!!!!!!!!"); nlwarning("ERROR: a session %u has faked a Plot item sheetId, or new plot items have been added. SheetId='%s' sheetIdAsInt=%u", sessionId.asInt(), plotItemSheetId.toString().c_str(), sheetIdAsInt); std::vector::const_iterator first(animSession->ConnectedChars.begin()), last(animSession->ConnectedChars.end()); nlwarning("There is %u connected Chars:", animSession->ConnectedChars.size()); for ( ; first != last ; ++first) { nlwarning("CharId = %u UserId(%u)", *first, *first >> 4); } nlwarning("!!!!!!!!!!!!"); nlwarning("!!!!!!!!!!!!"); return false; } TMissionItem missionItem; missionItem.SheetId = plotItemSheetId; missionItem.Name = ucstring::makeFromUtf8( plotItem->toString("Name") ); missionItem.Description = ucstring::makeFromUtf8( plotItem->toString("Description") ); missionItem.Comment = ucstring::makeFromUtf8( plotItem->toString("Comment") ); animSession->MissionItems.push_back(missionItem); } // LocationId { CObject* locations = rtScenario->getAttr("Locations"); if (!locations || !locations->isTable()) { nlwarning("R2An: Data corrupted"); return false; } uint32 lastLocation = locations->getSize(); uint32 firstLocation = 0; for (; firstLocation != lastLocation; ++firstLocation) { CObject* location = locations->getValue(firstLocation); if (!location || !location->isTable() || !location->isNumber("Season") || !location->isString("Island") || !location->isString("EntryPoint") ) { nlwarning("R2An: Data corrupted:session '%u'",sessionId.asInt()); return false; } CRtLocation locationItem; locationItem.Season = static_cast(location->toNumber("Season")); locationItem.Island = location->toString("Island"); locationItem.EntryPoint = location->toString("EntryPoint"); animSession->Locations.push_back(locationItem); } } //Translate Act to Primitive CObject* acts = rtScenario->getAttr("Acts"); uint32 firstAct = 0; uint32 lastAct = acts->getSize(); primDocs.resize(lastAct); animSession->Acts.resize(lastAct); for (; firstAct != lastAct ; ++firstAct) { //std::string key = acts->getKey(firstAct); CObject* act= acts->getValue(firstAct); if (!act) { nlwarning("R2An: Can't make animation session, invalid RtAct"); return false; } bool ok = translateActToPrimitive(components, animSession, act, firstAct, primDocs[firstAct] ); //TODO if (!ok) { nlwarning("R2An: Data corrupted:session '%u'",sessionId.asInt()); return false; } } uint32 first(0), last(primDocs.size()); animSession->Pdrs.resize(last); for ( ; first != last; ++first) { H_AUTO( translatePrimitivesToPdr ); // translatePrimitivesToPdr; //first <=> actId CPrimitives *primDoc = &primDocs[first]; std::string streamFileName = ""; if (first==0) { streamFileName= toString("r2.%04d.base.primitive", aiInstance); } else { streamFileName= toString("r2.%04d.act.primitive", aiInstance); } if (WriteScenarioDebugDataToFile) // Debug { nldebug("writing xml primitive file %s", toString("r2.%04u.act%u.primitive", sessionId.asInt(), first).c_str()); saveXmlPrimitiveFile(*primDoc, toString("r2.%04u.act%u.primitive", sessionId.asInt(), first)); // save for debug use } CAiWrapper::getInstance().primsToPdr(primDoc, streamFileName, animSession->Pdrs[first]); if (WriteScenarioDebugDataToFile) // Debug { string tmp = toString("r2.%04u.act%u.pdr.xml", sessionId.asInt(), first); nldebug( "writing xml pdr file %s", tmp.c_str() ); animSession->Pdrs[first].writeToTxtFile( tmp.c_str() ); } } // send start_test to the AI service startTest(sessionId, animSession->Pdrs.front()); // Update animator session info { std::vector::const_iterator first(animSession->ConnectedChars.begin()), last(animSession->ConnectedChars.end()); for ( ; first != last ; ++first) { bool inserted = _CharSessions.insert(std::make_pair(*first, sessionId)).second; if (!inserted) { if (_CharSessions[*first] != sessionId) { TSessionId previousCharSessionId = _CharSessions[*first]; CAnimationSession* previousSession = getSession( previousCharSessionId ); BOMB_IF(!previousSession ,"BUG: Failed to get animation session object with id "+NLMISC::toString(previousCharSessionId.asInt()), return false); std::vector & chars = previousSession->ConnectedChars; chars.erase(std::remove(chars.begin(), chars.end(), *first ), chars.end()); } _CharSessions[*first] = sessionId; } nlinfo("R2An: Char %u is connected to session %u as animator / tester(edition)", *first, sessionId.asInt()); } } // Not linked session. so we need to tp at first start (in order to avoid to be stuck at the // entry point of the scenario if the player has not enought ring point if (_Server->getEditionModule()->getLinkedSessionId(sessionId) == TSessionId(0) && !_Server->getEditionModule()->isEditingSession(sessionId) ) { animSession->InitialTp = true; } animSession->StartingAct = true; // start the first act 0.5 second after the creation of AINSTANCE to be sure that setPionerRight is done after the creation of the instance _Tasks.addTask( new CTaskStartAct( NLMISC::CTime::getLocalTime () + 500, this, sessionId, animSession->InitialAct, false)); //startAct(sessionId, animSession->InitialAct); return true; } bool CServerAnimationModule::getConnectedChars(TSessionId sessionId, std::vector& chars) const { CAnimationSession* previousSession = getSession( sessionId ); if (!previousSession) { return false;} chars = previousSession->ConnectedChars; return true; } bool CServerAnimationModule::stopTestImpl(TSessionId sessionId, uint32 & lastAct) { bool useNetwork = _Server->useNetwork(); CAnimationSession* session = getSession( sessionId ); if (!session) { nlwarning("R2An: Error can not stop a nonexistent animation %u", sessionId.asInt()); return false; } uint32 aiInstance = session->AiInstance; requestUnloadTable(sessionId); requestReleaseChannels(sessionId); if ( !_CharacterControlProxy.isNull()) { CCharacterControlItfProxy proxy(_CharacterControlProxy); proxy.scenarioEnded(this, sessionId); } if (useNetwork) { session->setWeatherValue(0); // back to auto-weather } // Use initial session id in case of linked act CAiWrapper::getInstance().stopTest(session->SessionId, aiInstance); std::vector chars = session->ConnectedChars; std::vector::iterator first(chars.begin()), last(chars.end()); for ( ; first != last ; ++first) { TCharSessions::iterator erased(_CharSessions.find(*first)); if (erased != _CharSessions.end()) { _CharSessions.erase(erased); } } chars.clear(); TSessions::iterator found = _Sessions.find(sessionId); if (found == _Sessions.end()) { TSessionId remappedSession = _Server->getEditionModule()->getLinkedSessionId(sessionId); found = _Sessions.find(remappedSession); } _Sessions.erase( found ); lastAct = session->CurrentAct; delete session; return true; } bool CServerAnimationModule::stopTest(TSessionId sessionId, uint32 & lastAct) { CAnimationSession* session = getSession( sessionId ); if (!session) { nlinfo("R2An: trying to stop a nonexistent animation %u (will try later)", sessionId.asInt()); _Tasks.addTaskAt( NLMISC::CTime::getLocalTime() + 1000, new CTaskStopTest(this, sessionId)); return false; } return stopTestImpl(sessionId, lastAct); } void CServerAnimationModule::onModuleUpdate() { H_AUTO(CServerAnimationModule_onModuleUpdate); bool queuedSession = _ReadyForNextSession && !_QueuedSessions.empty(); if (queuedSession) { CAnimationSession *animSession = _QueuedSessions.front(); _QueuedSessions.pop_front(); doMakeAnimationSession( animSession ); nldebug( "R2An: animation session %u processed, %u in queue", animSession->SessionId.asInt(), _QueuedSessions.size() ); } NLMISC::TTime now = NLMISC::CTime::getLocalTime(); _Tasks.execute(now); } void CServerAnimationModule::onModuleUp(NLNET::IModuleProxy *senderModuleProxy) { std::string moduleName = senderModuleProxy->getModuleClassName(); // send back a message to the client to open the firewall if ( moduleName == "StringManagerModule") { _StringManagerProxy = senderModuleProxy; nlinfo("StringManagerModule identified!!"); } else if ( moduleName == "CharacterControl") { _CharacterControlProxy = senderModuleProxy; } else if ( moduleName == "IOSRingModule") { _IOSRingProxy= senderModuleProxy; } } void CServerAnimationModule::onModuleDown(NLNET::IModuleProxy *senderModuleProxy) { std::string moduleName = senderModuleProxy->getModuleClassName(); if ( moduleName == "StringManagerModule") { _StringManagerProxy = NULL; nlinfo("StringManagerModule disconnected!"); } else if ( moduleName == "CharacterControl") { _CharacterControlProxy = NULL; } else if ( moduleName == "ClientEditionModule") // a client has disconnected { uint32 charId; NLMISC::CEntityId eid; std::string userPriv; std::string extendedPriv; bool ok = getCharInfo(senderModuleProxy, charId, eid, userPriv, extendedPriv); if (!ok) { return ; } TSessionId sessionId = getSessionIdByCharId(charId); { CAnimationSession* session = getSession(sessionId); if (session) { std::vector& connectChars = session->ConnectedChars; std::vector::iterator found ( std::find(connectChars.begin(), connectChars.end(), charId) ); if (found != connectChars.end()) { std::map incarningBots; std::map talkingAsBots; session->IncarningBots.getBots(eid, incarningBots); session->TalkingAsBots.getBots(eid, talkingAsBots); { std::map::const_iterator first(talkingAsBots.begin()), last(talkingAsBots.end()); for (; first != last; ++first) { removeTalkingAsPlayer(sessionId, first->second, eid); } } { std::map::const_iterator first(incarningBots.begin()), last(incarningBots.end()); for (; first != last; ++first) { removeIncarningPlayer(sessionId, first->second, eid); } } connectChars.erase(found); session->IncarningBots.removeChar(eid); session->TalkingAsBots.removeChar(eid); } { TCharSessions::iterator found( _CharSessions.find(charId) ); if (found != _CharSessions.end()) { sessionId = found->second; _CharSessions.erase(found); } } } } } else if (senderModuleProxy == _IOSRingProxy) { _IOSRingProxy = NULL; } } void CServerAnimationModule::stopAct(TSessionId sessionId) { nlinfo( "R2An: stopAct for sessionId %u", sessionId.asInt() ); if (!_Server->useNetwork()) { nlwarning("simulate stopAct"); return; } CAnimationSession* session = getSession(sessionId); if (!session) return; //nlwarning CurrentAct == 0 deactivateEasterEggsFromAct(sessionId, session->CurrentAct); session->CurrentAct = 0; uint32 aiInstance = session->AiInstance; // Use initial session in case of linked act CAiWrapper::getInstance().stopAct(session->SessionId, aiInstance); } bool CServerAnimationModule::getPosition(TSessionId sessionId, double& x, double& y, double& orient, uint8& season, uint32 actIndex) { CAnimationSession *animSession = getSession( sessionId ); if(! animSession) { return false; } // normal case when getStart position while creating scenario uint32 currentAct = animSession->CurrentAct; if (actIndex != 0) { currentAct = actIndex; } if (currentAct == 0) { currentAct = 1; } DROP_IF(currentAct >= animSession->Acts.size(), "Error: invalide act", return false); uint32 locationId = animSession->Acts[currentAct]->LocationId; DROP_IF(locationId >= animSession->Locations.size(), "Error: invalide location", return false); CRtLocation & location = animSession->Locations[locationId]; CScenarioEntryPoints& epManager = CScenarioEntryPoints::getInstance(); CScenarioEntryPoints::CCompleteIsland * island = epManager.getIslandFromId(location.Island); DROP_IF(!island, "No Island.", return false); CScenarioEntryPoints::CShortEntryPoint *entryPoint = epManager.getEntryPointFromIds(location.Island, location.EntryPoint); if (!entryPoint) { entryPoint = epManager.getEntryPointFromIds(location.Island, island->EntryPoints[0].Location); //Evil Hack must be removed } DROP_IF(!entryPoint, "No EntryPoint.", return false); x = entryPoint->X; y = entryPoint->Y; orient = 0; season = location.Season; return true; } void CServerAnimationModule::getStartParams(NLNET::IModuleProxy * /* sender */, uint32 charId, TSessionId lastStoredSessionId) { _Server->getEditionModule()->getStartParams(charId, lastStoredSessionId); } void CServerAnimationModule::askSetUserCharActPosition( NLNET::IModuleProxy * /* sender */, uint32 charId ) { // get entry point double x, y, orient; uint8 season; TSessionId sessionId = _Server->getAdminModule()->getSessionIdByCharId(charId ); bool ok = _Server->getAdminModule()->getPosition( sessionId, x, y, orient, season ); if (!ok) { return; } CFarPosition entryPoint; entryPoint.SessionId = sessionId; entryPoint.PosState.X = (sint32)(x*1000.0); entryPoint.PosState.Y = (sint32)(y*1000.0); entryPoint.PosState.Z = 0; // ?? entryPoint.PosState.Heading = 0; // ?? CCharacterControlItfProxy ccip( _CharacterControlProxy ); ccip.setUserCharActPosition(this, charId, entryPoint, season); } CAnimationSession* CServerAnimationModule::getSession(TSessionId sessionId) const { if (sessionId.asInt() == 0) { return 0; } TSessions::const_iterator session = _Sessions.find(sessionId); if (session == _Sessions.end()) { TSessionId remapped = _Server->getEditionModule()->getLinkedSessionId(sessionId); if (remapped.asInt() == 0) { return 0; } session = _Sessions.find(remapped); } if (session == _Sessions.end()) { return 0; } return session->second; } void CServerAnimationModule::connectAnimationModePlay(NLNET::IModuleProxy* proxy) { CShareClientEditionItfProxy client(proxy); //getEditionModule()->tpToEntryPoint(proxy, 0); client.onAnimationModePlayConnected(this); } TSessionId CServerAnimationModule::getSessionIdByCharId(TCharId charId) const { TCharSessions::const_iterator charSessionFound( _CharSessions.find(charId) ); if (charSessionFound == _CharSessions.end()) { return (TSessionId)0; } return charSessionFound->second; } CAnimationSession* CServerAnimationModule::getSessionByCharId(TCharId charId) const { if (charId == 0) return NULL; return getSession(getSessionIdByCharId(charId)); } void CServerAnimationModule::addPioneer( TSessionId sessionId, TCharId charId) { CAnimationSession* session = getSession(sessionId); if (!session) return; bool isLocal = !_Server->useNetwork(); std::vector::const_iterator found(std::find(session->ConnectedChars.begin(), session->ConnectedChars.end(), charId)); bool added = false; if (found == session->ConnectedChars.end()) { session->ConnectedChars.push_back(charId); added = true; } // Warning the player can receive an addPioneer Message before it client Module went down { bool inserted =_CharSessions.insert(std::make_pair(charId, sessionId)).second; if (!inserted) { // lookup the previous session id and make sure that we have a session for this id TSessionId previousCharSessionId = _CharSessions[charId]; // disconnect from previous scenario if (previousCharSessionId != sessionId) { CAnimationSession* previousSession = getSession(previousCharSessionId); if (previousSession != session) { std::vector & chars = previousSession->ConnectedChars; chars.erase(std::remove(chars.begin(), chars.end(), charId ), chars.end()); } } _CharSessions[charId] = sessionId; } } nlinfo("R2An: Char %u is connected as animator", charId); // update weather for that char if ( !isLocal ) { session->sendWeatherValueToChar(charId, session->WeatherValue); } const TModuleProxyPtr* clientProxyPtr = getEditionModule()->getClientProxyPtr(charId); if (!clientProxyPtr) { nlwarning("A pioneer has just entered in a session %u but has no proxy %u", sessionId.asInt(), charId); return; } getEditionModule()->updateCharPioneerRight(charId); // TODO send this informations only if client askMissionItemsDescription(*clientProxyPtr); askActPositionDescriptions(*clientProxyPtr); askUserTriggerDescriptions(*clientProxyPtr); askTalkingAsListUpdate(*clientProxyPtr); askIncarnatingListUpdate(*clientProxyPtr); askUpdateScenarioHeader(*clientProxyPtr); CShareClientEditionItfProxy proxy(*clientProxyPtr); proxy.onCurrentActIndexUpdated(this, session->CurrentAct); if (session->CharacternValidePosition.find(charId) == session->CharacternValidePosition.end()) { session->CharacternValidePosition.insert(charId); } if (added) { uint32 actId = session->CurrentAct; if (session->Acts.size() > actId && !session->Acts[actId]->ActDescription.empty()) { CShareClientEditionItfProxy proxy(*clientProxyPtr); proxy.systemMsg(this, "BC_ML", "", session->Acts[actId]->ActDescription); } } } void CServerAnimationModule::onDssTarget( IModuleProxy *senderModuleProxy, const std::vector & params) { uint32 charId; NLMISC::CEntityId eid; std::string userPriv; std::string extendedPriv; bool ok = checkSecurityInfo(senderModuleProxy, charId, eid, userPriv, extendedPriv); if (!ok) { return ; } DROP_IF(!_CharacterControlProxy, "Try to send message to EGS must he is down", return); CCharacterControlItfProxy proxy(_CharacterControlProxy); proxy.sendCharTargetToDss(this, eid, params); } /*** ** Called when the DM stops talking as a NPC or Incarning a NPC. **/ void CServerAnimationModule::stopTalk(const NLMISC::CEntityId &eid, const NLMISC::CEntityId &/* creatureId */, TDataSetRow entityRowId) { TCharId charId = static_cast(eid.getShortId()); const NLNET::TModuleProxyPtr * foundModule = getEditionModule()->getClientProxyPtr(charId); BOMB_IF(foundModule==NULL, "stopTalk failed because getClientProxyPtr() returned NULL for entity "+eid.toString(),return); CAnimationSession* session = getSessionByCharId(charId); if (!session) { return; } TModuleId moduleId = (*foundModule)->getModuleProxyId(); CMessage msg("stopTalk"); msg.serial(moduleId); msg.serial(entityRowId); _StringManagerProxy->sendModuleMessage(this,msg); } void CServerAnimationModule::stopIncarn(const NLMISC::CEntityId &eid, const NLMISC::CEntityId &creatureId) { CAiWrapper::getInstance().stopControlNpc(eid, creatureId); } CRtNpc* CServerAnimationModule::getNpcByAlias(TSessionId sessionId, TAIAlias alias) const { CAnimationSession* session = getSession(sessionId); if (!session) { return 0; } if (session->Acts.empty()) { return 0; } { CRtAct::TRtNpcs::const_iterator found( session->Acts[0]->RtNpcs.find(alias) ); if (found != session->Acts[0]->RtNpcs.end()) { return found->second; } } uint32 currentAct = session->CurrentAct; if (currentAct != 0) { CRtAct::TRtNpcs::const_iterator found( session->Acts[currentAct]->RtNpcs.find(alias) ); if (found != session->Acts[currentAct]->RtNpcs.end()) { return found->second; } } return 0; } void CServerAnimationModule::stopControlNpcs(TCharId charId) { const NLNET::TModuleProxyPtr * foundModule = getEditionModule()->getClientProxyPtr(charId); if (!foundModule) { return; } NLNET::TModuleProxyPtr clientProxyPtr = *foundModule; NLMISC::CEntityId clientEid; std::string userPriv; std::string extendedPriv; bool ok = checkSecurityInfo(clientProxyPtr, charId, clientEid, userPriv, extendedPriv); if (!ok) { return; } TSessionId sessionId = getSessionIdByCharId(charId); CAnimationSession* session = getSession(sessionId); if (!session) { return; } // Remove Incarn { std::map entities; session->IncarningBots.getBots(charId, entities); { std::map ::const_iterator botEid(entities.begin()), last(entities.end()); for (; botEid != last; ++botEid) { if (isIncarnedByPlayer(botEid->second, clientEid)) { removeIncarningPlayer(sessionId, botEid->second, clientEid); stopIncarn(clientEid, botEid->second); } } } } // Remove Talks as { std::map entities; session->TalkingAsBots.getBots(charId, entities); { std::map ::const_iterator botEid(entities.begin()), last(entities.end()); for (; botEid != last; ++botEid) { if (isTalkingAs(botEid->second, clientEid)) { TOwnedEntities::iterator iter = _TalkedAsEntities.find(botEid->second); if (iter != _TalkedAsEntities.end()) { stopTalk(clientEid, botEid->second, iter->second.CreatureRowId); removeTalkingAsPlayer(sessionId, botEid->second, clientEid); } } } } } } void CServerAnimationModule::askUpdateScenarioHeader(NLNET::IModuleProxy *clientProxyPtr) { uint32 charId; NLMISC::CEntityId clientEid; std::string userPriv; std::string extendedPriv; bool ok = checkSecurityInfo(clientProxyPtr, charId, clientEid, userPriv, extendedPriv); if (!ok) { return; } TSessionId sessionId = getSessionIdByCharId(charId); CAnimationSession* session = getSession(sessionId); if (!session) { return; } CShareClientEditionItfProxy proxy(clientProxyPtr); proxy.updateScenarioHeader(this, session->ScenarioHeader); } void CServerAnimationModule::askIncarnatingListUpdate(NLNET::IModuleProxy *clientProxyPtr) { uint32 charId; NLMISC::CEntityId clientEid; std::string userPriv; std::string extendedPriv; bool ok = checkSecurityInfo(clientProxyPtr, charId, clientEid, userPriv, extendedPriv); if (!ok) { return; } TSessionId sessionId = getSessionIdByCharId(charId); CAnimationSession* session = getSession(sessionId); if (!session) { return; } std::map entities; session->IncarningBots.getBots(charId, entities); std::map::const_iterator first(entities.begin()), last(entities.end()); std::vector botsId; for (; first!= last ; ++first) { TOwnedEntities::iterator found = _IncarnedEntities.find(first->second); if (found != _IncarnedEntities.end()) { TAIAlias alias = found->second.CreatatureAlias; CRtNpc* npc = getNpcByAlias(sessionId, alias); if (npc) { botsId.push_back(first->first); botsId.push_back(npc->NameId); } } } CShareClientEditionItfProxy proxy(clientProxyPtr); proxy.updateIncarningList(this, botsId); } void CServerAnimationModule::askTalkingAsListUpdate(NLNET::IModuleProxy *clientProxyPtr) { uint32 charId; NLMISC::CEntityId clientEid; std::string userPriv; std::string extendedPriv; bool ok = checkSecurityInfo(clientProxyPtr, charId, clientEid, userPriv, extendedPriv); if (!ok) { return; } TSessionId sessionId = getSessionIdByCharId(charId); CAnimationSession* session = getSession(sessionId); if (!session){ return; } std::map entities; session->TalkingAsBots.getBots(charId, entities); std::map::const_iterator first(entities.begin()), last(entities.end()); std::vector botsId; for (; first!= last ; ++first) { TOwnedEntities::iterator found = _TalkedAsEntities.find(first->second); if (found != _TalkedAsEntities.end()) { TAIAlias alias = found->second.CreatatureAlias; CRtNpc* npc = getNpcByAlias(sessionId, alias); if (npc) { botsId.push_back(first->first); botsId.push_back(npc->NameId); } } } CShareClientEditionItfProxy proxy(clientProxyPtr); proxy.updateTalkingAsList(this, botsId); } void CServerAnimationModule::updateIncarningList(TSessionId /* sessionId */, uint32 charId) { const NLNET::TModuleProxyPtr * foundModule = getEditionModule()->getClientProxyPtr(charId); if (foundModule) { askIncarnatingListUpdate(*foundModule); } } void CServerAnimationModule::updateTalkingAsList(TSessionId /* sessionId */, uint32 charId) { const NLNET::TModuleProxyPtr * foundModule = getEditionModule()->getClientProxyPtr(charId); if (foundModule) { askTalkingAsListUpdate(*foundModule); } } bool CServerAnimationModule::setIncarningPlayer(TSessionId sessionId, const NLMISC::CEntityId& creatureId, const NLMISC::CEntityId& eid, TDataSetRow entityRowId, TAIAlias alias) { bool ok = true; CAnimationSession* session = getSession(sessionId); if (!session) { return false; } ok = session->IncarningBots.add( eid, creatureId); if (!ok) { return false; } TOwnedEntities::iterator iter = _IncarnedEntities.find(creatureId); if (iter == _IncarnedEntities.end()) { COwnedCreatureInfo info; info.PlayerIds.push_back(eid); info.CreatureRowId = entityRowId; info.CreatatureAlias = alias; _IncarnedEntities[creatureId] = info; } else { _IncarnedEntities[creatureId].PlayerIds.push_back(eid); } updateIncarningList(sessionId, static_cast(eid.getShortId()) ); return true; } bool CServerAnimationModule::setTalkingAsPlayer(TSessionId sessionId, const NLMISC::CEntityId& creatureId, const NLMISC::CEntityId& eid, TDataSetRow entityRowId, TAIAlias alias) { bool ok = true; CAnimationSession* session = getSession(sessionId); if (!session) { return false; } ok = session->TalkingAsBots.add( eid, creatureId); if (!ok) { return false; } TOwnedEntities::iterator iter = _TalkedAsEntities.find(creatureId); if (iter == _TalkedAsEntities.end()) { COwnedCreatureInfo info; info.PlayerIds.push_back(eid); info.CreatureRowId = entityRowId; info.CreatatureAlias = alias; _TalkedAsEntities[creatureId] = info; } else { _TalkedAsEntities[creatureId].PlayerIds.push_back(eid); } updateTalkingAsList(sessionId, uint32(eid.getShortId())) ; return true; } bool CServerAnimationModule::isIncarnedByPlayer(const NLMISC::CEntityId& creatureId, const NLMISC::CEntityId& eid) const { TOwnedEntities::const_iterator iter = _IncarnedEntities.find(creatureId); if (iter == _IncarnedEntities.end()) { return false; } COwnedCreatureInfo info = (*iter).second; std::vector::const_iterator eidIt(info.PlayerIds.begin()), last(info.PlayerIds.end()); for (; eidIt != last; ++eidIt) { if ((*eidIt) == eid) { return true; } } return false; } bool CServerAnimationModule::isTalkingAs(const NLMISC::CEntityId& creatureId, const NLMISC::CEntityId& eid) const { TOwnedEntities::const_iterator iter = _TalkedAsEntities.find(creatureId); if (iter == _TalkedAsEntities.end()) { return false; } COwnedCreatureInfo info = (*iter).second; std::vector::const_iterator eidIt(info.PlayerIds.begin()), last(info.PlayerIds.end()); for (; eidIt != last; ++eidIt) { if ((*eidIt) == eid) { return true; } } return false; } void CServerAnimationModule::removeTalkingAsPlayer(TSessionId sessionId, const NLMISC::CEntityId& creatureId, const NLMISC::CEntityId& eid) { TOwnedEntities::iterator iter = _TalkedAsEntities.find(creatureId); COwnedCreatureInfo info = (*iter).second; std::vector::iterator eidIt(info.PlayerIds.begin()), last(info.PlayerIds.end()); for (; eidIt != last; ++eidIt) { if ((*eidIt) == eid) { info.PlayerIds.erase(eidIt); break; } } if (info.PlayerIds.empty()) { _TalkedAsEntities.erase(iter); } CAnimationSession* session = getSession(sessionId); if (!session) { return ; } session->TalkingAsBots.remove( eid, creatureId); updateTalkingAsList(sessionId, uint32( eid.getShortId())); } void CServerAnimationModule::removeIncarningPlayer(TSessionId sessionId, const NLMISC::CEntityId& creatureId, const NLMISC::CEntityId& eid) { TOwnedEntities::iterator iter = _IncarnedEntities.find(creatureId); COwnedCreatureInfo info = (*iter).second; std::vector::iterator eidIt(info.PlayerIds.begin()), last(info.PlayerIds.end()); for (; eidIt != last; ++eidIt) { if ((*eidIt) == eid) { info.PlayerIds.erase(eidIt); break; } } if (info.PlayerIds.empty()) { _IncarnedEntities.erase(iter); } CAnimationSession* session = getSession(sessionId); if (!session) { return ; } session->IncarningBots.remove(eid, creatureId); updateIncarningList(sessionId, uint32(eid.getShortId()) ); } void CServerAnimationModule::updateAnimationProperties(NLNET::IModuleProxy *senderModuleProxy, const NLMISC::CEntityId & eid, CRtNpc * rtNpc, CRtGrp* rtGrp) { CMessage msg("NPC_APROP"); //Animation Properties if (eid == NLMISC::CEntityId::Unknown || rtNpc == 0) { uint32 zero = 0; msg.serial(zero); senderModuleProxy->sendModuleMessage(this, msg); return; } uint32 animationProp = rtNpc->NpcAnimationProp; const NLMISC::CEntityId & creatureId = rtNpc->EntityId; if (animationProp & CAnimationProp::Controlable && rtNpc->Alived) { if (isIncarnedByPlayer(creatureId, eid)) { animationProp |= CAnimationProp::Controled; } } if (animationProp & CAnimationProp::Speaking && rtNpc->Alived) { if (isTalkingAs(creatureId, eid)) { animationProp |= CAnimationProp::SpeakedAs; } } if (!rtNpc->Alived) { animationProp &= ~CAnimationProp::Alive; } if (rtGrp) { CObjectTable* children = rtGrp->ObjectData->toTable("Children"); if (children->getSize() > 1) { animationProp |= CAnimationProp::Grouped; } } msg.serial(animationProp); senderModuleProxy->sendModuleMessage(this, msg); return; } void CServerAnimationModule::onCharTargetReceived( NLNET::IModuleProxy *senderModuleProxy, const NLMISC::CEntityId& eid, const NLMISC::CEntityId&creatureId, TAIAlias alias, TDataSetRow entityRowId, const ucstring& /* ucName */, uint32 nameId, const std::vector & param, bool alived) { std::vector args(param); TCharId charId = static_cast(eid.getShortId()); const NLNET::TModuleProxyPtr * foundModule = getEditionModule()->getClientProxyPtr(charId); DROP_IF(!foundModule, NLMISC::toString("Invalid Char %u", charId), return); if (!alived || entityRowId == TDataSetRow() || alias == 0 || creatureId == CEntityId::Unknown ) { updateAnimationProperties(* foundModule, CEntityId::Unknown, 0, 0); return; } TCharSessions::const_iterator charSessionFound( _CharSessions.find(charId) ); DROP_IF(charSessionFound == _CharSessions.end(), NLMISC::toString("Invalid Session for Char %u", charId), return); TSessionId sessionId = charSessionFound->second; CAnimationSession* session = getSession(sessionId); DROP_IF(session->Acts.empty() , NLMISC::toString("Invalid Session %u for Char %u (No act available)",charSessionFound->second.asInt(), charId), return); if ( session->Acts.empty() ) { return; } NLMISC::CEntityId oldTargetId = NLMISC::CEntityId::Unknown; CAnimationSession::TCharacterInfos::iterator charInfos = session->CharacterInfos.find(charId); if (charInfos != session->CharacterInfos.end()) { oldTargetId = charInfos->second.TargetId; } session->CharacterInfos[charId].TargetId = creatureId; // Add to targeted entities if necessary { COwnedCreatureInfo tmp; std::pair < TOwnedEntities::iterator, bool> ret = _TargetedEntities.insert( std::make_pair(creatureId, tmp)); TOwnedEntities::iterator entity = ret.first; bool firstTime = ret.second; std::vector& container = entity->second.PlayerIds; std::vector::iterator it = std::find(container.begin(), container.end(), eid); if (it == container.end()){ container.push_back(eid); } if (firstTime) { CAiWrapper::getInstance().askBotDespawnNotification(creatureId, alias); } } if (oldTargetId != NLMISC::CEntityId::Unknown && oldTargetId != creatureId) { CAnimationSession::TCharacterInfos::iterator charInfos = session->CharacterInfos.find(charId); if (charInfos != session->CharacterInfos.end()) { NLMISC::CEntityId oldTargetId = charInfos->second.TargetId; TOwnedEntities::iterator oldTargetIt = _TargetedEntities.find(oldTargetId); if (oldTargetIt != _TargetedEntities.end()) { std::vector& container = oldTargetIt->second.PlayerIds; std::vector::iterator it = std::find(container.begin(), container.end(), eid); if (it != container.end()) { container.erase(it); } if (container.empty()) { _TargetedEntities.erase(oldTargetIt); } } } } uint32 SelectedNpcAct = 0; CRtAct::TRtNpcs::const_iterator npcFound ( session->Acts[0]->RtNpcs.find(alias) ); CRtNpc * rtNpc = 0; std::string name; if (npcFound == session->Acts[0]->RtNpcs.end()) { npcFound = session->Acts[ session->CurrentAct ]->RtNpcs.find(alias); if (npcFound != session->Acts[ session->CurrentAct ]->RtNpcs.end()) { rtNpc = npcFound->second.getPtr(); name = rtNpc->ObjectData->getAttr("Name")->toString(); SelectedNpcAct= session->CurrentAct; } } else { rtNpc = npcFound->second.getPtr(); name = rtNpc->ObjectData->getAttr("Name")->toString(); } // Try to target an invalid if (!rtNpc) { return; } CRtAct::TRtGrps & rtGrps = session->Acts[ SelectedNpcAct ]->RtGrps; CRtAct::TRtGrps::const_iterator grpFound = rtGrps.find(rtNpc->GrpAlias); CRtGrp *rtGrp = 0; if (grpFound != rtGrps.end()) { rtGrp = grpFound->second.getPtr(); } //update data rtNpc->EntityId = creatureId; rtNpc->DataSetRow = entityRowId; rtNpc->NameId = nameId; rtNpc->Alived = alived; uint32 animationProp = rtNpc->NpcAnimationProp; if (args.empty()) { updateAnimationProperties(*foundModule, eid, rtNpc, rtGrp); return; } if ( (animationProp & CAnimationProp::Spawnable) ) { if (args[0] == "DESPAWN_NPC") { if (rtNpc->EntityId != NLMISC::CEntityId::Unknown) { CAiWrapper::getInstance().despawnEntity(rtNpc->EntityId, alias); } return; } } if ( (animationProp & CAnimationProp::Alive) ) { if (args[0] == "ADD_HP") { CAiWrapper::getInstance().setHPLevel(rtNpc->EntityId, alias, 1); return; } if (args[0] == "KILL_NPC" && alived) { CAiWrapper::getInstance().setHPLevel(rtNpc->EntityId, alias, 0); return; } if (args[0] == "ADD_HP") { CAiWrapper::getInstance().setHPLevel(rtNpc->EntityId, alias, 1); return; } if (args[0] == "GRP_KILL" && alived) { CAiWrapper::getInstance().setGrpHPLevel(rtNpc->EntityId, alias, 0); return; } if (args[0] == "GRP_HEAL") { CAiWrapper::getInstance().setGrpHPLevel(rtNpc->EntityId, alias, 1); return; } if (args[0] == "AGGRO_RANGE_BIG" || args[0] == "AGGRO_RANGE_NORMAL" || args[0] == "AGGRO_RANGE_SMALL" || args[0] == "AGGRO_RANGE_NONE") { if (args[0] == "AGGRO_RANGE_BIG") { CAiWrapper::getInstance().setAggroRange(rtNpc->EntityId, 100); return;} if (args[0] == "AGGRO_RANGE_NORMAL") { CAiWrapper::getInstance().setAggroRange(rtNpc->EntityId, 30); return;} if (args[0] == "AGGRO_RANGE_SMALL") { CAiWrapper::getInstance().setAggroRange(rtNpc->EntityId, 15); return;} if (args[0] == "AGGRO_RANGE_NONE") { CAiWrapper::getInstance().setAggroRange(rtNpc->EntityId, 0); return;} return; } } if ( (animationProp & CAnimationProp::Controlable) ) { if ( args[0] == "CONTROL" && alived) { if (!isIncarnedByPlayer(creatureId, eid)) { if (session->IncarningBots.getBotsCount(charId) == 0) // We can now only incarnate One Npc { if ( setIncarningPlayer(sessionId, creatureId, eid, entityRowId, alias) ) { CAiWrapper::getInstance().controlNpc(eid, creatureId); /* if (_CharacterControlProxy) { CCharacterControlItfProxy proxy(_CharacterControlProxy); proxy.teleportCharacterToNpc(this, charId, creatureId, session->CurrSeason ); } */ CAiWrapper::getInstance().askBotDespawnNotification(creatureId, alias); updateAnimationProperties(*foundModule, eid, rtNpc, rtGrp); } } else { CShareClientEditionItfProxy proxy( *foundModule ); proxy.systemMsg(this, "BC", "", "uiR2EDAlreadyIncarningANpc"); } } args[0] = "TALK_AS"; } if ( args[0] == "STOP_CONTROL") { CEntityId bot = creatureId; if (args.size() == 2) { uint32 id; fromString(args[1], id); CAnimationSession* session = getSession(sessionId); if (session) { bot = session->IncarningBots.getEntity( eid, id); if ( bot == NLMISC::CEntityId() ) { return; } } } if (isIncarnedByPlayer(bot, eid)) { stopIncarn(eid, bot); removeIncarningPlayer(sessionId, bot, eid); } if (isTalkingAs(bot, eid)) { stopTalk(eid, bot, entityRowId); removeTalkingAsPlayer(sessionId, bot, eid); } updateAnimationProperties(*foundModule, eid, rtNpc, rtGrp); return; } } if ( (animationProp & CAnimationProp::Speaking) ) { if (args[0] == "TALK_AS" && alived) { if (isTalkingAs(creatureId, eid)) return; if (session->TalkingAsBots.getBotsCount(charId) < 8) { if ( setTalkingAsPlayer(sessionId, creatureId, eid, entityRowId, alias) ) { CMessage msg("TALK_AS"); TModuleId tmp = (*foundModule)->getModuleProxyId(); msg.serial(tmp); msg.serial(entityRowId); msg.serial(name); msg.serial(sessionId); _StringManagerProxy->sendModuleMessage(this,msg); CAiWrapper::getInstance().askBotDespawnNotification(creatureId, alias); updateAnimationProperties(*foundModule, eid, rtNpc, rtGrp); } } else { CShareClientEditionItfProxy proxy(*foundModule); proxy.systemMsg(this, "BC", "", "uiR2EDSpeakingAsTooManyEntities"); } } if (args[0] == "STOP_TALK") { NLMISC::CEntityId bot = creatureId; TDataSetRow botDSR = entityRowId; if (args.size() == 2) { uint32 id; fromString(args[1], id); CAnimationSession* session = getSession(sessionId); if (session) { bot = session->TalkingAsBots.getEntity( eid, id); if ( bot == NLMISC::CEntityId() ) { return; } TOwnedEntities::const_iterator found(_TalkedAsEntities.find(bot)); if (found == _TalkedAsEntities.end()) { return ;} botDSR = found->second.CreatureRowId; } } if (isTalkingAs(bot, eid)) { stopTalk(eid, bot,botDSR); removeTalkingAsPlayer(sessionId, bot, eid); updateAnimationProperties(*foundModule, eid, rtNpc, rtGrp); } return; } } } // EGS message to indicates that a character is ready in mirror void CServerAnimationModule::characterReady(NLNET::IModuleProxy * /* sender */, const NLMISC::CEntityId &charEid) { uint32 charId = uint32(charEid.getShortId()); nldebug("characterReady : received character ready for char %u", charId); // forward the event to the server edition module getEditionModule()->characterReady(charId); } bool CServerAnimationModule::onProcessModuleMessage(IModuleProxy *senderModuleProxy, const CMessage &msgin) { std::string operationName = msgin.getName(); // if (CServerAnimationItfSkel::onDispatchMessage(senderModuleProxy, msgin)) // { // return; // } // // // From Client // if (CShareServerAnimationItfSkel::onDispatchMessage(senderModuleProxy, msgin)) // { // return; // } // from service.cpp if (!senderModuleProxy) { if (operationName == "SESSION_ACK") { // AIS ack receiving anim session uint32 aiInstance; nlRead(msgin, serial, aiInstance); nlinfo( "R2An: ack received from AIS for anim session %u", aiInstance ); _ReadyForNextSession = true; return true; } if (operationName == "translateAndForwardArg") { _StringManagerProxy->sendModuleMessage(this,msgin); return true; } nlassert(0); return false; } else if (senderModuleProxy->getModuleClassName() == "ClientEditionModule") { uint32 charId; NLMISC::CEntityId clientEid; std::string userPriv; std::string extendedPriv; bool ok = checkSecurityInfo(senderModuleProxy, charId, clientEid, userPriv, extendedPriv); if (!ok) { return true; } if (operationName == "requestStartAct") { // from users uint32 actId; nlRead(msgin,serial,actId); // check that char session is known TCharSessions::const_iterator charFound(_CharSessions.find(charId)); if ( charFound == _CharSessions.end()) { // if session is queued, then just info msg if( !_QueuedSessions.empty() ) { bool bFoundSession = false; CAnimationSession *lastSession = _QueuedSessions.back(); CAnimationSession *animSession = NULL; do { animSession = _QueuedSessions.front(); _QueuedSessions.pop_front(); _QueuedSessions.push_back( animSession ); if( !bFoundSession ) { // look for this char in the session std::vector::const_iterator it = animSession->ConnectedChars.begin(), itEnd = animSession->ConnectedChars.end(); while( it != itEnd ) { if( charId == *it++ ) { bFoundSession = true; break; } } } } while( lastSession != animSession ); if( bFoundSession ) { nlinfo("R2An: startAct received from char %u, anim session is in queue.", charId); return true; } } nlwarning("R2An: not connected Char(%u) try to start an act.", charId); return true; } scheduleStartAct(charFound->second, actId); return true; } if (operationName == "requestSetSeason") { uint8 seasonValue; nlRead(msgin, serial, seasonValue); TCharSessions::const_iterator charFound(_CharSessions.find(charId)); if ( charFound == _CharSessions.end()) { nlwarning("R2An: not connected char(%d) try to start an act.", charId); return true; } setSeasonValue(charFound->second, seasonValue); return true; } if (operationName == "requestSetWeather") { uint16 weatherValue; nlRead(msgin, serial, weatherValue); TCharSessions::const_iterator charFound(_CharSessions.find(charId)); if ( charFound == _CharSessions.end()) { nlwarning("R2An: not connected char(%d) try to set the weather.", charId); return true; } setWeatherValue(charFound->second, weatherValue); return true; } if (operationName == "requestStopAct") { //from chars TCharSessions::const_iterator charFound(_CharSessions.find(charId)); if ( charFound == _CharSessions.end()) { nlwarning("R2An: not connected char(%u) try to start an act.", charId); return true; } stopAct(charFound->second); return true; } if(operationName == "requestStringValue") { TSessionId scenarioId=(TSessionId)1; std::string stringId; TModuleId id = senderModuleProxy->getModuleProxyId(); nlRead(msgin,serial,stringId); CMessage msg("requestStringValue"); msg.serial(scenarioId); msg.serial(id); msg.serial(stringId); _StringManagerProxy->sendModuleMessage(this,msg); return true; } if(operationName == "requestIdList") { TSessionId scenarioId = (TSessionId)1; TModuleId id = senderModuleProxy->getModuleProxyId(); CMessage msg("requestIdList"); msg.serial(scenarioId); msg.serial(id); _StringManagerProxy->sendModuleMessage(this,msg); return true; } if(operationName =="talk_as") { std::string name ; nlRead(msgin,serial,name); CMessage msg("talk_as"); TModuleId tmp = senderModuleProxy->getModuleProxyId(); msg.serial(tmp); msg.serial(name); _StringManagerProxy->sendModuleMessage(this,msg); return true; } if(operationName == "stopTalk") { CMessage msg("stopTalk"); TModuleId id = senderModuleProxy->getModuleProxyId(); msg.serial(id); _StringManagerProxy->sendModuleMessage(this,msg); return true; } if(operationName == "requestStringTable") { CMessage msg("requestStringTable"); TSessionId scenarioId = (TSessionId)1; TModuleId id = senderModuleProxy->getModuleProxyId(); nlwarning("string table requested!!"); msg.serial(scenarioId); msg.serial(id); _StringManagerProxy->sendModuleMessage(this,msg); return true; } if(operationName=="requestSetValue") { TSessionId scenarioId = (TSessionId)1; std::string stringId; std::string value; nlRead(msgin,serial,stringId); nlRead(msgin,serial,value); CMessage msg("requestSetValue"); nlRead(msg,serial,scenarioId); nlRead(msg,serial,stringId); nlRead(msg,serial,value); _StringManagerProxy->sendModuleMessage(this,msg); return true; } } else if (senderModuleProxy->getModuleClassName() == "ServerEditionModule") { if (operationName == "DBG_CREATE_PRIMITIVES") { TSessionId sessionId; nlRead(msgin,serial,sessionId); TSessions::const_iterator found = _Sessions.find(sessionId); CObjectSerializerServer obj; nlRead(msgin,serial,obj); CAnimationSession* session = new CAnimationSession(); session->CurrentAct = 0; session->RtData.reset( obj.getData() ); session->SessionId = sessionId; queueSession(session, false); return true; } } return false; } TSessionId CServerAnimationModule::getScenarioId(uint32 charId) { TCharSessions::const_iterator found = _CharSessions.find(charId); if(found!=_CharSessions.end()) { return found->second; } return TSessionId(~0u); } void CServerAnimationModule::disconnectChar(TCharId charId) { const NLNET::TModuleProxyPtr* client = getEditionModule()->getClientProxyPtr(charId); if (client) { onModuleDown(*client); } } void CServerAnimationModule::scheduleStartSession(const CAnimationMessageAnimationStart &msg) { _Tasks.addTaskAt( NLMISC::CTime::getLocalTime() + 1000, new CTaskScheduleStartSession( this, msg) ); } void CServerAnimationModule::scheduleStartSessionImpl(const CAnimationMessageAnimationStart &msg) { //create new Session nlinfo("R2An: creating new animSession %u", msg.SessionId.asInt()); CAnimationSession* session = new CAnimationSession(); session->CurrentAct = msg.StartingAct; std::vector::const_iterator first(msg.AnimatorCharId.begin()), last(msg.AnimatorCharId.end()); for ( ; first != last ; ++first) { session->ConnectedChars.push_back(*first); } session->RtData.reset( msg.RtData.getData() ); session->SessionId = msg.SessionId; session->AiInstance = msg.AiInstance; session->InitialAct = msg.StartingAct; session->ScenarioHeader = msg.ScenarioHeader; // queue session bool ok = queueSession(session); if (!ok) { nlwarning("R2An: can't queue animation session"); return; } // Update animator session info { std::vector::const_iterator first(msg.AnimatorCharId.begin()), last(msg.AnimatorCharId.end()); for ( ; first != last ; ++first) { bool inserted =_CharSessions.insert(std::make_pair(*first, msg.SessionId)).second; if (!inserted) { // lookup the previous sessin id and make sure that we have a session for thsi id TSessionId previousCharSessionId = _CharSessions[*first]; nlinfo("R2An::scheduleStartSession Moving char (%u) from Session %u to Session %u", *first, previousCharSessionId.asInt(), msg.SessionId.asInt()); BOMB_IF(_Sessions.find(previousCharSessionId)==_Sessions.end(),"scheduleStartSession giving up because failed to find _Sessions entry for character",return); // disconnect from previous scenario if (previousCharSessionId != msg.SessionId) { CAnimationSession* previousSession = getSession( previousCharSessionId ); BOMB_IF(!previousSession, "BUG: Failed to get pointer to session object with Id: "+NLMISC::toString(previousCharSessionId.asInt()), return); std::vector & chars = previousSession->ConnectedChars; chars.erase(std::remove(chars.begin(), chars.end(), *first ), chars.end()); } _CharSessions[*first] = msg.SessionId; } nlinfo("R2An: Char %u is connected as animator", *first); } } session->CurrSeason = ~0; } IPrimitive* CServerAnimationModule::getEvent(CObject* event,CInstanceMap& components, const std::string& prefix,TSessionId scenarioId) { //create the primitive event IPrimitive* pEvent = 0; pEvent = dynamic_cast (CClassRegistry::create ("CPrimNode")); pEvent->addPropertyByName("class", new CPropertyString("npc_event_handler")); pEvent->addPropertyByName("ai_type", new CPropertyString("NPC_EVENT")); // AJM pEvent->addPropertyByName("state_keyword_filter", new CPropertyStringArray()); // AJM pEvent->addPropertyByName("group_keyword_filter", new CPropertyStringArray()); // AJM CAttributeToProperty a2pEvent(event, pEvent); a2pEvent.setAttributeAsStringWithPrefix("Id", "name", prefix); // a2pEvent.setAttributeAsString("Event", "event"); a2pEvent.setAttributeAsStringArrayWithPrefix("StatesByName", "states_by_name", prefix);//TODO more verification a2pEvent.setAttributeAsStringArrayWithPrefix("GroupsByName", "groups_by_name",prefix); //TODO??? CPrimAlias *event_alias = dynamic_cast (CClassRegistry::create ("CPrimAlias")); event_alias->addPropertyByName("class", new CPropertyString("alias")); event_alias->addPropertyByName("name", new CPropertyString("alias")); pEvent->insertChild(event_alias); CObject* actions_id = event->getAttr("ActionsId"); uint32 firstAction=0,lastAction=0; if(actions_id)lastAction=actions_id->getSize(); IPrimitive* father; if(lastAction>1) { father = dynamic_cast (CClassRegistry::create ("CPrimNode")); father->addPropertyByName("class", new CPropertyString("npc_event_handler_action")); father->addPropertyByName("ai_type", new CPropertyString("NPC_EVENT_ACTION")); // AJM father->addPropertyByName("weight", new CPropertyString("1")); // AJM father->addPropertyByName("action",new CPropertyString("multi_actions")); father->addPropertyByName("name", new CPropertyString("multi_actions")); // AJM pEvent->insertChild(father); } else { father = pEvent; } //for each action of this event for(;firstAction!=lastAction;++firstAction) { CObject * action_id = actions_id->getValue(firstAction); std::string id = action_id->toString(); CObject* action=components.find(id); // can be null? if (!action) { nlwarning("Error while generating primitives in session '%u' in action '%s'", scenarioId.asInt(), id.c_str()); return 0; } //create the primitive action IPrimitive* pAction=getAction(action, prefix,scenarioId); if (!pAction ) { nlwarning("Error for '%u'th action '%s' in states '%s' with group '%s'", firstAction, event->toString("Name").c_str(), event->toString("StatesByName").c_str(), event->toString("GroupsByName").c_str()); return 0; } //add the action to the event father->insertChild(pAction); } return pEvent; } void CServerAnimationModule::requestLoadTable(CAnimationSession* session) { CObject* texts = session->RtData->getAttr("Texts"); TSessionId scenarioId = session->SessionId; CMessage msg("registerTable"); //serialize scenarioId msg.serial(scenarioId); { uint32 size = session->ConnectedChars.size(); std::vector connected; for(uint32 i=0; igetClientProxyPtr(session->ConnectedChars[i]); if (ptr){ connected.push_back(ptr); } } uint32 connectedSize = connected.size(); msg.serial( connectedSize ); for(uint32 i=0; igetModuleProxyId(); msg.serial(id); } if (connected.size() != session->ConnectedChars.size()) { nlwarning("SAn: error pioneer deconnection not found."); } } //create the message to send the local string table to the //string manager module if((texts==NULL)||(texts->getAttr("Texts")->getSize()==0)) { uint32 tmp=0; msg.serial(tmp); } else { CObject* textsTable = texts->getAttr("Texts"); uint32 size; if(textsTable && textsTable->isTable() && (size=textsTable->getSize())!=0 ) { //serialize entry count msg.serial(size); for(uint32 i=0;igetValue(i); std::string tmp = entry->getAttr("Id")->toString(); msg.serial(tmp); tmp = entry->getAttr("Text")->toString(); msg.serial(tmp); } } } _StringManagerProxy->sendModuleMessage(this,msg ); } void CServerAnimationModule::requestUnloadTable(TSessionId sessionId) { CMessage msg("unregisterTable"); msg.serial(sessionId); if (_StringManagerProxy != 0) { _StringManagerProxy->sendModuleMessage(this,msg); } } void CServerAnimationModule::requestReleaseChannels(TSessionId sessionId) { CMessage msg("CLEAR_CHANNELS"); msg.serial(sessionId); if (_StringManagerProxy != 0) { _StringManagerProxy->sendModuleMessage(this,msg); } } void CServerAnimationModule::onServiceUp(const std::string &serviceName, TServiceId /* serviceId */) { nlinfo( "R2An: %s onServiceUp", serviceName.c_str() ); if( serviceName == "AIS" ) { _ReadyForNextSession = true; } } void CServerAnimationModule::onServiceDown(const std::string &serviceName, TServiceId /* serviceId */) { nlinfo( "R2An: %s onServiceDown", serviceName.c_str() ); if( serviceName == "AIS" ) { _ReadyForNextSession = false; } } void CServerAnimationModule::askMissionItemsDescription(NLNET::IModuleProxy *senderModuleProxy) { uint32 charId; NLMISC::CEntityId clientEid; std::string userPriv; std::string extendedPriv; bool ok = checkSecurityInfo(senderModuleProxy, charId, clientEid, userPriv, extendedPriv); if (!ok) { return; } TSessionId sessionId = getSessionIdByCharId(charId); CAnimationSession* session = getSession(sessionId); if (session) { CShareClientEditionItfProxy clientproxy(senderModuleProxy); clientproxy.updateMissionItemsDescription(this, sessionId, session->MissionItems); } } void CServerAnimationModule::deactivateEasterEggsFromAct(TSessionId scenarioId, uint32 actId) { DROP_IF(_CharacterControlProxy.isNull() , "No CharacterControlProxy", return); CAnimationSession* session = getSession(scenarioId); DROP_IF(!session, toString("No Session %d", scenarioId.asInt()), return); DROP_IF(actId >= session->Acts.size(), "Error in activateEasterEgg ", return ); CRtAct* rtAct = session->Acts[actId]; DROP_IF(!rtAct, "Error in activateEasterEgg ", return ); if (rtAct->ActiveEasterEggs.empty()) { return; } std::set easterEggs; CRtAct::TActiveEasterEggs::const_iterator first(rtAct->ActiveEasterEggs.begin()), last(rtAct->ActiveEasterEggs.end()); for (; first != last; ++first) { easterEggs.insert(first->first); CAnimationSession::TActiveEasterEggs::iterator toErase(session->ActiveEasterEggs.find(first->first)); DROP_IF(toErase == session->ActiveEasterEggs.end(), "Error in activateEasterEgg ", return ); session->ActiveEasterEggs.erase(toErase); } session->Acts[actId]->ActiveEasterEggs.clear(); CCharacterControlItfProxy proxy(_CharacterControlProxy); proxy.deactivateEasterEggs(this, easterEggs , scenarioId); } void CServerAnimationModule::deactivateEasterEgg(class NLNET::IModuleProxy * /* aisControl */, uint32 easterEggId, TSessionId scenarioId, uint32 actId) { DROP_IF(_CharacterControlProxy.isNull(), "No CharacterControlProxy", return); CAnimationSession* session = getSession(scenarioId); DROP_IF(!session, toString("No Session %d", scenarioId.asInt()), return); // TODO Move code to session? DROP_IF(actId >= session->Acts.size(), "Error in activateEasterEgg ", return ); bool ok = session->Acts[actId]->deactivateEasterEgg(easterEggId); if (!ok) { // already removed return; } CAnimationSession::TActiveEasterEggs::iterator found(session->ActiveEasterEggs.find(easterEggId)); if (found != session->ActiveEasterEggs.end()) { session->ActiveEasterEggs.erase(found); } CCharacterControlItfProxy proxy(_CharacterControlProxy); proxy.deactivateEasterEgg(this, easterEggId, scenarioId); } void CServerAnimationModule::activateEasterEgg(class NLNET::IModuleProxy * /* aisControl */, uint32 easterEggId, TSessionId scenarioId, uint32 actId ,const std::string & items, float x, float y, float z, float heading, const std::string& grpControler, const std::string& name, const std::string& look) { DROP_IF(_CharacterControlProxy.isNull(), "No CharacterControlProxy", return); CAnimationSession* session = getSession(scenarioId); DROP_IF(!session, toString("No Session %d", scenarioId.asInt()), return); std::vector itemNames; NLMISC::splitString(items, ";", itemNames); std::vector itemsAndQuantities; uint32 first(0), last(itemNames.size()); for (; first != last ; ++first) { std::vector itemAndQt; std::string itemQt = itemNames[first]; NLMISC::splitString(itemQt, ":", itemAndQt); DROP_IF( itemAndQt.size() != 2, "Syntax error in activateEasterEgg", return ); char* ok = 0; uint32 item = static_cast(strtol(itemAndQt[0].c_str(), &ok, 10)); DROP_IF( *ok != '\0', "Error activateEasterEgg", return); uint32 qt = static_cast(strtol(itemAndQt[1].c_str(), &ok, 10)); DROP_IF( *ok != '\0', "Error in activateEasterEgg", return); DROP_IF( qt > 255, "Error in activateEasterEgg", return); DROP_IF( item >= session->MissionItems.size(), "Error activateEasterEgg", return); R2::TItemAndQuantity itemAndQuantity; itemAndQuantity.SheetId = session->MissionItems[item].SheetId; itemAndQuantity.Quantity = qt; itemsAndQuantities.push_back(itemAndQuantity); } DROP_IF(actId >= session->Acts.size(), "Error in activateEasterEgg ", return ); bool ok = session->Acts[actId]->activateEasterEgg(easterEggId, grpControler); if (!ok) { // component already activated return; } ok = session->ActiveEasterEggs.insert(make_pair(easterEggId, actId)).second; if (!ok) { //must never happend nlwarning("Error while activating easter egg"); } CFarPosition pos; pos.SessionId = scenarioId; pos.PosState.X = static_cast(x*1000); pos.PosState.Y = static_cast(y*1000); pos.PosState.Z = static_cast(z*1000); pos.PosState.Heading = static_cast(heading*1000); CCharacterControlItfProxy proxy(_CharacterControlProxy); proxy.activateEasterEgg(this, easterEggId, scenarioId, session->AiInstance, itemsAndQuantities, pos, name, look); } void CServerAnimationModule::onEasterEggLooted(class NLNET::IModuleProxy * /* egs */, uint32 easterEggId, TSessionId scenarioId) { CAnimationSession* session = getSession(scenarioId); DROP_IF(!session, toString("No Session %d", scenarioId.asInt()), return); session->easterEggLooted(easterEggId, scenarioId); } void CServerAnimationModule::onUserTriggerTriggered(NLNET::IModuleProxy *senderModuleProxy, uint32 actId, uint32 triggerId) { uint32 charId; NLMISC::CEntityId clientEid; std::string userPriv; std::string extendedPriv; bool ok = checkSecurityInfo(senderModuleProxy, charId, clientEid, userPriv, extendedPriv); if (!ok) { return; } TSessionId sessionId = getSessionIdByCharId(charId); CAnimationSession* session = getSession(sessionId); if (session) { triggerUserTrigger(sessionId, actId, triggerId); } } void CServerAnimationModule::triggerUserTrigger( TSessionId sessionId, uint32 actId, uint32 triggerId) { CAnimationSession* animationSession = getSession(sessionId); if (animationSession && actId < animationSession->Acts.size() && triggerId < animationSession->Acts[actId]->UserTriggers.size()) { std::string groupName = animationSession->Acts[actId]->UserTriggers[triggerId].FullName; CAiWrapper::getInstance().triggerUserTrigger(groupName, 1); } else { nlwarning("error in CServerAnimationModule::triggerUserTrigger(%d, %d, %d)", sessionId.asInt(), actId, triggerId); } } void CServerAnimationModule::askActPositionDescriptions(NLNET::IModuleProxy *senderModuleProxy) { uint32 charId; NLMISC::CEntityId clientEid; std::string userPriv; std::string extendedPriv; bool ok = checkSecurityInfo(senderModuleProxy, charId, clientEid, userPriv, extendedPriv); if (!ok) { return; } TSessionId sessionId = getSessionIdByCharId(charId); CAnimationSession* session = getSession(sessionId); if (session) { CShareClientEditionItfProxy clientproxy(senderModuleProxy); TActPositionDescriptions actPositionDescriptions; session->updateActPositionDescriptions(actPositionDescriptions); clientproxy.updateActPositionDescriptions(this, actPositionDescriptions); } } void CServerAnimationModule::askUserTriggerDescriptions(NLNET::IModuleProxy *senderModuleProxy) { uint32 charId; NLMISC::CEntityId clientEid; std::string userPriv; std::string extendedPriv; bool ok = checkSecurityInfo(senderModuleProxy, charId, clientEid, userPriv, extendedPriv); if (!ok) { return; } TSessionId sessionId = getSessionIdByCharId(charId); CAnimationSession* session = getSession(sessionId); if (session) { CShareClientEditionItfProxy clientproxy(senderModuleProxy); TUserTriggerDescriptions userTriggerDescriptions; session->updateUserTriggerDescriptions(userTriggerDescriptions); clientproxy.updateUserTriggerDescriptions(this, userTriggerDescriptions); } } void CServerAnimationModule::onBotDeathNotification(NLMISC::CEntityId& creatureId) { onBotDespawnNotification(creatureId); } void CServerAnimationModule::onBotDespawnNotification(NLMISC::CEntityId& creatureId) { TOwnedEntities::iterator itControl = _IncarnedEntities.find(creatureId); TOwnedEntities::iterator itTalk = _TalkedAsEntities.find(creatureId); TOwnedEntities::iterator itTarget = _TargetedEntities.find(creatureId); if (itControl == _IncarnedEntities.end() && itTalk == _TalkedAsEntities.end() && itTarget == _TargetedEntities.end() ) { return; } if (itTarget != _TargetedEntities.end() ) { COwnedCreatureInfo& info = (*itTarget).second; std::vector& playerId = info.PlayerIds; std::vector::iterator first(playerId.begin()), last(playerId.end()); for (; first != last; ++first) { CEntityId eid = *first; uint32 charId = static_cast(first->getShortId()); const NLNET::TModuleProxyPtr* pClient = getEditionModule()->getClientProxyPtr(charId); if (pClient) { updateAnimationProperties(*pClient, CEntityId::Unknown, 0, 0); } } _TargetedEntities.erase(itTarget); } if (itControl != _IncarnedEntities.end()) { COwnedCreatureInfo& info = (*itControl).second; std::vector playerId = info.PlayerIds; std::vector::iterator first(playerId.begin()), last(playerId.end()); for (; first != last; ++first) { CEntityId eid = *first; uint32 charId = static_cast(first->getShortId()); TSessionId sessionId = getSessionIdByCharId(charId) ; removeIncarningPlayer(sessionId, creatureId, eid); stopIncarn(eid, creatureId); const NLNET::TModuleProxyPtr* pClient = getEditionModule()->getClientProxyPtr(charId); if (pClient) { updateAnimationProperties(*pClient, CEntityId::Unknown, 0, 0); } } } if (itTalk != _TalkedAsEntities.end()) { COwnedCreatureInfo& info = (*itTalk).second; std::vector playerId = info.PlayerIds; std::vector::iterator first(playerId.begin()), last(playerId.end()); for (; first != last; ++first) { CEntityId eid = *first; uint32 charId = static_cast( first->getShortId() ); TSessionId sessionId = getSessionIdByCharId(charId); removeTalkingAsPlayer(sessionId, creatureId, eid); stopTalk(eid, creatureId, info.CreatureRowId); const NLNET::TModuleProxyPtr* pClient = getEditionModule()->getClientProxyPtr(charId); if (pClient) { updateAnimationProperties(*pClient, CEntityId::Unknown, 0, 0); } } } } void CServerAnimationModule::onStopNpcControlNotification(NLMISC::CEntityId& creatureId) { TOwnedEntities::iterator itControl = _IncarnedEntities.find(creatureId); if (itControl != _IncarnedEntities.end()) { COwnedCreatureInfo& info = (*itControl).second; std::vector playerId = info.PlayerIds; std::vector::iterator first(playerId.begin()), last(playerId.end()); for (; first != last; ++first) { CEntityId eid = *first; uint32 charId = static_cast(first->getShortId()); TSessionId sessionId = getSessionIdByCharId(charId) ; removeIncarningPlayer(sessionId, creatureId, eid); stopIncarn(eid, creatureId); const NLNET::TModuleProxyPtr* pClient = getEditionModule()->getClientProxyPtr(charId); if (pClient) { updateAnimationProperties(*pClient, CEntityId::Unknown, 0, 0); } } } } NLMISC_CLASS_COMMAND_IMPL(CServerAnimationModule, loadPdrFile) { if (args.size() != 1) return false; Pdr.clear(); CAiWrapper::getInstance().fileToPdr(args[0], Pdr); return true; } NLMISC_CLASS_COMMAND_IMPL(CServerAnimationModule, savePdrFile) { if (args.size() != 1) return false; CAiWrapper::getInstance().pdrToFile(Pdr, args[0]); return true; } NLMISC_CLASS_COMMAND_IMPL(CServerAnimationModule, displayPdr) { if (args.size() != 0) return false; CAiWrapper::getInstance().displayPdr(Pdr); return true; } NLMISC_CLASS_COMMAND_IMPL(CServerAnimationModule, clearPdr) { if (args.size() != 0) return false; CAiWrapper::getInstance().clearPdr( Pdr); return true; } NLMISC_CLASS_COMMAND_IMPL(CServerAnimationModule, loadPrimitiveFile) { if (args.size() != 1) return false; CAiWrapper::getInstance().primitiveFileToPdr(args[0], Pdr); return true; } NLMISC_CLASS_COMMAND_IMPL(CServerAnimationModule, loadRtFile) { if (args.size() != 1) return false; CIFile file; if (!file.open(args[0])) { nlwarning("can't open '%s'", args[0].c_str()); } CObjectSerializerServer obj; obj.serial(file); Pdr.clear(); // translateScenarioToPdr(obj.getData(), Pdr); return true; } NLMISC_CLASS_COMMAND_IMPL(CServerAnimationModule, startTest) { if (args.size() != 1) return false; uint32 id; fromString(args[0], id); startTest(TSessionId(id), Pdr); return true; } NLMISC_CLASS_COMMAND_IMPL(CServerAnimationModule, stopTest) { if (args.size() != 1) return false; uint32 dummyLastAct = 0; uint32 id; fromString(args[0], id); stopTest(TSessionId(id), dummyLastAct ); return true; } NLMISC_CLASS_COMMAND_IMPL(CServerAnimationModule, displayMissionItems) { if (args.size() != 1) { log.displayNL("ServerAnimationModule.displayMissionItems sessionId"); return false; } uint32 id; fromString(args[0], id); TSessionId sessionId = TSessionId(id); CAnimationSession* animationSession = getSession(sessionId); if (animationSession) { uint32 first(0), last(animationSession->MissionItems.size()); log.displayNL("%d Missions Item:", last); for ( ;first != last ; ++first) { log.displayNL("Item %d '%s' '%s' '%s' '%s'", first, animationSession->MissionItems[first].SheetId.toString().c_str(), animationSession->MissionItems[first].Name.toString().c_str(), animationSession->MissionItems[first].Description.toString().c_str(), animationSession->MissionItems[first].Comment.toString().c_str() ); } } return true; } NLMISC_CLASS_COMMAND_IMPL(CServerAnimationModule, displayUserTriggers) { if (args.size() != 1) { log.displayNL("ServerAnimationModule.displayUserTriggers sessionId"); return false; } uint32 id; fromString(args[0], id); TSessionId sessionId = TSessionId(id); CAnimationSession* animationSession = getSession(sessionId); if (animationSession) { TUserTriggerDescriptions userTriggerDescriptions; animationSession->updateUserTriggerDescriptions(userTriggerDescriptions); uint32 first(0), last(userTriggerDescriptions.size()); log.displayNL("%d User Trigger:", last); for ( ;first != last ; ++first) { log.displayNL("Trigger %d: Name='%s' act='%d' id='%d'", first, userTriggerDescriptions[first].Name.c_str(), userTriggerDescriptions[first].Act, userTriggerDescriptions[first].Id ); } } return true; } NLMISC_CLASS_COMMAND_IMPL(CServerAnimationModule, triggerUserTrigger) { if (args.size() != 3) { log.displayNL("ServerAnimationModule.triggerUserTrigger sessionId actId triggerId"); return false; } uint32 id; fromString(args[0], id); TSessionId sessionId = TSessionId(id); uint32 actId; fromString(args[1], actId); uint32 triggerId; fromString(args[2], triggerId); triggerUserTrigger(sessionId, actId, triggerId); return true; } } // namespace R2 IServerEditionModule* CServerAnimationModule::getEditionModule() const { return _Server->getEditionModule(); } NLNET::IModule* CServerAnimationModule::getModule() const { return const_cast(this); } bool CServerAnimationModule::isSessionRunning(TSessionId sessionId) const { CAnimationSession* session = getSession(sessionId); return session != 0; } uint32 CServerAnimationModule::getCurrentAct(TSessionId sessionId) const { CAnimationSession* session = getSession(sessionId); if (session) { return session->CurrentAct; } return 1; } void CServerAnimationModule::dssMessage(NLNET::IModuleProxy * /* ais */, TSessionId sessionId, const std::string & msgType, const std::string& who, const std::string& msg) { CAnimationSession* session = getSession(sessionId); if (session) { CMessage message; std::string translatedMessage = _Server->getValue(sessionId, msg); CShareClientEditionItfProxy::buildMessageFor_systemMsg(message, msgType, who, translatedMessage); std::vector::const_iterator first( session->ConnectedChars.begin()), last(session->ConnectedChars.end()); for (; first != last; ++first) { const NLNET::TModuleProxyPtr* ptr = getEditionModule()->getClientProxyPtr(*first); if (ptr) { (*ptr)->sendModuleMessage(this, message); } } } } void CServerAnimationModule::setSessionStartParams(TSessionId sessionId, sint32 x, sint32 y, uint8 season) { CAnimationSession* session = getSession(sessionId); if (session) { session->setStartParams(x, y, season);} } bool CServerAnimationModule::mustReloadPosition(TSessionId sessionId, TCharId charId) const { CAnimationSession* session = getSession(sessionId); if (!session) { return false; } bool ok = session->CharacternValidePosition.find(charId) != session->CharacternValidePosition.end(); return ok; } bool CServerAnimationModule::getHeaderInfo(TSessionId sessionId, TScenarioHeaderSerializer::TValueType& values) const { CAnimationSession* session = getSession(sessionId); if (!session) { return false; } values = session->ScenarioHeader.Value; return true; } void CServerAnimationModule::teleportCharacter(NLNET::IModuleProxy * /* ais */, const NLMISC::CEntityId& eid, float x, float y, float z) { CAnimationSession * session = getSessionByCharId(TCharId(eid.getShortId())); if (session) { const R2::TR2TpInfos tpInfos; //no tp Infos if ( !_CharacterControlProxy.isNull()) { CCharacterControlItfProxy ccip( _CharacterControlProxy ); ccip.onTpPositionAsked(this, eid, x, y, z, session->CurrSeason, tpInfos); } } } void CServerAnimationModule::broadcastMsg(TSessionId sessionId, const NLNET::CMessage& msg) { CAnimationSession * session = getSession(sessionId); if (!session) { return; } broadcastMessage(session, msg); } void CServerAnimationModule::setScenarioPoints(NLNET::IModuleProxy * /* ais */, TSessionId sessionId, float scenarioPoints) { CAnimationSession* session = getSession(sessionId); if (!session) { return; } session->ScenarioScore = static_cast(scenarioPoints); //nldebug("Current Scenario points= %f)", scenarioPoints); return; } void CServerAnimationModule::startScenarioTiming(NLNET::IModuleProxy * /* ais */, TSessionId sessionId) { CAnimationSession* session = getSession(sessionId); if (!session) { return; } if (!session->TimingIsFinished) { //NLMISC::TTime startTime = NLMISC::CTime::getLocalTime(); session->ScenarioTime = NLMISC::CTime::getLocalTime(); } //nlinfo("Scenario Start time= %u)", scenarioPoints); return; } void CServerAnimationModule::endScenarioTiming(NLNET::IModuleProxy * /* ais */, TSessionId sessionId) { CAnimationSession* session = getSession(sessionId); if (!session) { return; } if (!session->TimingIsFinished) { //NLMISC::TTime startTime = NLMISC::CTime::getLocalTime(); session->ScenarioTime = NLMISC::CTime::getLocalTime() - session->ScenarioTime; nldebug("Scenario has been completed in: %u ms", session->ScenarioTime); session->TimingIsFinished = true; } //nlinfo("Scenario Start time= %u)", scenarioPoints); return; } bool CServerAnimationModule::getScore(TSessionId sessionId, uint32 &score, NLMISC::TTime &timeTaken) { CAnimationSession* session = getSession(sessionId); if (!session) { score = 0; timeTaken = 0; return false; } score = session->ScenarioScore; if (session->TimingIsFinished == true) { timeTaken = session->ScenarioTime; } else { timeTaken = 0; } return true; }