From: Keith F. <ven...@us...> - 2003-04-18 06:35:46
|
Update of /cvsroot/planeshift/planeshift/src/server In directory sc8-pr-cvs1:/tmp/cvs-serv477 Added Files: pscel.h pscel.cpp Log Message: Added CEL wrapper classes. These classes encapulate all access to iCelEntity and all PCs owned by different types of entities. From now on, if you find yourself using a PC directly on the server, you are probably doing something wrong. :-) --- NEW FILE: pscel.h --- /* * pscel.h - author Keith Fulton <ke...@pa...> * * Copyright (C) 2003 PlaneShift Team (in...@pl..., * http://www.planeshift.it) * * 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. * * This is the cel access class for PS. */ #ifndef __PSCEL_H__ #define __PSCEL_H__ #include <csutil/csstring.h> #include <csutil/hashmap.h> #include "engine/celbase.h" #include "engine/netpersist.h" #include <pl/entity.h> struct iPcProximityList; struct iPcLinearMovement; struct iPcCharacterData; struct iPcNPCDialog; class psServerCharManager; class MsgHandler; class psCelServer; class celPSObject; class psDatabase; /** * This class holds the refs to the core factories, etc in CEL. */ class psCel { protected: csHashMap entities; public: csRef<iObjectRegistry> object_reg; csRef<iCelPlLayer> pl; csRef<iCelBlLayer> bl; psNetPersist *netpersist; public: psCel(iObjectRegistry *objreg,iCelPlLayer *player,iCelBlLayer *blayer,psNetPersist *net); csPtr<iCelEntity> CreateEntity(celPSObject *obj); celPSObject *FindObject(CS_ID id); }; /** * A celPSObject is any solid, graphical object visible in PS with normal physics * and normal collision detection. */ class celPSObject { protected: bool valid; csRef<iCelEntity> entity; iPcMesh* pcmesh; iPcProximityList *proxlist; csString name; static psCel *cel; csVector3 pos; iSector *sector; bool InitProximityList(float radius,int clientnum,int objID); bool InitMesh(const char *name,const char *factname,const char *filename, const csVector3& pos,const float rotangle,iSector* room, const char *action); public: celPSObject(psCel *cel,const char* name, const char* factname,const char* filename,iSector* room, const csVector3& pos,float rotangle,int clientnum,int objID); /// This ctor is only for use in making keys for the BinaryTree celPSObject(const char *name) { this->name = name; pcmesh=NULL; sector=NULL; }; ~celPSObject(); bool IsValid(void) { return (entity!=NULL); } iCelEntity *GetEntity() { return entity; } void SendBehaviorMessage(const char *str, celPSObject *obj, ...); const char *GetName() { return entity->GetName(); } // Mesh related functions iMeshWrapper *GetMeshWrapper(); void Move(const csVector3& pos,float rotangle,iSector* room); bool IsNear(celPSObject *obj,float radius); // Proxlist related functions PublishVector& GetMulticastClients(); void RemoveFromAllProx(); int GetClientID(); int GetObjectID(); float RangeTo(celPSObject *obj); // Networking functions void Broadcast(int clientnum); // Overridden functions in child classes virtual int GetMode() { return 0; }; virtual int GetPlayerID() { return 0; }; virtual iPcNPCDialog *GetNPCDialogPtr() { return 0; }; }; /* * Any PS Object with which a player may have interaction (i.e. clickable). */ class celPSActiveObject : public celPSObject { public: celPSActiveObject(psCel *cel, const char* name, const char* factname, const char* filename, iSector* room, const csVector3& pos, float rotangle, int clientnum, int objID, psServerCharManager* charmanager, MsgHandler* msghandler,psCelServer *celserver); }; /* * Any semi-autonomous object, either a player or an NPC. */ class celPSActor : public celPSObject { protected: iPcLinearMovement* pcmove; iPcCharacterData* pcdata; int playerID; bool InitLinMove(const csVector3& pos,float angle, const iSector* sector); bool InitCharData(); public: celPSActor(psCel *cel,const char* name, const char* factname,const char* filename,iSector* room, const csVector3& pos,float rotangle,int clientnum,int objID,int playerID); void SetTextureParts(const char *parts); void SetEquipment(const char *equip); void SetMode(int mode); int GetMode(); void SetPosition(const csVector3& pos,float angle, const iSector* sector); void GetPosition(csVector3& pos,float& angle, iSector*& sector); csPtr<iDataBuffer> GetDRData(); void SetDRData(iDataBuffer* data,bool detectcheat); virtual int GetPlayerID() { return playerID; }; }; class celPSNPC : public celPSActor { protected: iPcNPCDialog *npcdialog; public: celPSNPC(psCel *cel,const char* name, const char* factname,const char* filename,iSector* room, const csVector3& pos,float rotangle,int clientnum,int objID,int playerID); virtual iPcNPCDialog *GetNPCDialogPtr() { return npcdialog; }; void SetupDialog(int NPCID,psDatabase *database); }; #endif --- NEW FILE: pscel.cpp --- /* * pscel.h by Keith Fulton <ke...@pa...> * * Copyright (C) 2003 PlaneShift Team (in...@pl..., * http://www.planeshift.it) * * 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. * */ #include <config.h> #include <iengine/engine.h> #include <iengine/campos.h> #include <iengine/mesh.h> #include <ivideo/txtmgr.h> #include <ivideo/texture.h> #include <iutil/objreg.h> #include <iutil/cfgmgr.h> #include <iutil/object.h> #include <csgeom/box.h> #include <igeom/objmodel.h> #include <csgeom/transfrm.h> #include <csutil/snprintf.h> #include <csengine/movable.h> #include <csengine/sector.h> #include <pl/pl.h> #include <bl/bl.h> #include <pl/entity.h> #include <pl/propfact.h> #include <pl/propclas.h> #include <pl/persist.h> #include <pf/mesh.h> #include <pf/mesh.h> #include <pf/meshsel.h> #include <pf/inv.h> #include <pf/chars.h> #include <pf/move.h> #include <pf/tooltip.h> #include <pf/camera.h> #include <pf/gravity.h> #include <pf/timer.h> #include <pf/region.h> #include <pf/input.h> #include "client.h" #include "clients.h" #include "net/message.h" #include "net/msghandler.h" #include "util/pserror.h" #include "engine/netpersist.h" #include "psbehave/psworld.h" #include "pscelserver.h" #include "psserverdr.h" #include "psserver.h" #include "util/serverconsole.h" #include "weathermanager.h" #include "psdatabase.h" #include "psprop/pc/pspclinmove.h" #include "psprop/pc/pspcchar.h" #include "psprop/pc/pspcnpcdialog.h" #include "psprop/pc/pspcproxlist.h" #include "psserverbehave.h" psCel *celPSObject::cel; psCel::psCel(iObjectRegistry *objreg,iCelPlLayer *player,iCelBlLayer *blayer,psNetPersist *net) { object_reg = objreg; pl = player; bl = blayer; netpersist = net; } csPtr<iCelEntity> psCel::CreateEntity(celPSObject *obj) { csRef<iCelEntity> ent = pl->CreateEntity(); csHashKey key = ent->GetID(); entities.Put(key,obj); return (csPtr<iCelEntity>) ent; } celPSObject *psCel::FindObject(CS_ID id) { csHashKey key = id; csHashIterator i(&entities, key); celPSObject* obj; while ( (obj=(celPSObject*) i.Next()) ) { if ( obj->GetEntity()->GetID() == id) return obj; } Notify2("No object with the id of '%u' was found.", id); return NULL; } celPSObject::celPSObject(psCel *cel, const char* name, const char* factname, const char* filename, iSector* room, const csVector3& pos, float rotangle, int clientnum, int objID) { if (!this->cel) this->cel = cel; csRef<iCelPropertyClass> pc; entity = cel->CreateEntity(this); entity->SetName(name); if (!InitMesh(name,factname,filename,pos,rotangle,room,NULL)) { Error1("Could not create Item because mesh could not be Init'd."); entity = NULL; return; } if (!InitProximityList(DEF_PROX_DIST,clientnum,objID)) { Error1("Could not create Item because prox list could not be Init'd."); entity = NULL; return; } } celPSObject::~celPSObject() { } void celPSObject::SendBehaviorMessage(const char *str, celPSObject *obj, ...) { if (!entity) return; iCelBehaviour *bl = entity->GetBehaviour(); if (bl) { va_list arg; va_start (arg, obj); bl->SendMessageV(str, (iBase *)obj, arg); va_end (arg); } } void celPSObject::Broadcast(int clientnum) { cel->netpersist->BroadcastEntity(clientnum,entity); } bool celPSObject::InitMesh(const char *name, const char *factname, const char *filename, const csVector3& pos, const float rotangle, iSector* room, const char *action) { csRef<iCelPropertyClass> pc; pc = cel->pl->CreatePropertyClass(entity, "pcmesh"); if ( !pc ) { Error1("Could not create Item because pcmesh class couldn't be created."); return false; } pcmesh = SCF_QUERY_INTERFACE ( pc, iPcMesh ); if ( !pcmesh ) { Error1("Could not create Item because pcmesh class doesn't implement iPcMesh."); return false; } pcmesh->SetMesh(factname, filename); if ( !pcmesh->GetMesh() ) { Error2("Could not create Item because could not load %s file into mesh.",factname); return false; } iMeshWrapper* mesh = pcmesh->GetMesh(); if ( !mesh ) { Error1("Could not create Item because pcmesh didn't have iMeshWrapper."); return false; } Move(pos,rotangle,room); if (action) pcmesh->SetAction(action); return true; } iMeshWrapper *celPSObject::GetMeshWrapper() { return pcmesh->GetMesh(); } void celPSObject::Move(const csVector3& pos,float rotangle, iSector* room) { // Position and sector pcmesh->MoveMesh( room, pos); // Rotation csMatrix3 matrix = (csMatrix3) csYRotMatrix3 (rotangle); pcmesh->GetMesh()->GetMovable()->GetTransform().SetO2T (matrix); this->pos = pos; this->sector = room; } #define PSABS(x) ((x) < 0 ? -(x) : (x)) bool celPSObject::IsNear(celPSObject *obj,float radius) { // Find the current position of the specified entity csVector3 pos,pos2; float yrot,yrot2; iSector *sector,*sector2; proxlist->GetMeshPosition(entity,pos,yrot,sector); obj->proxlist->GetMeshPosition(obj->entity,pos2,yrot2,sector2); if (sector != sector2) // ptr comparison here is dangerous but valid. Might convert to strcmp later. return false; // if not same sector, then by definition not Near. /** * Note below defines a cube, not a sphere, but for updating * purposes should be fine and is faster. */ if ( (PSABS(pos.x - pos2.x) < radius) && (PSABS(pos.y - pos2.y) < radius) && (PSABS(pos.z - pos2.z) < radius) ) return true; else return false; } float celPSObject::RangeTo(celPSObject* obj) { return proxlist->RangeTo(obj->GetEntity() ); } bool celPSObject::InitProximityList(float radius,int clientnum,int objID) { csRef<iCelPropertyClass> pc; // Now create and init the proximity list for the object also pc = cel->pl->CreatePropertyClass(entity, "pcproximitylist"); if ( !pc ) { Error1("Could not create Item because could not Create PropClass for ProxList"); entity = NULL; return false; } proxlist = SCF_QUERY_INTERFACE(pc, iPcProximityList); proxlist->Initialize(clientnum,objID); // store these for fast access later bool subscribed_self=false; // Find nearby entities csRef<iCelEntityList> nearlist = cel->pl->FindNearbyEntities(sector,pos,radius); int count=0; // If a list was created, cycle through them and add any entities // that represent players to the proximity subscription list. if (nearlist) { #ifdef PSPROXDEBUG printf("NearList has %d possible entities to subscribe to.\n",nearlist->GetCount()); #endif for (int i=0; i<nearlist->GetCount(); i++) { iCelEntity *nearentity = nearlist->Get(i); csRef<iPcProximityList> listnear = CEL_QUERY_PROPCLASS(nearentity->GetPropertyClassList(), iPcProximityList); if (!listnear) continue; // entities w/o proxlists are theoretically legal /** * If this is prox list for a player, subscribe to all near entities * but if it is an object or NPC, near entities need to subscribe to it * instead. */ float range = proxlist->RangeTo(nearentity); if (proxlist->GetClientID()) { if (proxlist->GetClientID()==listnear->GetClientID()) subscribed_self=true; #ifdef PSPROXDEBUG printf(" %s subscribing to %s\n",entity->GetName(),nearentity->GetName() ); #endif proxlist->MutualSubscribe(listnear->GetClientID(),nearentity,range); count++; } else if (listnear->GetClientID()) listnear->MutualSubscribe(proxlist->GetClientID(),entity,range); } } // A client should always subscribe to itself if (!subscribed_self && proxlist->GetClientID()) { printf("Forcing a self-subscription for %s\n",entity->GetName()); proxlist->MutualSubscribe(proxlist->GetClientID(),entity,0.0); count++; } #ifdef PSPROXDEBUG printf("%d entities on prox list for %s.\n",count, entity->GetName()); #endif return true; } PublishVector& celPSObject::GetMulticastClients() { return proxlist->GetClients(); } void celPSObject::RemoveFromAllProx() { proxlist->RemoveFromAll(); } int celPSObject::GetClientID() { return proxlist->GetClientID(); } int celPSObject::GetObjectID() { return proxlist->GetObjectID(); } //------------------------------------------------------------------------------------ celPSActiveObject::celPSActiveObject(psCel *cel, const char* name, const char* factname, const char* filename, iSector* room, const csVector3& pos, float rotangle, int clientnum, int objID, psServerCharManager* charmanager, MsgHandler* msghandler,psCelServer *celserver) : celPSObject(cel,name,factname,filename,room,pos,rotangle,clientnum,objID) { // This is just a dummy behaviour. Later on we can read the behaviour // to load from the database. But for now we need something here. // Add on the server side behaviour for that item psChestBehaviour* behave = new psChestBehaviour(); behave->Initialize(celserver, charmanager, entity, this, cel->object_reg, msghandler); behave->SetName("Chest"); behave->SetBehaviourLayer(cel->bl); entity->SetBehaviour(behave); } //-------------------------------------------------------------------------------------- celPSActor::celPSActor(psCel *cel, const char* name, const char* factname, const char* filename, iSector* room, const csVector3& pos, float rotangle, int clientnum, int objID, int pID) : celPSObject(cel,name,factname,filename,room,pos,rotangle,clientnum,objID) { if (!InitLinMove(pos,rotangle,sector)) { Error1("Could not initialize LinMove prop class, so actor not created."); entity = NULL; return; } if (!InitCharData()) { Error1("Could not init char data. Actor not created."); entity = NULL; return; } csRef<iCelBehaviour> behaviour = cel->bl->CreateBehaviour (entity, "actor"); if (!behaviour) { Error1("Could not create actor behavior. Actor not created."); entity = NULL; return; } entity->SetBehaviour (behaviour); playerID = pID; printf("Successfully created actor %s at %1.2f,%1.2f,%1.2f in sector %s.\n", factname,pos.x,pos.y,pos.z,sector->QueryObject()->GetName() ); } /** * Determines the right size and height for the collider for the sprite * and sets the actual position of the sprite. */ bool celPSActor::InitLinMove (const csVector3& pos, float angle, const iSector* sector) { csRef<iCelPropertyClass> pc; pc = cel->pl->CreatePropertyClass(entity, "pclinearmovement"); if ( !pc ) { Error1("Could not create property class pclinearmovement. Actor not created."); return NULL; } pcmove = SCF_QUERY_INTERFACE(pc, iPcLinearMovement); // Now Determine CD bounding boxes for upper and lower colliders csBox3 box; pcmesh->GetMesh()->GetMeshObject()->GetObjectModel()->GetObjectBoundingBox(box,CS_BBOX_ACCURATE); float width = box.MaxX() - box.MinX(); float height = box.MaxY() - box.MinY(); float depth = box.MaxZ() - box.MinZ(); // Add a fudge factor to the depth to allow for feet // sticking forward while running depth *= 1.33; csVector3 top(width,height*(1.0/3.0),depth); csVector3 bottom(width-.1,height*(2.0/3.0),depth-.1); pcmove->InitCD(top, bottom); SetPosition(pos,angle,sector); return true; // right now this func never fail, but might later. } bool celPSActor::InitCharData() { csRef<iCelPropertyClass> pc; pc = cel->pl->CreatePropertyClass(entity, "pccharacterdata"); if ( !pc ) { Error1("Could not create property class pccharacterdata. Actor not created."); return NULL; } pcdata = SCF_QUERY_INTERFACE(pc, iPcCharacterData); if (pcdata) return true; // right now this func never fail, but might later. else return false; } void celPSActor::SetTextureParts(const char *parts) { pcdata->SetTextureParts(parts); } void celPSActor::SetEquipment(const char *equip) { pcdata->SetEquipment(equip); } void celPSActor::SetMode(int mode) { pcdata->SetMode(mode); } int celPSActor::GetMode() { return pcdata->GetMode(); } void celPSActor::GetPosition(csVector3& pos,float& angle, iSector*& sector) { pcmove->GetLastPosition(pos,angle,sector); } void celPSActor::SetPosition(const csVector3& pos,float angle, const iSector* sector) { pcmove->SetPosition(pos,angle,sector); } csPtr<iDataBuffer> celPSActor::GetDRData() { return pcmove->GetDRData(); } void celPSActor::SetDRData(iDataBuffer* data,bool detectcheat) { pcmove->SetDRData(data,detectcheat); } //-------------------------------------------------------------------------------------- celPSNPC::celPSNPC(psCel *cel, const char* name, const char* factname, const char* filename, iSector* room, const csVector3& pos, float rotangle, int clientnum, int objID, int pID) : celPSActor(cel,name,factname,filename,room,pos,rotangle,clientnum,objID,pID) { npcdialog = NULL; } void celPSNPC::SetupDialog(int NPCID,psDatabase *database) { if (database->CountKnowledgeAreas(NPCID)) { iCelPropertyClass* pc; pc = cel->pl->CreatePropertyClass (entity, "pcnpcdialog"); if (!pc) return; csRef<iPcNPCDialog> npcdlg = SCF_QUERY_INTERFACE (pc, iPcNPCDialog); if (!npcdlg) return; npcdlg->Initialize(database,NPCID); npcdialog = npcdlg; } } |