/* * psnetmanager.cpp by Matze Braun * * Copyright (C) 2002 Atomic Blue (info@planeshift.it, http://www.atomicblue.org) * * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation (version 2 of the License) * 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 General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #ifndef __psCelClient_H__ #define __psCelClient_H__ #include #include #include #include #include "engine/celbase.h" #include "net/cmdbase.h" #include #include #include #include #include struct Trait; class MsgHandler; class ModeHandler; class ZoneHandler; class psClientDR; class psNetPersist; class psClientVitals; struct iPcCommandInput; struct iVFS; struct iSpriteCal3DState; class psEntityLabels; class psWorld; class psPersistActor; class psPersistItem; class GEMClientObject; class GEMClientActor; class GEMClientItem; class GEMClientActionLocation; class psEffect; /** This is information about an entity with unresolved position (=sector not found) * This happens when some entity is located in map that is not currently loaded. * We are trying to resolve the position every time new maps are loaded */ class UnresolvedPos { public: GEMClientObject * entity; // our object .. csVector3 pos; // .. and its position that could not be set float rot; csString sector; UnresolvedPos(GEMClientObject * entity, const csVector3 & pos, float rot, const csString & sector) { this->entity = entity; this->pos = pos; this->rot = rot; this->sector = sector; } }; /** * Client version of the Cel Manager */ class psCelClient : public CelBase, public psClientNetSubscriber { private: csPDelArray entities; csHash entities_hash; csArray newActorQueue; csArray newItemQueue; // Keep seperate for speedups csArray actions; bool ignore_others; public: psCelClient(); virtual ~psCelClient(); bool Initialize (iObjectRegistry* object_reg, MsgHandler* msghandler, ModeHandler *modehndlr,ZoneHandler *zonehndlr); bool Initialize(iObjectRegistry* object_reg) { return CelBase::Initialize(object_reg); } void Clear() { mainPlayerEntity = NULL; } void RequestServerWorld(); bool IsReady(); iCelEntity* GetMainActor(); GEMClientObject* FindObject( int ID ); void SetMainActor(iCelEntity* entity); void SetPlayerReady(bool flag); void RemoveObject(GEMClientObject* entity); void SendPersist(); psClientDR* GetClientDR() { return clientdr; } const csPDelArray& GetEntities () const { return entities; } bool IsMeshSubjectToAction(const char* sector,const char* mesh); virtual void HandleMessage(MsgEntry* me); void SetupWorldColliders(); psEntityLabels * GetEntityLabels() { return entityLabels; } GEMClientActor* GetMainPlayer() { return local_player; } /** Caled when new world maps were loaded CelClient looks for GEM Objects which have sectors with unknown name and checks if this name is known now */ void OnMapsLoaded(); /** Called when a region of the world is deleted from the client (because we don't need it loaded now) CelClient removes all GEMClientObjects that are in this region */ void OnRegionsDeleted(csArray& regions); psWorld* GetWorld() { return gameWorld; } /** This is called when position of some entity could not be resolved (see the UnresolvedPos struct) * It adds this position to list of unresolved positions which we will attempt to resolve later * and moves the entity to special sector that keeps these unfortunate entities. */ void HandleUnresolvedPos(GEMClientObject * entity, const csVector3 & pos, float rot, const csString & sector); void PruneEntities(); bool IsUnresSector(iSector* sector) { return unresSector == sector;} int GetRequestStatus() { return requeststatus; } void IgnoreOthers(bool state) { ignore_others = state; } bool IsIgnoringOthers() { return ignore_others; } void CheckEntityQueues(); protected: void ReadKeyBindings (const char* filename, iPcCommandInput* pcinp); void QueueNewActor(MsgEntry *me); void QueueNewItem(MsgEntry *me); /** Finds given entity in list of unresolved entities */ csList::Iterator FindUnresolvedPos(GEMClientObject * entity); int requeststatus; csRef mainPlayerEntity; csRef vfs; csRef msghandler; psClientDR* clientdr; ModeHandler *modehandler; ZoneHandler *zonehandler; psEntityLabels * entityLabels; psWorld* gameWorld; void HandleWorld( MsgEntry* me ); void HandleActor( MsgEntry* me ); void HandleItem( MsgEntry* me ); void HandleActionLocation( MsgEntry* me ); void HandleObjectRemoval( MsgEntry* me ); void HandleNameChange( MsgEntry* me ); void HandleGuildChange( MsgEntry* me ); void HandleGroupChange( MsgEntry* me ); /** Handles a stats message from the server. * This basically just publishes the data to PAWS so various widgets can be updated. */ void HandleStats( MsgEntry* me ); void RequestActor(); GEMClientActor* local_player; /// Handle a change in the main actor void HandleMainActor( psPersistActor& mesg ); csRef local_player_defaultMesh; csRef local_player_defaultFact; csString local_player_defaultFactName; csList unresPos; ///< list of entities with unresolved location iSector * unresSector; ///< sector where we keep these entities }; enum GEMOBJECT_TYPE { GEM_OBJECT = 0, GEM_ACTOR, GEM_ITEM, GEM_ACTION_LOC, GEM_TYPE_COUNT }; /** An object that the client knows about. This is the base object for any * 'entity' that the client can be sent. */ class GEMClientObject { public: GEMClientObject(); GEMClientObject( psCelClient* cel, PS_ID id ); virtual ~GEMClientObject(); virtual GEMOBJECT_TYPE GetObjectType() { return GEM_OBJECT; } iCelEntity* GetEntity() { return entity; } bool InitMesh(const char *factname,const char *filename, const csVector3& pos,const float rotangle, const char* sector ); /** Set position of mesh */ void Move(const csVector3& pos,float rotangle, const char* room); /** Set position of entity */ virtual bool SetPosition(const csVector3 & pos, float rot, iSector * sector); int GetID() { return id; } csRef pcmesh; int GetType() { return type; } const char* GetName() { return name; } void ChangeName(const char* name); const char* GetFactName() { return factname; } psEffect* GetEntityLabel() { return entitylabel; } void SetEntityLabel(psEffect* el) { entitylabel = el; } /** * Indicate if this object is alive */ virtual bool IsAlive() { return false; } /** Get the flag bit field. * @return The bit field that contains the flags on this actor. */ int Flags() { return flags; } protected: friend class psCelClient; static psCelClient *cel; csRef entity; csString name; csString factname; int id; int type; int flags; ///< Various flags on the entity. psEffect* entitylabel; }; class psDRMessage; //--------------------------------------------------------------------------- //-------------------------------------------------------------------------- /** This is a player or another 'alive' entity on the client. */ class GEMClientActor : public GEMClientObject { public: GEMClientActor( psCelClient* cel, psPersistActor& mesg ); virtual ~GEMClientActor(); virtual GEMOBJECT_TYPE GetObjectType() { return GEM_ACTOR; } virtual bool SetPosition(const csVector3 & pos, float rot, iSector * sector); void SetAlive( bool aliveFlag, bool newactor ); virtual bool IsAlive() { return alive; } /** Get the condition manager on this actor. */ psClientVitals* GetVitalMgr() { return vitalManager; } csVector3 Pos(); csVector3 Rot(); iSector *GetSector(); const char* GetGuildName() { return guildName; } void SetGuildName(const char* guild) { guildName = guild; } bool NeedDRUpdate(unsigned char& priority); void SendDRUpdate(unsigned char priority,csStringHash* msgstrings); void SetDRData(psDRMessage& drmsg); void StopMoving(bool worldVel = false); csRef linmove; csRef colldet; /// The Vital of the player with regards to his health/mana/fatigue/etc. psClientVitals *vitalManager; void SetIdleAnimation(const char* anim); void SetAnimationVelocity(const csVector3& velocity); bool SetAnimation(const char* anim, int duration=0); void RefreshCal3d(); ///< Reloads iSpriteCal3DState csRef cal3dstate; bool control; /** * This optimal routine tries to get the animation index given an * animation csStringID. */ int GetAnimIndex (csStringHash* msgstrings, csStringID animid); // The following hash is used by GetAnimIndex(). csHash anim_hash; csString race; csString helmGroup; csString equipment; csString traits; csVector3 vel, angularVelocity; csVector3 lastSentVelocity,lastSentRotation; bool stationary,path_sent; csTicks lastDRUpdateTime; bool ready; // Access functions for the group var bool IsGroupedWith(GEMClientActor* actor); unsigned int GetGroupID() { return groupID; } void SetGroupID(unsigned int id) { groupID = id; } unsigned int GetOwnerID() { return ownerID; } void SetOwnerID(unsigned int id) { ownerID = id; } csPDelArray traitList; protected: unsigned int groupID; unsigned int ownerID; csString guildName; uint8_t DRcounter; /// increments in loop to prevent out of order packet overwrites of better data bool DRcounter_set; bool InitLinMove(const csVector3& pos,float angle, const char* sector, csVector3 top, csVector3 bottom, csVector3 offset); bool InitCharData(const char* textures, const char* equipment); bool alive; void SetCharacterMode(size_t id, bool newactor=false); size_t mode; }; /** An item on the client. */ class GEMClientItem : public GEMClientObject { public: GEMClientItem( psCelClient* cel, psPersistItem& mesg ); virtual GEMOBJECT_TYPE GetObjectType() { return GEM_ITEM; } protected: }; /** An action location on the client. */ class GEMClientActionLocation : public GEMClientObject { public: GEMClientActionLocation( psCelClient* cel, psPersistActionLocation& mesg ); virtual GEMOBJECT_TYPE GetObjectType() { return GEM_ACTION_LOC; } const char* GetMesh() { return meshname; } protected: csString meshname; }; #endif