/* * networkmgr.cpp * * Copyright (C) 2003 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. * */ #include #include #include #include #include #include "util/sleep.h" #include "util/log.h" #include "net/connection.h" #include "net/messages.h" #include "net/msghandler.h" #include "net/npcmessages.h" #include "engine/netpersist.h" #include "util/eventmanager.h" #include "networkmgr.h" #include "globals.h" #include "npcclient.h" #include "npc.h" #include "gem.h" #include "util/serverconsole.h" #include "tribe.h" extern bool running; NetworkManager::NetworkManager(MsgHandler *mh,psNetConnection* conn) : reconnect(false) { msghandler = mh; ready = false; connected = false; msghandler->Subscribe(this,MSGTYPE_NPCLIST); msghandler->Subscribe(this,MSGTYPE_MAPLIST); msghandler->Subscribe(this,MSGTYPE_CELPERSIST); msghandler->Subscribe(this,MSGTYPE_ALLENTITYPOS); msghandler->Subscribe(this,MSGTYPE_NPCOMMANDLIST); msghandler->Subscribe(this,MSGTYPE_PERSIST_ACTOR); msghandler->Subscribe(this,MSGTYPE_PERSIST_ITEM); msghandler->Subscribe(this,MSGTYPE_REMOVE_OBJECT); msghandler->Subscribe(this,MSGTYPE_DISCONNECT); msghandler->Subscribe(this,MSGTYPE_WEATHER); msghandler->Subscribe(this,MSGTYPE_MSGSTRINGS); msghandler->Subscribe(this,MSGTYPE_NEW_NPC); msghandler->Subscribe(this,MSGTYPE_NPC_SETOWNER); msghandler->Subscribe(this,MSGTYPE_NPC_COMMAND); msgstrings = NULL; connection= conn; PrepareMessage(); } NetworkManager::~NetworkManager() { if (msghandler) { msghandler->Unsubscribe(this,MSGTYPE_NPCLIST); msghandler->Unsubscribe(this,MSGTYPE_MAPLIST); msghandler->Unsubscribe(this,MSGTYPE_CELPERSIST); msghandler->Unsubscribe(this,MSGTYPE_ALLENTITYPOS); msghandler->Unsubscribe(this,MSGTYPE_NPCOMMANDLIST); msghandler->Unsubscribe(this,MSGTYPE_PERSIST_ACTOR); msghandler->Unsubscribe(this,MSGTYPE_PERSIST_ITEM); msghandler->Unsubscribe(this,MSGTYPE_REMOVE_OBJECT); msghandler->Unsubscribe(this,MSGTYPE_DISCONNECT); msghandler->Unsubscribe(this,MSGTYPE_WEATHER); msghandler->Unsubscribe(this,MSGTYPE_MSGSTRINGS); msghandler->Unsubscribe(this,MSGTYPE_NPC_SETOWNER); msghandler->Unsubscribe(this,MSGTYPE_NPC_COMMAND); } } void NetworkManager::Authenticate(csString& host,int port,csString& user,csString& pass) { this->port = port; this->host = host; this->user = user; this->password = pass; psNPCAuthenticationMessage login(0,user,pass); msghandler->SendMessage(login.msg); } void NetworkManager::Disconnect() { psDisconnectMessage discon(0, 0, ""); msghandler->SendMessage(discon.msg); connection->SendOut(); // Flush the network connection->DisConnect(); } const char *NetworkManager::GetCommonString(uint32_t id) { if (!msgstrings) return NULL; return msgstrings->Request(id); } void NetworkManager::HandleMessage(MsgEntry *me) { switch ( me->GetType() ) { case MSGTYPE_MAPLIST: { connected = true; if (ReceiveMapList(me)) { RequestAllObjects(); } break; } case MSGTYPE_NPCLIST: { ReceiveNPCList(me); ready = true; break; } case MSGTYPE_PERSIST_ACTOR: { HandleActor( me ); break; } case MSGTYPE_PERSIST_ITEM: { HandleItem( me ); break; } case MSGTYPE_REMOVE_OBJECT: { HandleObjectRemoval( me ); break; } case MSGTYPE_ALLENTITYPOS: { HandlePositionUpdates(me); break; } case MSGTYPE_NPCOMMANDLIST: { HandlePerceptions(me); break; } case MSGTYPE_MSGSTRINGS: { csRef engine = CS_QUERY_REGISTRY(npcclient->GetObjectReg(), iEngine); // receive message strings hash table psMsgStringsMessage msg(me); msgstrings = msg.msgstrings; connection->SetMsgStrings(msgstrings); connection->SetEngine(engine); break; } case MSGTYPE_DISCONNECT: { HandleDisconnect(me); break; } case MSGTYPE_WEATHER: { HandleTimeUpdate(me); break; } case MSGTYPE_NEW_NPC: { HandleNewNpc(me); break; } case MSGTYPE_NPC_SETOWNER: { HandleNPCSetOwner(me); break; } case MSGTYPE_NPC_COMMAND: { psServerCommandMessage msg(me); printf(msg.command.GetData()); break; } } } void NetworkManager::HandleActor( MsgEntry* me ) { csRef engine = CS_QUERY_REGISTRY(npcclient->GetObjectReg(), iEngine); psPersistActor mesg( me, npcclient->GetNetworkMgr()->GetMsgStrings(), engine ); gemNPCObject * obj = npcclient->FindEntityID(mesg.entityid); if(obj && obj->GetPlayerID() == mesg.playerID) { // We already know this entity so just update the entity. CPrintf(CON_DEBUG, "Already know about gemNPCActor: %s (%s), %u.\n", mesg.name.GetData(), obj->GetName().GetData(), mesg.entityid ); obj->Move(mesg.pos, mesg.yrot, mesg.sectorName); obj->SetVisible( !(mesg.flags & psPersistActor::INVISIBLE) ); obj->SetInvincible((mesg.flags & psPersistActor::INVINCIBLE)? true : false ); return; } if(mesg.playerID != 0 && !obj) obj = npcclient->FindCharacterID(mesg.playerID); if(obj) { // We have a player id, entity id mismatch and we already know this entity // so we can only assume a RemoveObject message misorder and we will delete the existing one and recreate. CPrintf(CON_DEBUG, "Deleting because we already know gemNPCActor: %s (%s), EID: %u PID: %u as EID: %u PID: %u.\n", mesg.name.GetData(), obj->GetName().GetData(), mesg.entityid, mesg.playerID, obj->GetEntity()->GetID(), obj->GetPlayerID() ); npcclient->Remove(obj->GetEntity()->GetID()); } gemNPCActor* actor = new gemNPCActor( npcclient, mesg); // CPrintf(CON_DEBUG, "Notified about: %s (EID: %u) at %f %f %f\n", actor->GetName().GetData(), mesg.entityid ,mesg.pos.x,mesg.pos.y,mesg.pos.z); if ( actor->GetPlayerID() != 0 ) { npcclient->AttachNPC( actor, mesg.counter); } npcclient->Add( actor ); } void NetworkManager::HandleItem( MsgEntry* me ) { psPersistItem mesg(me); gemNPCObject * obj = npcclient->FindEntityID(mesg.id); if(obj) { // We already know this item so just update the position. CPrintf(CON_DEBUG, "Already know about gemNPCItem: %s (%s), %u.\n", mesg.name.GetData(), obj->GetName().GetData(), mesg.id ); obj->Move(mesg.pos, mesg.yRot, mesg.sector); return; } gemNPCItem* item = new gemNPCItem( npcclient, mesg); npcclient->Add( item ); } void NetworkManager::HandleObjectRemoval( MsgEntry* me ) { psRemoveObject mesg(me); npcclient->Remove( mesg.object); } void NetworkManager::HandleTimeUpdate( MsgEntry* me ) { psWeatherMessage msg(me); if (msg.type == psWeatherMessage::DAYNIGHT) // time update msg { TimePerception pcpt("time",msg.time); npcclient->TriggerEvent(NULL,&pcpt); // Broadcast } } void NetworkManager::RequestAllObjects() { CPrintf(CON_DEBUG, "Requesting all game objects\n"); psRequestAllObjects mesg; msghandler->SendMessage( mesg.msg ); } bool NetworkManager::ReceiveMapList(MsgEntry *msg) { psMapListMessage list(msg); CPrintf(CON_CMDOUTPUT,"\n"); for (size_t i=0; iLoadMap(list.map[i])) return false; } return true; } bool NetworkManager::ReceiveNPCList(MsgEntry *msg) { uint32_t length, pid, eid; length = msg->GetUInt32(); CPrintf(CON_DEBUG, "Received list of %i NPCs.\n", length); for (unsigned int x=0; xGetUInt32(); eid = msg->GetUInt32(); //gemNPCObject *actor = npcclient->FindCharacterID(pid); //if (actor) // npcclient->AttachNPC(actor->GetActorPtr(), (uint8_t)-1); } return true; } void NetworkManager::HandlePositionUpdates(MsgEntry *msg) { psAllEntityPosMessage updates(msg); csRef engine = CS_QUERY_REGISTRY(npcclient->GetObjectReg(), iEngine); for (int x=0; xGetNetworkMgr()->GetMsgStrings(), engine); npcclient->SetEntityPos(id,pos, sector); } } void NetworkManager::HandlePerceptions(MsgEntry *msg) { psNPCCommandsMessage list(msg); // CPrintf(CON_DEBUG, "Got NPC Perception List:\n"); char cmd = list.msg->GetInt8(); while (cmd != psNPCCommandsMessage::CMD_TERMINATOR) { switch(cmd) { case psNPCCommandsMessage::PCPT_TALK: { PS_ID speaker = list.msg->GetUInt32(); PS_ID target = list.msg->GetUInt32(); int faction = list.msg->GetInt16(); NPC *npc = npcclient->FindNPC(target); if (!npc) { CPrintf(CON_DEBUG, "Got talk perception for unknown NPC(%d) from %d!\n", target,speaker); break; } iCelEntity *speaker_ent = npcclient->FindEntity(speaker); if (!speaker_ent) { CPrintf(CON_DEBUG, "%s got talk perception from unknown speaker!\n", npc->GetName().GetData()); break; } FactionPerception talk("talk",faction,speaker_ent); CPrintf(CON_DEBUG, "Got Talk perception for NPC %s, from actor %s, faction diff=%d.\n", npc->GetEntity()->GetName(),speaker_ent->GetName(),faction); npcclient->TriggerEvent(npc,&talk); break; } case psNPCCommandsMessage::PCPT_ATTACK: { PS_ID target = list.msg->GetUInt32(); PS_ID attacker = list.msg->GetUInt32(); NPC *npc = npcclient->FindNPC(target); iCelEntity *attacker_ent = npcclient->FindEntity(attacker); if (!npc) { CPrintf(CON_DEBUG, "Got attack perception for unknown NPC!\n"); break; } if (!attacker_ent) { CPrintf(CON_ERROR, "%s got attack perception for unknown attacker (EID: %u)!\n",npc->GetName().GetData(), attacker ); break; } AttackPerception attack("attack",attacker_ent); CPrintf(CON_DEBUG, "Got Attack perception for NPC %s, from actor %s.\n", npc->GetEntity()->GetName(),attacker_ent->GetName()); npcclient->TriggerEvent(npc,&attack); break; } case psNPCCommandsMessage::PCPT_GROUPATTACK: { PS_ID target = list.msg->GetUInt32(); NPC *npc = npcclient->FindNPC(target); int groupCount = list.msg->GetUInt8(); csArray attacker_ents(groupCount); csArray bestSkillSlots(groupCount); for (int i=0; iFindEntity(list.msg->GetUInt32())); bestSkillSlots.Push(list.msg->GetInt8()); if(!attacker_ents.Top()) { if(npc) CPrintf(CON_DEBUG, "%s got group attack perception for unknown group member!\n",npc->GetEntity()->GetName() ); attacker_ents.Pop(); bestSkillSlots.Pop(); } } if (!npc) { CPrintf(CON_DEBUG, "Got group attack perception for unknown NPC!\n"); break; } if(attacker_ents.Length() == 0) { CPrintf(CON_DEBUG, "%s got group attack perception and all group members are unknown!\n",npc->GetName().GetData() ); break; } GroupAttackPerception attack("attack",attacker_ents,bestSkillSlots); CPrintf(CON_DEBUG, "Got Group Attack perception for NPC %s, recognising %i actors in the group.\n", npc->GetEntity()->GetName(),attacker_ents.Length()); npcclient->TriggerEvent(npc,&attack); break; } case psNPCCommandsMessage::PCPT_DMG: { PS_ID attacker = list.msg->GetUInt32(); PS_ID target = list.msg->GetUInt32(); float dmg = list.msg->GetFloat(); NPC *npc = npcclient->FindNPC(target); if (!npc) { CPrintf(CON_DEBUG, "Attack on unknown npc.\n"); break; } iCelEntity *attacker_ent = npcclient->FindEntity(attacker); if (!attacker_ent) { CPrintf(CON_ERROR, "%s got attack perception for unknown attacker! (EID: %u)\n",npc->GetName().GetData(), attacker ); break; } DamagePerception damage("damage",attacker_ent,dmg); CPrintf(CON_DEBUG, "Got Damage perception for NPC %s, from actor %s for %1.1f HP.\n", npc->GetEntity()->GetName(),attacker_ent->GetName(),dmg); npcclient->TriggerEvent(npc,&damage); break; } case psNPCCommandsMessage::PCPT_DEATH: { PS_ID who = list.msg->GetUInt32(); NPC *npc = npcclient->FindNPC(who); if (!npc) // Not managed by us, or a player { CPrintf(CON_DEBUG, "Got Death message for human player %u\n",who); DeathPerception pcpt("death",who); npcclient->TriggerEvent(NULL,&pcpt); // Broadcast break; } CPrintf(CON_DEBUG, "Got Death message for %s\n",npc->GetName().GetData()); npcclient->HandleDeath(npc); break; } case psNPCCommandsMessage::PCPT_SPELL: { PS_ID caster = list.msg->GetUInt32(); PS_ID target = list.msg->GetUInt32(); uint32_t strhash = list.msg->GetUInt32(); float severity = list.msg->GetInt8() / 10; csString type = GetCommonString(strhash); iCelEntity *caster_ent = npcclient->FindEntity(caster); NPC *npc = npcclient->FindNPC(target); iCelEntity *target_ent = (npc) ? npc->GetEntity() : npcclient->FindEntity(target); CPrintf(CON_DEBUG,"Got Spell Perception for %s\n",(caster_ent)?caster_ent->GetName():"(unknown entity)"); if (!caster_ent || !target_ent) break; iSector *sector; csVector3 pos; float yrot; psGameObject::GetPosition((caster_ent)?caster_ent:target_ent,pos,yrot,sector); SpellPerception pcpt("spell",caster_ent,target_ent,type,severity); npcclient->TriggerEvent(NULL,&pcpt,20,&pos,sector); break; } case psNPCCommandsMessage::PCPT_LONGRANGEPLAYER: case psNPCCommandsMessage::PCPT_SHORTRANGEPLAYER: case psNPCCommandsMessage::PCPT_VERYSHORTRANGEPLAYER: { PS_ID npcid = list.msg->GetUInt32(); PS_ID player = list.msg->GetUInt32(); float faction = list.msg->GetFloat(); NPC *npc = npcclient->FindNPC(npcid); if (!npc) break; // This perception is not our problem npc->Printf("Range perception npc: %d, player: %d, faction:%.0f\n", npcid, player, faction); iCelEntity *npc_ent = (npc) ? npc->GetEntity() : npcclient->FindEntity(npcid); iCelEntity *player_ent = npcclient->FindEntity(player); if (!player_ent || !npc_ent) break; npc->Printf("Got Player %s in Range of %s Perception, with faction %.0f\n", player_ent->GetName(), npc_ent->GetName(), faction); csString pcpt_name; if ( npc->GetOwner() == player_ent ) { pcpt_name.Append("owner "); } else { pcpt_name.Append("player "); } if (cmd == psNPCCommandsMessage::PCPT_LONGRANGEPLAYER) pcpt_name.Append("sensed"); if (cmd == psNPCCommandsMessage::PCPT_SHORTRANGEPLAYER) pcpt_name.Append("nearby"); if (cmd == psNPCCommandsMessage::PCPT_VERYSHORTRANGEPLAYER) pcpt_name.Append("adjacent"); // @@@ Jorrit: cast to in ok below? FactionPerception pcpt(pcpt_name, int (faction), player_ent); npcclient->TriggerEvent(npc,&pcpt); break; } case psNPCCommandsMessage::PCPT_OWNER_CMD: { PS_ID command = list.msg->GetUInt32(); PS_ID owner_id = list.msg->GetUInt32(); PS_ID pet_id = list.msg->GetUInt32(); iCelEntity *owner = npcclient->FindEntity(owner_id); NPC *npc = npcclient->FindNPC(pet_id); iCelEntity *pet = (npc) ? npc->GetEntity() : npcclient->FindEntity( pet_id ); CPrintf(CON_DEBUG,"Got OwnerCmd %d Perception from %s for %s\n",command,(owner)?owner->GetName():"(unknown entity)",(pet)?pet->GetName():"(unknown entity)"); if (!owner || !pet) break; iSector *sector; csVector3 pos; float yrot; psGameObject::GetPosition((owner)?owner:pet,pos,yrot,sector); OwnerCmdPerception pcpt( "OwnerCmdPerception", command, owner, pet ); npcclient->TriggerEvent( npc, &pcpt); break; } case psNPCCommandsMessage::PCPT_OWNER_ACTION: { PS_ID action = list.msg->GetUInt32(); PS_ID owner_id = list.msg->GetUInt32(); PS_ID pet_id = list.msg->GetUInt32(); iCelEntity *owner = npcclient->FindEntity(owner_id); NPC *npc = npcclient->FindNPC(pet_id); iCelEntity *pet = (npc) ? npc->GetEntity() : npcclient->FindEntity( pet_id ); CPrintf(CON_DEBUG,"Got OwnerAction %d Perception from %s for %s\n",action,(owner)?owner->GetName():"(unknown entity)",(pet)?pet->GetName():"(unknown entity)"); if (!owner || !pet) break; iSector *sector; csVector3 pos; float yrot; psGameObject::GetPosition((owner)?owner:pet,pos,yrot,sector); OwnerActionPerception pcpt( "OwnerActionPerception", action, owner, pet ); npcclient->TriggerEvent( npc, &pcpt); break; } case psNPCCommandsMessage::PCPT_INVENTORY: { PS_ID owner_id = msg->GetUInt32(); csString item_name = msg->GetStr(); bool inserted = msg->GetBool(); iCelEntity *owner = npcclient->FindEntity(owner_id); NPC *npc = npcclient->FindNPC(owner_id); if (!owner || !npc) break; npc->Printf("Got Inventory %s Perception from %s for %s\n",(inserted?"Add":"Remove"),(owner)?owner->GetName():"(unknown entity)",item_name.GetData()); iSector *sector; csVector3 pos; float yrot; psGameObject::GetPosition(owner,pos,yrot,sector); /* TODO: Create a inventory for each NPC. if (inserted) { npc->InventoryAdd(item_name); } else { npc->InventoryRemove(item_name); } */ csString str; str.Format("inventory:%s",(inserted?"added":"removed")); InventoryPerception pcpt( str, item_name, pos, sector, 5.0 ); npcclient->TriggerEvent( npc, &pcpt); // Hack: To get inventory to tribe. Need some more general way of // delivery of perceptions to tribes.... if (npc->GetTribe()) { npc->GetTribe()->HandlePerception(&pcpt); } // ... end of hack. break; } case psNPCCommandsMessage::PCPT_FLAG: { PS_ID owner_id = msg->GetUInt32(); uint32_t flags = msg->GetUInt32(); gemNPCObject * obj = npcclient->FindEntityID(owner_id); if (!obj) break; obj->SetVisible(!(flags & psNPCCommandsMessage::INVISIBLE)); obj->SetInvincible((flags & psNPCCommandsMessage::INVINCIBLE) ? true : false); break; } default: { CPrintf(CON_ERROR,"************************\nUnknown npc cmd: %d\n*************************\n",cmd); break; } } cmd = list.msg->GetInt8(); } } void NetworkManager::HandleDisconnect(MsgEntry *msg) { psDisconnectMessage disconnect(msg); // Special case to drop login failure reply from server immediately after we have already logged in. if (connected && disconnect.msgReason.CompareNoCase("Already Logged In.")) return; CPrintf(CON_DEBUG, "Disconnected: %s\n",disconnect.msgReason.GetData()); // Reconnect is disabled right now because the CEL entity registry is not flushed upon // reconnect which will cause BIG problems. Disconnect(); abort(); ServerConsole::Abort(); if(!reconnect && false) { connected = ready = false; // reconnect connection->DisConnect(); npcclient->RemoveAll(); reconnect = true; // 60 secs to allow any connections to go linkdead. psNPCReconnect *recon = new psNPCReconnect(60000, this, false); npcclient->GetEventMgr()->Push(recon); } } void NetworkManager::HandleNewNpc(MsgEntry *me) { printf("*****Got new NPC notification\n"); psNewNPCCreatedMessage msg(me); printf("*****Master=%d, New=%d\n",msg.master_id,msg.new_npc_id); NPC *npc = npcclient->FindNPC(msg.master_id); if (npc) { // Insert a row in the db for this guy next. // We will get an entity msg in a second to make him come alive. npc->InsertCopy(msg.new_npc_id); // Now requery so we have the new guy on our list when we get the entity msg. if (!npcclient->ReadSingleNPC(msg.new_npc_id)) { Error3("Error creating copy of master %d as id %d.",msg.master_id,msg.new_npc_id); return; } //gemNPCObject *actor = npcclient->FindCharacterID(msg.new_npc_id); // see if we already got entity //if (actor) // npcclient->AttachNPC(actor->GetActorPtr(), (uint8_t)-1); } else { // Ignore it here. We don't manage the master. } } void NetworkManager::HandleNPCSetOwner(MsgEntry *me) { printf("*****Got NPC Owner notification\n"); psNPCSetOwnerMessage msg(me); printf("*****Master=%d, Pet=%d\n",msg.master_clientid,msg.npcpet_id); NPC *npc = npcclient->FindNPC( msg.npcpet_id ); if ( npc ) npc->SetOwnerID( msg.master_clientid ); } void NetworkManager::PrepareMessage() { outbound = new psNPCCommandsMessage(0,30000); cmd_count = 0; } void NetworkManager::QueueDRData(iCelEntity *entity,iPcLinearMovement *linmove,uint8_t counter) { if ( outbound->msg->current > ( outbound->msg->bytes->GetSize() - 100 ) ) { CPrintf(CON_DEBUG, "Sent all commands [%d] due to possible Message overrun.\n", cmd_count ); SendAllCommands(); } outbound->msg->Add( (int8_t) psNPCCommandsMessage::CMD_DRDATA); psDRMessage drmsg(0,entity->GetID(),counter,msgstrings,linmove); outbound->msg->Add( drmsg.msg->bytes->payload,(uint32_t)drmsg.msg->bytes->GetTotalSize() ); if ( outbound->msg->overrun ) { CS_ASSERT(!"NetworkManager::QueueDRData put message in overrun state!\n"); } cmd_count++; } void NetworkManager::QueueAttackCommand(iCelEntity *attacker, iCelEntity *target) { if ( outbound->msg->current > ( outbound->msg->bytes->GetSize() - 100 ) ) { CPrintf(CON_DEBUG, "Sent all commands [%d] due to possible Message overrun.\n", cmd_count ); SendAllCommands(); } if (target) CPrintf(CON_DEBUG, "%s is attacking %s.\n",attacker->GetName(),target->GetName() ); else CPrintf(CON_DEBUG, "%s stops attacking.\n",attacker->GetName() ); outbound->msg->Add( (int8_t) psNPCCommandsMessage::CMD_ATTACK); outbound->msg->Add( (uint32_t) attacker->GetID() ); if (target) outbound->msg->Add( (uint32_t) target->GetID() ); else outbound->msg->Add( (uint32_t) 0 ); // 0 target means stop attack if ( outbound->msg->overrun ) { CS_ASSERT(!"NetworkManager::QueueAttackCommand put message in overrun state!\n"); } cmd_count++; } void NetworkManager::QueueSpawnCommand(iCelEntity *mother, iCelEntity *father) { if ( outbound->msg->current > ( outbound->msg->bytes->GetSize() - 100 ) ) { CPrintf(CON_DEBUG, "Sent all commands [%d] due to possible Message overrun.\n", cmd_count ); SendAllCommands(); } outbound->msg->Add( (int8_t) psNPCCommandsMessage::CMD_SPAWN); outbound->msg->Add( (uint32_t) mother->GetID() ); outbound->msg->Add( (uint32_t) father->GetID() ); if ( outbound->msg->overrun ) { CS_ASSERT(!"NetworkManager::QueueSpawnCommand put message in overrun state!\n"); } cmd_count++; } void NetworkManager::QueueTalkCommand(iCelEntity *speaker, const char* text) { if ( outbound->msg->current > ( outbound->msg->bytes->GetSize() - 100 ) ) { CPrintf(CON_DEBUG, "Sent all commands [%d] due to possible Message overrun.\n", cmd_count ); SendAllCommands(); } outbound->msg->Add( (int8_t) psNPCCommandsMessage::CMD_TALK); outbound->msg->Add( (uint32_t) speaker->GetID() ); outbound->msg->Add(text); if ( outbound->msg->overrun ) { CS_ASSERT(!"NetworkManager::QueueTalkCommand put message in overrun state!\n"); } cmd_count++; } void NetworkManager::QueueVisibilityCommand(iCelEntity *entity, bool status) { if ( outbound->msg->current > ( outbound->msg->bytes->GetSize() - 100 ) ) { CPrintf(CON_DEBUG, "Sent all commands [%d] due to possible Message overrun.\n", cmd_count ); SendAllCommands(); } outbound->msg->Add( (int8_t) psNPCCommandsMessage::CMD_VISIBILITY); outbound->msg->Add( (uint32_t) entity->GetID() ); outbound->msg->Add(status); if ( outbound->msg->overrun ) { CS_ASSERT(!"NetworkManager::QueueVisibleCommand put message in overrun state!\n"); } cmd_count++; } void NetworkManager::QueuePickupCommand(iCelEntity *entity, iCelEntity *item, int count) { if ( outbound->msg->current > ( outbound->msg->bytes->GetSize() - 100 ) ) { CPrintf(CON_DEBUG, "Sent all commands [%d] due to possible Message overrun.\n", cmd_count ); SendAllCommands(); } outbound->msg->Add( (int8_t) psNPCCommandsMessage::CMD_PICKUP); outbound->msg->Add( (uint32_t) entity->GetID() ); outbound->msg->Add( (uint32_t) item->GetID() ); outbound->msg->Add( (int16_t) count ); if ( outbound->msg->overrun ) { CS_ASSERT(!"NetworkManager::QueuePickupCommand put message in overrun state!\n"); } cmd_count++; } void NetworkManager::QueueEquipCommand(iCelEntity *entity, csString item, csString slot, int count) { if ( outbound->msg->current > ( outbound->msg->bytes->GetSize() - 100 ) ) { CPrintf(CON_DEBUG, "Sent all commands [%d] due to possible Message overrun.\n", cmd_count ); SendAllCommands(); } outbound->msg->Add( (int8_t) psNPCCommandsMessage::CMD_EQUIP); outbound->msg->Add( (uint32_t) entity->GetID() ); outbound->msg->Add( item ); outbound->msg->Add( slot ); outbound->msg->Add( (int16_t) count ); if ( outbound->msg->overrun ) { CS_ASSERT(!"NetworkManager::QueueEquipCommand put message in overrun state!\n"); } cmd_count++; } void NetworkManager::QueueDequipCommand(iCelEntity *entity, csString slot) { if ( outbound->msg->current > ( outbound->msg->bytes->GetSize() - 100 ) ) { CPrintf(CON_DEBUG, "Sent all commands [%d] due to possible Message overrun.\n", cmd_count ); SendAllCommands(); } outbound->msg->Add( (int8_t) psNPCCommandsMessage::CMD_DEQUIP); outbound->msg->Add( (uint32_t) entity->GetID() ); outbound->msg->Add( slot ); if ( outbound->msg->overrun ) { CS_ASSERT(!"NetworkManager::QueueDequipCommand put message in overrun state!\n"); } cmd_count++; } void NetworkManager::QueueDigCommand(iCelEntity *entity, csString resource) { if ( outbound->msg->current > ( outbound->msg->bytes->GetSize() - 100 ) ) { CPrintf(CON_DEBUG, "Sent all commands [%d] due to possible Message overrun.\n", cmd_count ); SendAllCommands(); } outbound->msg->Add( (int8_t) psNPCCommandsMessage::CMD_DIG); outbound->msg->Add( (uint32_t) entity->GetID() ); outbound->msg->Add( resource ); if ( outbound->msg->overrun ) { CS_ASSERT(!"NetworkManager::QueueDigCommand put message in overrun state!\n"); } cmd_count++; } void NetworkManager::QueueDropCommand(iCelEntity *entity, csString slot) { if ( outbound->msg->current > ( outbound->msg->bytes->GetSize() - 100 ) ) { CPrintf(CON_DEBUG, "Sent all commands [%d] due to possible Message overrun.\n", cmd_count ); SendAllCommands(); } outbound->msg->Add( (int8_t) psNPCCommandsMessage::CMD_DROP); outbound->msg->Add( (uint32_t) entity->GetID() ); outbound->msg->Add( slot ); if ( outbound->msg->overrun ) { CS_ASSERT(!"NetworkManager::QueueDropCommand put message in overrun state!\n"); } cmd_count++; } void NetworkManager::QueueResurrectCommand(csVector3 where, float rot, csString sector, int character_id) { if ( outbound->msg->current > ( outbound->msg->bytes->GetSize() - 100 ) ) { CPrintf(CON_DEBUG, "Sent all commands [%d] due to possible Message overrun.\n", cmd_count ); SendAllCommands(); } outbound->msg->Add( (int8_t) psNPCCommandsMessage::CMD_RESURRECT); outbound->msg->Add( (uint32_t) character_id ); outbound->msg->Add( (float)rot ); outbound->msg->Add( (float)where.x ); outbound->msg->Add( (float)where.y ); outbound->msg->Add( (float)where.z ); outbound->msg->Add( sector ); if ( outbound->msg->overrun ) { CS_ASSERT(!"NetworkManager::QueueResurrectCommand put message in overrun state!\n"); } cmd_count++; } void NetworkManager::SendAllCommands() { if (cmd_count) { outbound->msg->Add( (int8_t) psNPCCommandsMessage::CMD_TERMINATOR); outbound->msg->ClipToCurrentSize(); msghandler->SendMessage(outbound->msg); delete outbound; PrepareMessage(); } } void NetworkManager::ReAuthenticate() { Authenticate(host,port,user,password); } void NetworkManager::ReConnect() { if (!connection->Connect(host,port)) { CPrintf(CON_ERROR, "Couldn't connect to %s on port %d.\n",(const char *)host,port); return; } // 2 seconds to allow linkdead messages to be processed psNPCReconnect *recon = new psNPCReconnect(2000, this, true); npcclient->GetEventMgr()->Push(recon); } void NetworkManager::SendConsoleCommand(const char *cmd) { psServerCommandMessage msg(0,cmd); msg.SendMessage(); } /*------------------------------------------------------------------*/ psNPCReconnect::psNPCReconnect(int offsetticks, NetworkManager *mgr, bool authent) : psGameEvent(0,offsetticks,"psNPCReconnect"), authent(authent), networkMgr(mgr) { } void psNPCReconnect::Trigger() { if(!running) return; if(!authent) { networkMgr->ReConnect(); return; } if(!networkMgr->IsReady()) { CPrintf(CON_DEBUG, "Reconnecting...\n"); networkMgr->ReAuthenticate(); } networkMgr->reconnect = false; }