khanat-opennel-code/code/ryzom/common/src/game_share/server_animation_module.h
2017-03-15 20:43:10 +01:00

422 lines
18 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// 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 <http://www.gnu.org/licenses/>.
#ifndef R2_SERVER_ANIMATION_MODULE_H
#define R2_SERVER_ANIMATION_MODULE_H
#include <queue>
#include <memory>
#include "nel/misc/types_nl.h"
#include "nel/misc/entity_id.h"
#include "nel/misc/time_nl.h"
#include "nel/misc/smart_ptr.h"
#include "nel/net/module_manager.h"
#include "nel/net/module.h"
#include "nel/net/module_builder_parts.h"
#include "nel/ligo/primitive.h"
#include "game_share/dyn_chat.h"
#include "game_share/task_list.h"
#include "r2_modules_itf.h"
#include "game_share/r2_share_itf.h"
#include "game_share/object.h"
#include "game_share/scenario.h"
#include "game_share/small_string_manager.h"
#include "game_share/r2_basic_types.h"
#include "dms.h"
class CPersistentDataRecord;
class CPersistentDataRecordRyzomStore;
namespace NLLIGO
{
class CPrimitives;
}
namespace R2
{
class CObject;
class CDynamicMapService;
class CAnimationSession;
class CRtNpc;
class CRtGrp;
/** Handle the animation Mode (Play Mode and DM Mode in animation session, DM/Test Mode in Edition Session).
* Creations from RT data of Primitives that are read by AI
* start/stop of act
* DM functions (Kill, Heal)
*/
class CServerAnimationModule :
public IServerAnimationModule,
public NLNET::CEmptyModuleServiceBehav<NLNET::CEmptyModuleCommBehav<NLNET::CEmptySocketBehav <NLNET::CModuleBase> > >,
public CServerAnimationItfSkel,
public CShareServerAnimationItfSkel
{
public:
//typedef uint32 TCharId;
// typedef uint32 TUserId;
// typedef uint32 TSessionId;
typedef uint32 TActId;
public:
CServerAnimationModule();
~CServerAnimationModule();
void init(NLNET::IModuleSocket* gateway, CDynamicMapService* server);
/////////////////////////////////////////////////////
//// CModuleBase API
/////////////////////////////////////////////////////
virtual void onServiceUp(const std::string &serviceName, NLNET::TServiceId serviceId);
virtual void onServiceDown(const std::string &serviceName, NLNET::TServiceId serviceId);
virtual void onModuleUpdate();
virtual void onModuleUp(NLNET::IModuleProxy *moduleProxy);
virtual void onModuleDown(NLNET::IModuleProxy *moduleProxy);
virtual bool onProcessModuleMessage(NLNET::IModuleProxy *senderModuleProxy, const NLNET::CMessage &message);
virtual bool isImmediateDispatchingSupported() const { return false; }
/////////////////////////////////////////////////////
//// Start / Stop session, act, scenario
/////////////////////////////////////////////////////
/// schedule the start of an act (the act will begin 30 seconds after)
void scheduleStartAct(TSessionId sessionId, uint32 actId);
/// Called by the client when he connect to play mode in an animation session
virtual void connectAnimationModePlay(NLNET::IModuleProxy*);
// Called by EGS to set the start position of a player
virtual void getStartParams(NLNET::IModuleProxy *sender, uint32 charId, TSessionId lastStoredSessionId);
/// launch the start of a new Act (is launch by AIS or by DM bia dmc)
void startAct(TSessionId sessionId, uint32 actId);
void scheduleStartSession(const CAnimationMessageAnimationStart &msg);
void scheduleStartSessionImpl(const CAnimationMessageAnimationStart &msg);
// Remove a char from a session, remove its module
void disconnectChar(TCharId charId);
virtual bool getConnectedChars(TSessionId sessionId, std::vector<TCharId>& chars) const;
virtual void setSessionStartParams(TSessionId sessionId, sint32 x, sint32 y, uint8 season);
virtual void teleportCharacter(NLNET::IModuleProxy *ais, const NLMISC::CEntityId& eid, float x, float y, float z);
void broadcastMsg(TSessionId sessionId, const NLNET::CMessage& msg);
/////////////////////////////////////////////////////
//// Data Access
/////////////////////////////////////////////////////
IServerEditionModule* getEditionModule() const;
CAnimationSession* getSession(TSessionId sessionId) const;
TSessionId getSessionIdByCharId(TCharId charId) const;
CAnimationSession* getSessionByCharId(TCharId charId) const;
virtual NLNET::IModule* getModule() const;
// Called by EditionModule to add a character
virtual void addPioneer( TSessionId sessionId, TCharId charId) ;
// from client (the module will upload mission item description to dm that will store it to its db)
virtual void askMissionItemsDescription(NLNET::IModuleProxy *client);
// from client (the module will upload Acts Position Description to client)
virtual void askActPositionDescriptions(NLNET::IModuleProxy *client);
// from client (the module will upload Acts Position Description to client)
virtual void askUserTriggerDescriptions(NLNET::IModuleProxy *client);
// from client (the module will upload Acts Position Description to client)
virtual void askIncarnatingListUpdate(NLNET::IModuleProxy *client);
virtual void askTalkingAsListUpdate(NLNET::IModuleProxy *client);
virtual void askUpdateScenarioHeader(NLNET::IModuleProxy *clientProxyPtr);
virtual bool getHeaderInfo(TSessionId sessionId, TScenarioHeaderSerializer::TValueType& values) const;
/////////////////////////////////////////////////////
//// DM
/////////////////////////////////////////////////////
virtual void 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);
virtual void deactivateEasterEgg(class NLNET::IModuleProxy *aisControl, uint32 easterEggId, TSessionId scenarioId, uint32 actId);
virtual void deactivateEasterEggsFromAct(TSessionId scenarioId, uint32 actId);
virtual void onEasterEggLooted(class NLNET::IModuleProxy *egs, uint32 easterEggId, TSessionId scenarioId);
virtual void dssMessage(class NLNET::IModuleProxy *ais, TSessionId sessionId, const std::string & msgType, const std::string& who, const std::string& msg);
// a dm target a npc and want to know what et can do on it (control, kill) and execute dm action (kill, heal...)
virtual void onDssTarget( NLNET::IModuleProxy *senderModuleProxy, const std::vector<std::string> & params);
// EGS gives infos to d
virtual void onCharTargetReceived( NLNET::IModuleProxy *senderModuleProxy,
const NLMISC::CEntityId& eid, const NLMISC::CEntityId&creatureId,
TAIAlias alias, TDataSetRow entityRowId,
const ucstring& ucName, uint32 nameId,
const std::vector<std::string> & params,
bool alived);
// EGS message to indicates that a character is ready in mirror
virtual void characterReady(NLNET::IModuleProxy *sender, const NLMISC::CEntityId &charEid);
virtual void setScenarioPoints(NLNET::IModuleProxy *ais, TSessionId sessionId, float scenarioPoints);
virtual void startScenarioTiming(NLNET::IModuleProxy *ais, TSessionId sessionId);
virtual void endScenarioTiming(NLNET::IModuleProxy *ais, TSessionId sessionId);
bool getScore(TSessionId sessionId, uint32 &score, NLMISC::TTime &timeTaken);
/////////////////////////////////////////////////////
//// DM
/////////////////////////////////////////////////////
void triggerUserTrigger(TSessionId sessionId, uint32 actId, uint32 triggerId);
virtual void onUserTriggerTriggered(NLNET::IModuleProxy *client, uint32 actId, uint32 triggerId);
//////////////////////////////////////////////////////
// NPC Control & talk methods
///////////////////////////////////////////////////////
/*
* stopTalk sends a message to indicate a DM has stopped talking as an NPC.
* eid is the DM Id.
* creatureId is the targeted npc's id.
* entityrowId is the mirror's id of the npc
*/
void stopTalk(const NLMISC::CEntityId &eid, const NLMISC::CEntityId &creatureId, TDataSetRow entityRowId);
/*
* stopIncarn calls a AIWrapper method that sends a message to the AIS to indicate the DM has stopped
* controlling a npc.
* eid is the DM Id.
* creatureId is the targeted npc's id.
*/
void stopIncarn(const NLMISC::CEntityId &eid, const NLMISC::CEntityId &creatureId);
/*
* stop the control of all Npc controlled by the player(incarn or talk as) clientProxyPtr
* (use when client Go from DM -> Player)
*/
virtual void stopControlNpcs(TCharId charId);
/*
* When a bot is despawned, this method checks if it was controlled and "talked as" by a DM.
* If controlled, the stopControl method is called and the _ControlledEntities map is updated: if no more players
* control the npc the map entry corresponding to the creature is deleted. If there is still one player or more that
* controls the npc, the map entry is maintained and its eid vector is updated.
* It does the same treatment on the _TalkedAsEntities map.
*/
void onBotDespawnNotification(NLMISC::CEntityId& creatureId);
void onBotDeathNotification(NLMISC::CEntityId& creatureId);
void onStopNpcControlNotification(NLMISC::CEntityId& creatureId);
/////////////////////////////////////////////////////
//// Position
/////////////////////////////////////////////////////
virtual void askSetUserCharActPosition( NLNET::IModuleProxy *sender, uint32 charId );
bool getPosition(TSessionId sessionId, double& x, double& y, double& orient, uint8& season, uint32 actIndex = 0);
virtual bool isSessionRunning(TSessionId sessionId) const;
virtual uint32 getCurrentAct(TSessionId sessionId) const;
virtual bool mustReloadPosition(TSessionId sessionId, TCharId charId) const;
virtual bool stopTestImpl(TSessionId sessionId, uint32& lastAct);
/////////////////////////////////////////////////////
//// Debug/test functions
/////////////////////////////////////////////////////
NLMISC_COMMAND_HANDLER_TABLE_EXTEND_BEGIN(CServerAnimationModule, CModuleBase)
NLMISC_COMMAND_HANDLER_ADD(CServerAnimationModule, loadPrimitiveFile, "load Primitive file ", "filename")
NLMISC_COMMAND_HANDLER_ADD(CServerAnimationModule, loadPdrFile, "load AiActions from Prd", "filename")
NLMISC_COMMAND_HANDLER_ADD(CServerAnimationModule, loadRtFile, "", "filename")
NLMISC_COMMAND_HANDLER_ADD(CServerAnimationModule, savePdrFile, "load AiActions from Pdr", "filename")
NLMISC_COMMAND_HANDLER_ADD(CServerAnimationModule, displayPdr, "display pdr", "no args")
NLMISC_COMMAND_HANDLER_ADD(CServerAnimationModule, clearPdr, "clear prd", "no args")
NLMISC_COMMAND_HANDLER_ADD(CServerAnimationModule, startTest, "run test", "the sessionId")
NLMISC_COMMAND_HANDLER_ADD(CServerAnimationModule, stopTest, "stop a test", "the sessionId")
// NLMISC_COMMAND_HANDLER_ADD(CServerAnimationModule, stopTest, "stop a test", "the sessionId")
NLMISC_COMMAND_HANDLER_ADD(CServerAnimationModule, displayMissionItems, "display Mission items of a session", "the sessionId")
NLMISC_COMMAND_HANDLER_ADD(CServerAnimationModule, displayUserTriggers, "display UserTrigger of a session", "the sessionId")
NLMISC_COMMAND_HANDLER_ADD(CServerAnimationModule, triggerUserTrigger, "trigger a user trigger", "the sessionId, the trigger act, the trigger Id");
NLMISC_COMMAND_HANDLER_TABLE_END
NLMISC_CLASS_COMMAND_DECL(loadPrimitiveFile);
NLMISC_CLASS_COMMAND_DECL(loadPdrFile);
NLMISC_CLASS_COMMAND_DECL(savePdrFile);
NLMISC_CLASS_COMMAND_DECL(displayPdr);
NLMISC_CLASS_COMMAND_DECL(clearPdr);
NLMISC_CLASS_COMMAND_DECL(loadRtFile);
NLMISC_CLASS_COMMAND_DECL(startTest);
NLMISC_CLASS_COMMAND_DECL(stopTest);
NLMISC_CLASS_COMMAND_DECL(displayMissionItems);
NLMISC_CLASS_COMMAND_DECL(displayUserTriggers);
NLMISC_CLASS_COMMAND_DECL(triggerUserTrigger);
private:
struct COwnedCreatureInfo
{
std::vector<NLMISC::CEntityId> PlayerIds;
TDataSetRow CreatureRowId;
uint32 CreatatureAlias;
};
//private types
typedef std::deque<CAnimationSession*> TSessionsQ;
//map <scenarioId,CAnimationSession*>
typedef std::map<TSessionId, CAnimationSession*> TSessions;
//map <userId,scenarioId>
typedef std::map<TCharId, TSessionId> TCharSessions;
//map <userId,ClientAnimationModule>
//key: controlled creature id; value: player id
typedef std::map<NLMISC::CEntityId, COwnedCreatureInfo> TOwnedEntities;
private: // private functions
////////////////////////////
// Talk & control methods
////////////////////////////
/*
* If the creature is already controlled by a player, updates its eid vector by adding the id of the new controlling
* player. If the creature is not already controlled by any player, this method adds an entry in the
* _ControlledEntities map.
*/
bool setIncarningPlayer(TSessionId sessionId, const NLMISC::CEntityId& creatureId, const NLMISC::CEntityId& eid, TDataSetRow entityRowId, TAIAlias alias);
/*
* If the creature is already "talked as" by a player, updates its eid vector by adding the id of the new talking
* player. If the creature is not already "talked as"by any player, this method adds an entry in the
* _TalkedAsEntities map.
*/
bool setTalkingAsPlayer(TSessionId sessionId, const NLMISC::CEntityId& creatureId, const NLMISC::CEntityId& eid, TDataSetRow entityRowId, TAIAlias alias);
/*
* Checks whether the player is already talking as the targeted npc or not.
*/
bool isTalkingAs(const NLMISC::CEntityId& creatureId, const NLMISC::CEntityId& eid) const;
/*
* Checks whether a creature is already controlled by the player or not.
*/
bool isIncarnedByPlayer(const NLMISC::CEntityId& creatureId, const NLMISC:: CEntityId& eid) const;
/*
* Deletes an eid from the eid vector of a creature (in the _TalkedAsEntities map).If the vector is empty, the
* whole map entry is deleted.
*/
void removeTalkingAsPlayer(TSessionId sessionId, const NLMISC::CEntityId& creatureId, const NLMISC::CEntityId& eid);
/*
* Deletes an eid from the eid vector of a creature (in the _ControlledEntities map).If the vector is empty, the
* whole map entry is deleted.
*/
void removeIncarningPlayer(TSessionId sessionId, const NLMISC::CEntityId& creatureId, const NLMISC::CEntityId& eid);
bool doMakeAnimationSession(CAnimationSession* animSession);
void requestReleaseChannels(TSessionId sessionId);
void requestLoadTable(CAnimationSession* session);
void requestUnloadTable(TSessionId sessionId);
TSessionId getScenarioId(TCharId charId);
void broadcastMessage(CAnimationSession* session, const NLNET::CMessage& msg);
NLMISC::CEntityId getEid(NLNET::TModuleProxyPtr senderModuleProxy);
// message from Server Admin Module for starting Animation Session (calle queueSession)
//called by the DM to change the weather
void setWeatherValue(TSessionId instanceId, uint16 weatherValue);
//called by the DM to change the season
void setSeasonValue(TSessionId instanceId, uint8 seasonValue);
/// Queue the creation of an animation session (+ output Debug)
bool queueSession(CAnimationSession* session, bool runTest = true);
/// for queueSession implementation
bool makeAnimationSession(CAnimationSession* animSession, bool runTest);
/// Create primitives that will be send to AIS from RTData
bool translateActToPrimitive(CInstanceMap& components, CAnimationSession* animSession, CObject* act,
uint32 actId, NLLIGO::CPrimitives& primDoc);
// Create an Actuib (for translateActToPrimitive implementation)
virtual NLLIGO::IPrimitive* getAction(CObject* object, const std::string& prefix,TSessionId scenarioId);
// Create an Event (for translateActToPrimitive implementation)
virtual NLLIGO::IPrimitive* getEvent(CObject* object,CInstanceMap& components, const std::string& prefix,TSessionId scenarioId);
/// Queue the creation of an animation session (one creation is done by
void startTest(TSessionId sessionId, CPersistentDataRecord& pdr);
/// start a test mode (send message to AIS)
bool startTest(CAnimationSession* session, bool runTest = true);
/// stop a test (send message to AIS to unload Primitives)
virtual bool stopTest(TSessionId sessionId, uint32& lastAct);
/// stop the act
void stopAct(TSessionId sessionId);
// Update client the list of controlled by dm
void updateTalkingAsList(TSessionId sessionId, uint32 charId);
void updateIncarningList(TSessionId sessionId, uint32 charId);
// Update client animation properties
void updateAnimationProperties(NLNET::IModuleProxy *senderModuleProxy, const NLMISC::CEntityId & eid, CRtNpc * rtNpc, CRtGrp * rtGrp);
CRtNpc* getNpcByAlias(TSessionId sessionId, TAIAlias alias) const;
private: // privates members
CDynamicMapService* _Server;
// Proxy to string manager
NLNET::TModuleProxyPtr _StringManagerProxy;
// Proxy to Character Controler
NLNET::TModuleProxyPtr _CharacterControlProxy;
// Proxy to IOS ring interface
NLNET::TModuleProxyPtr _IOSRingProxy;
//Map of SessionId, Animation Session
TSessions _Sessions;
// Map of UserId, SessionId
TCharSessions _CharSessions;
// liste of emote Map of emote name and animation name
// Only one session can be performed by update
TSessionsQ _QueuedSessions;
bool _ReadyForNextSession;
// Task that are waiting to be executed (like starting an act in 30 seconds...)
CTaskList<NLMISC::TTime> _Tasks;
CEmoteBehavior _Emotes;
/*
* Map containing:
* -key: CEntityId corresponding to a controlled creature Id
* -value: a COwnedCreatureInfo structure. This structure contains a TDataSetRow corresponding to the creature's id
* in the mirror, and a vector of CEntityId (eids) corresponding to the players respectively controlling or "talking
* as" the npc.
*/
TOwnedEntities _IncarnedEntities;
TOwnedEntities _TalkedAsEntities;
TOwnedEntities _TargetedEntities;
};
} // namespace R2
#endif // R2_SERVER_ANIMATION_MODULE_H