void xrServer::Perform_destroy (CSE_Abstract* object, u32 mode) { R_ASSERT (object); R_ASSERT (object->ID_Parent == 0xffff); #ifdef DEBUG # ifdef SLOW_VERIFY_ENTITIES verify_entities (); # endif #endif while (!object->children.empty()) { CSE_Abstract *child = game->get_entity_from_eid(object->children.back()); R_ASSERT2 (child, make_string("child registered but not found [%d]",object->children.back())); // Msg ("SLS-CLEAR : REJECT [%s][%s] FROM [%s][%s]",child->name(),child->name_replace(),object->name(),object->name_replace()); Perform_reject (child,object,2*NET_Latency); #ifdef DEBUG # ifdef SLOW_VERIFY_ENTITIES verify_entities (); # endif #endif Perform_destroy (child,mode); } // Msg ("SLS-CLEAR : DESTROY [%s][%s]",object->name(),object->name_replace()); u16 object_id = object->ID; entity_Destroy (object); #ifdef DEBUG # ifdef SLOW_VERIFY_ENTITIES verify_entities (); # endif #endif NET_Packet P; P.w_begin (M_EVENT); P.w_u32 (Device.dwTimeGlobal - 2*NET_Latency); P.w_u16 (GE_DESTROY); P.w_u16 (object_id); ClientID clientID; clientID.setBroadcast (); SendBroadcast (clientID,P,mode); }
u32 xrServer::OnMessage (NET_Packet& P, ClientID sender) // Non-Zero means broadcasting with "flags" as returned { if (g_pGameLevel && Level().IsDemoSave()) Level().Demo_StoreServerData(P.B.data, P.B.count); u16 type; P.r_begin (type); csPlayers.Enter (); VERIFY (verify_entities()); xrClientData* CL = ID_to_client(sender); switch (type) { case M_UPDATE: { Process_update (P,sender); // No broadcast VERIFY (verify_entities()); }break; case M_SPAWN: { // R_ASSERT(CL->flags.bLocal); if (CL->flags.bLocal) Process_spawn (P,sender); VERIFY (verify_entities()); }break; case M_EVENT: { Process_event (P,sender); VERIFY (verify_entities()); }break; case M_EVENT_PACK: { NET_Packet tmpP; while (!P.r_eof()) { tmpP.B.count = P.r_u8(); P.r (&tmpP.B.data, tmpP.B.count); OnMessage (tmpP, sender); }; }break; case M_CL_UPDATE: { xrClientData* CL = ID_to_client (sender); if (!CL) break; CL->net_Ready = TRUE; if (!CL->net_PassUpdates) break; //------------------------------------------------------------------- u32 ClientPing = CL->stats.getPing(); P.w_seek(P.r_tell()+2, &ClientPing, 4); //------------------------------------------------------------------- if (SV_Client) SendTo (SV_Client->ID, P, net_flags(TRUE, TRUE)); VERIFY (verify_entities()); }break; case M_MOVE_PLAYERS_RESPOND: { xrClientData* CL = ID_to_client (sender); if (!CL) break; CL->net_Ready = TRUE; CL->net_PassUpdates = TRUE; }break; //------------------------------------------------------------------- case M_CL_PING_CHALLENGE: { P.r_u32(); u32 id = sender.value(); P.w_seek( P.r_tell(), &(id), 4); if (SV_Client) SendTo (SV_Client->ID, P, net_flags(FALSE)); }break; case M_CL_PING_CHALLENGE_RESPOND: { P.r_u32(); u32 id = P.r_u32(); ClientID clientID; clientID.set(id); u32 clLastPing = P.r_u32(); xrClientData* pCL = ID_to_client(clientID); pCL->ps->Rping = u16(clLastPing); SendTo (clientID, P, net_flags(FALSE)); }break; //------------------------------------------------------------------- case M_CL_INPUT: { xrClientData* CL = ID_to_client (sender); if (CL) CL->net_Ready = TRUE; if (SV_Client) SendTo (SV_Client->ID, P, net_flags(TRUE, TRUE)); VERIFY (verify_entities()); }break; case M_GAMEMESSAGE: { ClientID clientID;clientID.setBroadcast(); SendBroadcast (clientID,P,net_flags(TRUE,TRUE)); VERIFY (verify_entities()); }break; case M_CLIENTREADY: { xrClientData* CL = ID_to_client(sender); if (CL) { CL->net_Ready = TRUE; CL->ps->DeathTime = Device.dwTimeGlobal; game->OnPlayerConnectFinished(sender); }; game->signal_Syncronize (); VERIFY (verify_entities()); }break; case M_SWITCH_DISTANCE: { game->switch_distance (P,sender); VERIFY (verify_entities()); }break; case M_CHANGE_LEVEL: { if (game->change_level(P,sender)){ ClientID clientID;clientID.setBroadcast(); SendBroadcast (clientID,P,net_flags(TRUE,TRUE)); } VERIFY (verify_entities()); }break; case M_SAVE_GAME: { game->save_game (P,sender); VERIFY (verify_entities()); }break; case M_LOAD_GAME: { game->load_game (P,sender); ClientID clientID;clientID.setBroadcast(); SendBroadcast (clientID,P,net_flags(TRUE,TRUE)); VERIFY (verify_entities()); }break; case M_RELOAD_GAME: { ClientID clientID;clientID.setBroadcast(); SendBroadcast (clientID,P,net_flags(TRUE,TRUE)); VERIFY (verify_entities()); }break; case M_SAVE_PACKET: { Process_save (P,sender); VERIFY (verify_entities()); }break; case M_CLIENT_REQUEST_CONNECTION_DATA: { xrClientData* CL = ID_to_client (sender); OnCL_Connected (CL); }break; case M_CHAT_MESSAGE: { xrClientData *l_pC = ID_to_client(sender); OnChatMessage (&P, l_pC); }break; case M_CHANGE_LEVEL_GAME: { ClientID CID; CID.set (0xffffffff); SendBroadcast (CID,P,net_flags(TRUE,TRUE)); }break; case M_CL_AUTH: { game->AddDelayedEvent (P,GAME_EVENT_PLAYER_AUTH, 0, sender); }break; case M_PAUSE_GAME: { ClientID clientID;clientID.setBroadcast(); SendBroadcast (clientID,P,net_flags(TRUE,TRUE)); }break; case M_STATISTIC_UPDATE: { ClientID clientID;clientID.setBroadcast(); if (SV_Client) SendBroadcast (SV_Client->ID,P,net_flags(TRUE,TRUE)); else SendBroadcast (clientID,P,net_flags(TRUE,TRUE)); }break; case M_STATISTIC_UPDATE_RESPOND: { if (SV_Client) SendTo (SV_Client->ID, P, net_flags(TRUE, TRUE)); }break; case M_PLAYER_FIRE: { if (game) game->OnPlayerFire(sender, P); }break; } VERIFY (verify_entities()); csPlayers.Leave (); return IPureServer::OnMessage(P, sender); }
void xrServer::Process_event (NET_Packet& P, ClientID sender) { # ifdef SLOW_VERIFY_ENTITIES VERIFY (verify_entities()); # endif u32 timestamp; u16 type; u16 destination; u32 MODE = net_flags(TRUE,TRUE); // correct timestamp with server-unique-time (note: direct message correction) P.r_u32 (timestamp ); // read generic info P.r_u16 (type ); P.r_u16 (destination); CSE_Abstract* receiver = game->get_entity_from_eid (destination); if (receiver) { R_ASSERT(receiver->owner); receiver->OnEvent (P,type,timestamp,sender); }; switch (type) { case GE_GAME_EVENT: { u16 game_event_type; P.r_u16(game_event_type); game->AddDelayedEvent(P,game_event_type,timestamp,sender); }break; case GE_INFO_TRANSFER: case GE_WPN_STATE_CHANGE: case GE_ZONE_STATE_CHANGE: case GE_ACTOR_JUMPING: case GEG_PLAYER_PLAY_HEADSHOT_PARTICLE: case GEG_PLAYER_ATTACH_HOLDER: case GEG_PLAYER_DETACH_HOLDER: case GEG_PLAYER_ITEM2SLOT: case GEG_PLAYER_ITEM2BELT: case GEG_PLAYER_ITEM2RUCK: case GE_GRENADE_EXPLODE: { SendBroadcast (BroadcastCID,P,MODE); }break; case GEG_PLAYER_ACTIVATEARTEFACT: { Process_event_activate (P,sender,timestamp,destination,P.r_u16(), true); break; }; case GE_INV_ACTION: { xrClientData* CL = ID_to_client(sender); if (CL) CL->net_Ready = TRUE; if (SV_Client) SendTo(SV_Client->ID, P, net_flags(TRUE, TRUE)); }break; case GE_RESPAWN: { CSE_Abstract* E = receiver; if (E) { R_ASSERT (E->s_flags.is(M_SPAWN_OBJECT_PHANTOM)); svs_respawn R; R.timestamp = timestamp + E->RespawnTime*1000; R.phantom = destination; q_respawn.insert (R); } } break; case GE_TRADE_BUY: case GE_OWNERSHIP_TAKE: { Process_event_ownership (P,sender,timestamp,destination); VERIFY (verify_entities()); }break; case GE_OWNERSHIP_TAKE_MP_FORCED: { Process_event_ownership (P,sender,timestamp,destination,TRUE); VERIFY (verify_entities()); }break; case GE_TRADE_SELL: case GE_OWNERSHIP_REJECT: case GE_LAUNCH_ROCKET: { Process_event_reject (P,sender,timestamp,destination,P.r_u16()); VERIFY (verify_entities()); }break; case GE_DESTROY: { Process_event_destroy (P,sender,timestamp,destination, NULL); VERIFY (verify_entities()); } break; case GE_TRANSFER_AMMO: { u16 id_entity; P.r_u16 (id_entity); CSE_Abstract* e_parent = receiver; // кто забирает (для своих нужд) CSE_Abstract* e_entity = game->get_entity_from_eid (id_entity); // кто отдает if (!e_entity) break; if (0xffff != e_entity->ID_Parent) break; // this item already taken xrClientData* c_parent = e_parent->owner; xrClientData* c_from = ID_to_client (sender); R_ASSERT (c_from == c_parent); // assure client ownership of event // Signal to everyone (including sender) SendBroadcast (BroadcastCID,P,MODE); // Perfrom real destroy entity_Destroy (e_entity ); VERIFY (verify_entities()); } break; case GE_HIT: case GE_HIT_STATISTIC: { P.r_pos -=2; if (type == GE_HIT_STATISTIC) { P.B.count -= 4; P.w_u32(sender.value()); }; game->AddDelayedEvent(P,GAME_EVENT_ON_HIT, 0, ClientID() ); } break; case GE_ASSIGN_KILLER: { u16 id_src; P.r_u16 (id_src); CSE_Abstract *e_dest = receiver; // кто умер // this is possible when hit event is sent before destroy event if (!e_dest) break; CSE_ALifeCreatureAbstract *creature = smart_cast<CSE_ALifeCreatureAbstract*>(e_dest); if (creature) creature->set_killer_id( id_src ); // Msg ("[%d][%s] killed [%d][%s]",id_src,id_src==u16(-1) ? "UNKNOWN" : game->get_entity_from_eid(id_src)->name_replace(),id_dest,e_dest->name_replace()); break; } case GE_CHANGE_VISUAL: { CSE_Visual* visual = smart_cast<CSE_Visual*>(receiver); VERIFY(visual); string256 tmp; P.r_stringZ (tmp); visual->set_visual (tmp); }break; case GE_DIE: { // Parse message u16 id_dest = destination, id_src; P.r_u16 (id_src); xrClientData *l_pC = ID_to_client(sender); VERIFY (game && l_pC); #ifndef MASTER_GOLD if ((game->Type() != eGameIDSingle) && l_pC && l_pC->owner) { Msg ("* [%2d] killed by [%2d] - sended by [%s:%2d]", id_dest, id_src, game->get_option_s(*l_pC->name,"name","Player"), l_pC->owner->ID); } #endif // #ifndef MASTER_GOLD CSE_Abstract* e_dest = receiver; // кто умер // this is possible when hit event is sent before destroy event if (!e_dest) break; #ifndef MASTER_GOLD if (game->Type() != eGameIDSingle) Msg ("* [%2d] is [%s:%s]", id_dest, *e_dest->s_name, e_dest->name_replace()); #endif // #ifndef MASTER_GOLD CSE_Abstract* e_src = game->get_entity_from_eid (id_src ); // кто убил if (!e_src) { xrClientData* C = (xrClientData*) game->get_client(id_src); if (C) e_src = C->owner; }; VERIFY (e_src); if (!e_src) { Msg("! ERROR: SV: src killer not exist."); return; } // R_ASSERT2 (e_dest && e_src, "Killer or/and being killed are offline or not exist at all :("); #ifndef MASTER_GOLD if (game->Type() != eGameIDSingle) Msg ("* [%2d] is [%s:%s]", id_src, *e_src->s_name, e_src->name_replace()); #endif // #ifndef MASTER_GOLD game->on_death (e_dest,e_src); xrClientData* c_src = e_src->owner; // клиент, чей юнит убил if (c_src->owner->ID == id_src) { // Main unit P.w_begin (M_EVENT); P.w_u32 (timestamp); P.w_u16 (type); P.w_u16 (destination); P.w_u16 (id_src); P.w_clientID (c_src->ID); } SendBroadcast (BroadcastCID,P,MODE); ////////////////////////////////////////////////////////////////////////// // if (game->Type() == eGameIDSingle) { P.w_begin (M_EVENT); P.w_u32 (timestamp); P.w_u16 (GE_KILL_SOMEONE); P.w_u16 (id_src); P.w_u16 (destination); SendTo (c_src->ID, P, net_flags(TRUE, TRUE)); } ////////////////////////////////////////////////////////////////////////// VERIFY (verify_entities()); } break; case GE_ADDON_ATTACH: case GE_ADDON_DETACH: case GE_CHANGE_POS: { SendTo(SV_Client->ID, P, net_flags(TRUE, TRUE)); }break; case GE_INSTALL_UPGRADE: { shared_str upgrade_id; P.r_stringZ ( upgrade_id ); CSE_ALifeInventoryItem* iitem = smart_cast<CSE_ALifeInventoryItem*>( receiver ); if ( !iitem ) { break; } iitem->add_upgrade ( upgrade_id ); }break; case GEG_PLAYER_DISABLE_SPRINT: case GEG_PLAYER_WEAPON_HIDE_STATE: { SendTo (SV_Client->ID, P, net_flags(TRUE, TRUE)); # ifdef SLOW_VERIFY_ENTITIES VERIFY (verify_entities()); # endif }break; case GEG_PLAYER_ACTIVATE_SLOT: case GEG_PLAYER_ITEM_EAT: { SendTo(SV_Client->ID, P, net_flags(TRUE, TRUE)); # ifdef SLOW_VERIFY_ENTITIES VERIFY (verify_entities()); # endif }break; case GEG_PLAYER_ITEM_SELL: { game->OnPlayer_Sell_Item(sender, P); }break; case GE_TELEPORT_OBJECT: { game->teleport_object (P,destination); }break; case GE_ADD_RESTRICTION: { game->add_restriction (P,destination); }break; case GE_REMOVE_RESTRICTION: { game->remove_restriction(P,destination); }break; case GE_REMOVE_ALL_RESTRICTIONS: { game->remove_all_restrictions(P,destination); }break; case GE_MONEY: { CSE_Abstract *e_dest = receiver; CSE_ALifeTraderAbstract* pTa = smart_cast<CSE_ALifeTraderAbstract*>(e_dest); pTa->m_dwMoney = P.r_u32(); }break; case GE_FREEZE_OBJECT: break; default: R_ASSERT2 (0,"Game Event not implemented!!!"); break; } }
void xrServer::Update () { NET_Packet Packet; u32 position; csPlayers.Enter (); VERIFY (verify_entities()); // game update game->ProcessDelayedEvent(); game->Update (); // spawn queue u32 svT = Device.TimerAsync(); while (!(q_respawn.empty() || (svT<q_respawn.begin()->timestamp))) { // get svs_respawn R = *q_respawn.begin(); q_respawn.erase (q_respawn.begin()); // CSE_Abstract* E = ID_to_entity(R.phantom); E->Spawn_Write (Packet,FALSE); u16 ID; Packet.r_begin (ID); R_ASSERT(M_SPAWN==ID); ClientID clientID; clientID.set(0xffff); Process_spawn (Packet,clientID); } // for (u32 client=0; client<net_Players.size(); ++client) { // Initialize process and check for available bandwidth xrClientData* Client = (xrClientData*) net_Players [client]; if (!Client->net_Ready) continue; if (!HasBandwidth(Client) #ifdef DEBUG && !g_sv_SendUpdate #endif ) continue; // Send relevant entities to client // CSE_Abstract* Base = Client->owner; u16 PacketType = M_UPDATE; Packet.w_begin (PacketType); // GameUpdate ++(Client->game_replicate_id); u32 g_it = (Client->game_replicate_id % client_Count()); // u32 g_id = net_Players[g_it]->ID; ClientID g_id = net_Players[g_it]->ID; game->net_Export_Update (Packet,Client->ID,g_id); // if (!Client->flags.bLocal) game->net_Export_GameTime(Packet); if (!Client->flags.bLocal || client_Count() == 1) { #ifdef DEBUG if (g_Dump_Update_Write) Msg("---- UPDATE_Write to %s --- ", *(Client->Name)); #endif // Entities NET_Packet tmpPacket; xrS_entities::iterator I=entities.begin(),E=entities.end(); for (; I!=E; ++I) { CSE_Abstract& Test = *(I->second); if (0==Test.owner) continue; // Phantom(?) if (!Test.net_Ready) continue; if (Test.owner == Client && Client->flags.bLocal) continue; // Can't be relevant if (Test.s_flags.is(M_SPAWN_OBJECT_PHANTOM)) continue; // Surely: phantom tmpPacket.B.count = 0; // write specific data { tmpPacket.w_u16 (Test.ID ); tmpPacket.w_chunk_open8 (position ); Test.UPDATE_Write (tmpPacket ); #ifdef DEBUG if (g_Dump_Update_Write) Msg("* %s : %d", Test.name(), u32(tmpPacket.w_tell()-position)-sizeof(u8)); #endif tmpPacket.w_chunk_close8 (position ); if (Packet.B.count + tmpPacket.B.count < NET_PacketSizeLimit) { Packet.w(tmpPacket.B.data, tmpPacket.B.count); } else { if (Packet.B.count > 2) { // if (!Client->flags.bLocal) // Msg ("- Server Update[%d] to Client : %d", PacketType, Packet.B.count); SendTo (Client->ID,Packet,net_flags(FALSE,TRUE)); } PacketType = M_UPDATE_OBJECTS; Packet.w_begin(PacketType); } } } #ifdef DEBUG if (g_Dump_Update_Write) Msg("----------------------- "); #endif }; if (Packet.B.count > 2) { // if (!Client->flags.bLocal) // Msg ("- Server Update[%d] to Client : %d", PacketType, Packet.B.count); SendTo (Client->ID,Packet,net_flags(FALSE,TRUE)); } } #ifdef DEBUG g_sv_SendUpdate = 0; #endif if (game->sv_force_sync) Perform_game_export(); VERIFY (verify_entities()); //----------------------------------------------------- //Remove any of long time disconnected players for (u32 DI = 0; DI<net_Players_disconnected.size(); DI++) { IClient* CL = net_Players_disconnected[DI]; if (CL->dwTime_LastUpdate+g_sv_Client_Reconnect_Time*60000<Device.dwTimeGlobal) client_Destroy(CL); } //----------------------------------------------------- csPlayers.Leave (); }