// 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 (uint32)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 which 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 = std::numeric_limits::max();
StartingAct = false;
InitialAct = 1;
AiInstance = std::numeric_limits::max(); //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 (uint32)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 = (uint32)Acts.size();
for ( ; actIndex != actCount; ++actIndex)
{
CRtAct* act = Acts[actIndex];
uint32 userTriggerCount = (uint32)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 = (uint32)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 = (uint32)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 = (uint)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].c_str();
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 = (uint32)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(), (uint)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 = (uint32)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 = (uint32)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 = (uint32)basic.size();
static std::string female = "_female";
static uint32 femaleSize = (uint32)female.size();
static std::string male = "_male";
static uint32 maleSize = (uint32)male.size();
uint32 sheetClientSize = (uint32)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 = (uint32)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 information 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(std::numeric_limits::max());
}
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 = std::numeric_limits::max();
}
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 = (uint32)session->ConnectedChars.size();
std::vector connected;
for(uint32 i=0; igetClientProxyPtr(session->ConnectedChars[i]);
if (ptr){ connected.push_back(ptr); }
}
uint32 connectedSize = (uint32)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 = (uint32)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 );
uint32 item;
bool ok = NLMISC::fromString(itemAndQt[0], item);
DROP_IF( !ok, "Error activateEasterEgg", return);
uint32 qt;
ok = NLMISC::fromString(itemAndQt[1], qt);
DROP_IF( !ok, "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 = (uint32)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 = (uint32)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;
}