//===========================================================================// // File: Dictionary.cpp //---------------------------------------------------------------------------// // Date Who Modification // // -------- --- ---------------------------------------------------------- // // 01/06/1999 JSE Inital coding //---------------------------------------------------------------------------// // Copyright (C) 1998, Microsoft Corp. // // All Rights reserved worldwide // // This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL // //===========================================================================// #include "MW4Headers.hpp" #include "Dictionary.hpp" #include "MWEntityManager.hpp" #include "NetUpdateManager.hpp" #include "MWApplication.hpp" #include "Adept\NetStatCollector.hpp" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Scalar OneCycle = 2.0f; Scalar HerzPreSec[DictionaryPage::UpdateCycleCount] = { 0.5f, //double of the hrz since we are in a 2 second cycle.. 1.0f, 2.0f, 3.0f, 4.0f, 6.0f, 8.0f, 9.0f, 12.0f, 16.0f }; int Translation_Table[DictionaryPage::UpdateCycleCount] = { DictionaryPage::HalfhzType, DictionaryPage::OneHzType, DictionaryPage::TwoHzType, DictionaryPage::ThreeHzType, DictionaryPage::FourHzType, DictionaryPage::SixHzType, DictionaryPage::EightHzType, DictionaryPage::NineHzType, DictionaryPage::TwelveHzType, DictionaryPage::SixteenHzType }; //########################################################################## //########################### DictionaryParagraph //########################################################################## DictionaryParagraph::DictionaryParagraph(): Plug(DefaultData), entitySlot(NULL) { activeUpdateCycle = 0x0; inactiveUpdateCycle = 0x0; active = true; activeCycle = -1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DictionaryParagraph::DictionaryParagraph(Entity *entity, int message_type, int active_update_cycle, int inactive_update_cycle): Plug(DefaultData), entitySlot(NULL) { Check_Object(entity); entitySlot.Add(entity); NetVerify(message_type > UpdateManager::BaseUpdateID); NetVerify(message_type < UpdateManager::UpdateCount); messageType = message_type; activeUpdateCycle = active_update_cycle; inactiveUpdateCycle = inactive_update_cycle; active = true; activeCycle = 0; entityVariableMessageSize = -1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DictionaryParagraph::~DictionaryParagraph() { } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DictionaryParagraph::Encode(Stuff::DynamicMemoryStream* memory_stream, int connection, int debug_level, int bandwidth) { Check_Object(memory_stream); Entity *entity = entitySlot.GetCurrent(); Check_Object(entity); ReplicatorID rep_id = entity->GetReplicatorID(); UpdateEntry *update = &UpdateManager::UpdateEntries[messageType]; (update->m_encode)(entity, memory_stream, connection, debug_level, bandwidth); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DictionaryParagraph::Decode(Stuff::MemoryStream* memory_stream, Time till, Scalar packet_latency, int connection, int debug_level, int bandwidth) { Check_Object(memory_stream); Entity *entity = entitySlot.GetCurrent(); if (entity != NULL) { Check_Object(entity); ReplicatorID rep_id = entity->GetReplicatorID(); UpdateEntry *update = &UpdateManager::UpdateEntries[messageType]; int rate_type = BitDepthManager::GetUpdateRate(update->m_updateID, bandwidth).m_ActiveRate; Scalar rate = DictionaryPage::CalculateSeconds(rate_type); (*update->m_decode)(entity, memory_stream, till, packet_latency, connection, debug_level, bandwidth, rate); } else { UpdateEntry *update = &UpdateManager::UpdateEntries[messageType]; (*update->m_skip)(memory_stream, entityVariableMessageSize, till, connection, debug_level, bandwidth); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool DictionaryParagraph::ReadyToUpdate(int cycles_to_update) { if (active) { if (activeUpdateCycle & cycles_to_update) return true; } else { if (inactiveUpdateCycle & cycles_to_update) return true; } return false; } //########################################################################## //########################### DictionaryPage //########################################################################## //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DictionaryPage::DictionaryPage(int page_number): Plug(DefaultData), dictionaryParagraphs(NULL) { pageNumber = page_number; paragraphCount = 0; usedUpdateCycle = 0x0; lastExecuted = -2.0f; timeFromLastSlowestUpdate = 0.0f; lastPacketNumber = 0; for (int i = 0; i < UpdateCycleCount; ++i) { currentCycleCount[i] = 0; } if (pageNumber >= MaximumPages) STOP(("DictionaryPage::DictionaryPage:TOO MANY PAGES")); NetVerify(pageNumber > -1); NetVerify(pageNumber < MaximumPages); Time current_time = gos_GetElapsedTime(); for (i = 0; i < 8; ++i) { activeCycles[i] = current_time; current_time += 0.25; } currentActiveCycle = 0; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DictionaryPage::~DictionaryPage() { Stuff::ChainIteratorOf iterator(&dictionaryParagraphs); Stuff::Plug *plug; while ((plug = iterator.GetCurrent()) != NULL) { iterator.Remove(); Check_Object(plug); delete plug; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DictionaryPage::Encode(Stuff::DynamicMemoryStream* memory_stream, int connection, int debug_level, int bandwidth) { Check_Object(memory_stream); Stuff::ChainIteratorOf iterator(&dictionaryParagraphs); int paragraph_count = 0; ++lastPacketNumber; if (lastPacketNumber == 255) lastPacketNumber = 0; MWEntityManager *manager = Cast_Object(MWEntityManager*, EntityManager::GetInstance()); NetVerify(manager->serverController != NULL); Scalar current_time = (float)(gos_GetElapsedTime(1) * 1000.0); memory_stream->WriteBits(&lastPacketNumber, 8); memory_stream->WriteBits(&manager->serverController->lastPingDelta[connection], 32); memory_stream->WriteBits(¤t_time, 32); //SPEWALWAYS(("jerryeds", "S-SEND - %d : t2-t1 : %f, t3 : %f", lastPacketNumber, manager->serverController->lastPingDelta[connection], current_time)); //SPEW(("jerryeds", "ENCODE: packet %d", lastPacketNumber)); //SPEW(("jerryeds", "ENCODE: t1 %d", manager->serverController->lastPingDelta[connection])); //SPEW(("jerryeds", "ENCODE: t2 %d", current_time)); if (debug_level > 1) { BYTE magic_number = 0xAA; memory_stream->WriteBits(&magic_number, 8); //SPEW(("jerryeds", "ENCODE: MAGIC")); Network::GetInstance()->netStatCollector[Network::OutgoingHeaderBitSizeStat].AddToStatistic(connection,8); } DictionaryParagraph *paragraph; while ((paragraph = iterator.ReadAndNext()) != NULL) { if (paragraph->ReadyToUpdate(cyclesToUpdate)) { memory_stream->WriteBit(true); paragraph->Encode(memory_stream, connection, debug_level, bandwidth); } else { memory_stream->WriteBit(false); } if (debug_level > 1) { memory_stream->WriteBits(¶graph_count, 8); Network::GetInstance()->netStatCollector[Network::OutgoingHeaderBitSizeStat].AddToStatistic(connection,8); } ++paragraph_count; } if (debug_level > 0) { BYTE magic_number = 0xAA; memory_stream->WriteBits(&magic_number, 8); Network::GetInstance()->netStatCollector[Network::OutgoingHeaderBitSizeStat].AddToStatistic(connection,8); } Network::GetInstance()->netStatCollector[Network::OutgoingHeaderBitSizeStat].AddToStatistic(connection,paragraph_count + 8); Network::GetInstance()->netStatCollector[Network::OutgoingHeaderBitSizeStat].AddToStatistic(connection,64); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DictionaryPage::Decode(Stuff::MemoryStream* memory_stream, Time till, int connection, int debug_level, int bandwidth) { Check_Object(memory_stream); // throw out old ones BYTE packet_number; Scalar t2_minus_t1; Scalar t3; memory_stream->ReadBits(&packet_number, 8); memory_stream->ReadBits(&t2_minus_t1, 32); memory_stream->ReadBits(&t3, 32); //SPEW(("jerryeds", "DECODE: packet %d", packet_number)); //SPEW(("jerryeds", "DECODE: t1 %d", t2_minus_t1)); //SPEW(("jerryeds", "DECODE: t2 %d", t3)); if (debug_level > 1) { BYTE magic_number = 0; memory_stream->ReadBits(&magic_number, 8); Network::GetInstance()->netStatCollector[Network::IncomingHeaderBitSizeStat].AddToStatistic(connection,8); //SPEW(("jerryeds", "DECODE: MAGIC")); if(magic_number != 0xAA) { STOP(("UPDATE HEADER PAGE READ ERROR: %d",pageNumber)); } } //SPEWALWAYS(("jerryeds", "DICTIONARY LATENCY : %f", packet_latency)); if (MWEntityManager::IsNumberBehind(packet_number, lastPacketNumber, 40, 255)) { #if defined(LAB_ONLY) SPEWALWAYS(("jerryeds", "LATE DICTIONARY PACKET THROWN OUT")); #endif return; } MWEntityManager *manager = Cast_Object(MWEntityManager*, EntityManager::GetInstance()); Scalar t4 = (float)(gos_GetElapsedTime(1) * 1000.0); manager->clientController->lastPingDelta = t4 - t3; MWApplication::GetInstance()->servedConnectionData[connection].effectivePing = t2_minus_t1 + (t4 - t3); //SPEWALWAYS(("jerryeds", "C-REC - %d : t2-t1 : %f, t4-t3 %f : t3 : %f t4 : %f", packet_number, t2_minus_t1, t4 - t3, t3, t4)); Scalar packet_latency = MWApplication::GetInstance()->servedConnectionData[connection].effectivePing * 0.5f; Min_Clamp(packet_latency, 1.0f); packet_latency *= 0.001f; //SPEWALWAYS(("jerryeds", "latency : %f\n", packet_latency)); lastPacketNumber = packet_number; lastExecuted = till; Stuff::ChainIteratorOf iterator(&dictionaryParagraphs); int paragraph_count = 0; DictionaryParagraph *paragraph; while ((paragraph = iterator.ReadAndNext()) != NULL) { bool noskip_bit; memory_stream->ReadBit(noskip_bit); if (noskip_bit) paragraph->Decode(memory_stream, till, packet_latency, connection, debug_level, bandwidth); if (debug_level > 1) { int debug_paragraph_count = 0; memory_stream->ReadBits(&debug_paragraph_count, 8); Network::GetInstance()->netStatCollector[Network::IncomingHeaderBitSizeStat].AddToStatistic(connection,8); if (debug_paragraph_count != paragraph_count) { Entity *entity = paragraph->entitySlot.GetCurrent(); if (entity != NULL && entity->instanceName) { STOP(("UPDATE PARAGRAPH READ ERROR: %s : Page %d, Paragraph %d, Type %d", (char*)entity->instanceName, pageNumber, paragraph_count, paragraph->messageType)); } else { STOP(("UPDATE PARAGRAPH READ ERROR: NO ENTITY : Page %d, Paragraph %d, Type %d", pageNumber, paragraph_count, paragraph->messageType)); } } } ++paragraph_count; } if (debug_level > 0) { BYTE magic_number; memory_stream->ReadBits(&magic_number, 8); Network::GetInstance()->netStatCollector[Network::IncomingHeaderBitSizeStat].AddToStatistic(connection,8); if(magic_number != 0xAA) { STOP(("UPDATE PAGE READ ERROR: %d",pageNumber)); } } Network::GetInstance()->netStatCollector[Network::IncomingHeaderBitSizeStat].AddToStatistic(connection,paragraph_count+8); Network::GetInstance()->netStatCollector[Network::IncomingHeaderBitSizeStat].AddToStatistic(connection,64); } Scalar DictionaryPage::CalculateSeconds(int type) { Verify(type >= 0); Verify(type <= UpdateCycleCount); return 1.0f / HerzPreSec[type]; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int DictionaryPage::CalculateCycles(Time till) { Scalar time_slice = static_cast(till - lastExecuted); lastExecuted = till; //increment the time from the last full cycle. //The full cycle is OneCycle, which is also the //slowest cycle. timeFromLastSlowestUpdate += time_slice; // calculate the carryover if there is any. Scalar carryover = 0; int carryover_count = 0; if (timeFromLastSlowestUpdate > OneCycle) { // how many cycles it carried over carryover_count = (int)(timeFromLastSlowestUpdate / OneCycle); // how far past the last cycle it carried over carryover = timeFromLastSlowestUpdate - (carryover_count * OneCycle); } // calculate the cycle counts int cycle_triggers = 0x0; for (int i = 0; i < UpdateCycleCount; ++i) { // this is how many times this cycle should have triggered int cycles_triggered = (int)(timeFromLastSlowestUpdate*HerzPreSec[i]); // if we haven't triggered that many times than trigger one if (cycles_triggered > currentCycleCount[i]) { // add the cycle to the bit mask cycle_triggers |= (0x1<servedConnectionData[connection_id].vehiclePosition; // reset the counters for (int i = 0; i < 8; ++i) { flip[i] = false; if (till - activeCycles[i] > 2.0) { flip[i] = true; activeCycles[i] += 2.0; // deactivate any cylces that are on this cycle.. // if this is the largest time to flip this frame // than this is the currentactivecycle. if (largest_time < activeCycles[i]) { largest_time = activeCycles[i]; currentActiveCycle = i; } } } // maintain the paragraphs active states DictionaryParagraph *paragraph; Stuff::ChainIteratorOf iterator(&dictionaryParagraphs); while ((paragraph = iterator.ReadAndNext()) != NULL) { if (paragraph->active && flip[paragraph->activeCycle]) { paragraph->active = false; paragraph->activeCycle = -1; } UpdateEntry *update = &UpdateManager::UpdateEntries[paragraph->messageType]; if ((update->m_maintainActiveFlag)(paragraph->entitySlot.GetCurrent(), cull_location)) { paragraph->active = true; paragraph->activeCycle = currentActiveCycle; } if (paragraph->ReadyToUpdate(cyclesToUpdate)) { req_update = true; } } return req_update; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // bool DictionaryPage::RequireUpdate(Time new_time, int connection_id) { cyclesToUpdate = CalculateCycles(new_time); bool require_update = MaintainCycles(new_time, connection_id); return require_update; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DictionaryParagraph * DictionaryPage::MakeDictionaryParagraph(Entity *entity, int message_type, UpdateRate update_cycle) { usedUpdateCycle |= Translation_Table[update_cycle.m_ActiveRate]; usedUpdateCycle |= Translation_Table[update_cycle.m_InactiveRate]; DictionaryParagraph *paragraph = new DictionaryParagraph(entity, message_type, Translation_Table[update_cycle.m_ActiveRate], Translation_Table[update_cycle.m_InactiveRate]); Check_Object(paragraph); dictionaryParagraphs.Add(paragraph); ++paragraphCount; //NetVerify(paragraphCount < 64); return paragraph; } //########################################################################## //########################### Dictionary //########################################################################## //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Dictionary::Dictionary(int version_number, int connection, int debug_level, int bandwidth): Plug(DefaultData), dictionaryPages(NULL, true) { versionNumber = version_number; connectionID = connection; debugDictionaryLevel = debug_level; dictionaryBandwidth = bandwidth; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Dictionary::Dictionary(int version_number, int connection): Plug(DefaultData), dictionaryPages(NULL, true) { versionNumber = version_number; connectionID = connection; debugDictionaryLevel = -1; dictionaryBandwidth = -1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Dictionary::~Dictionary() { Stuff::SortedChainIteratorOf iterator(&dictionaryPages); Stuff::Plug *plug; while ((plug = iterator.GetCurrent()) != NULL) { iterator.Remove(); Check_Object(plug); delete plug; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Dictionary::Encode(Time till) { Stuff::SortedChainIteratorOf iterator(&dictionaryPages); DictionaryPage *page; while ((page = iterator.ReadAndNext()) != NULL) { if (page->RequireUpdate(till, connectionID)) { DynamicMemoryStream memory_stream(MWEntityManager::Packet_Buffer, DefaultPacketBufferSize); // make stream // write dictionary format memory_stream.WriteBits(&versionNumber, 8); //SPEW(("jerryeds", "ENCODE: version %d", versionNumber)); // write page data page->Encode(&memory_stream, connectionID, debugDictionaryLevel, dictionaryBandwidth); memory_stream.WriteByteAlign(); memory_stream.Rewind(); NetVerify(memory_stream.GetBufferBytesUsed() > 0); // send page Network::GetInstance()->SendNetMessage( connectionID, MWEntityManager::DictionaryPage0MessageID + page->pageNumber, &memory_stream, false); Network::GetInstance()->netStatCollector[Network::OutgoingHeaderBitSizeStat].AddToStatistic(connectionID,4); } } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void Dictionary::Decode(int message_type, Stuff::MemoryStream* memory_stream, Time till) { Check_Object(memory_stream); int version = 0; memory_stream->ReadBits(&version, 8); //SPEW(("jerryeds", "DECODE: version %d", version)); Network::GetInstance()->netStatCollector[Network::IncomingHeaderBitSizeStat].AddToStatistic(connectionID,4); if (version != versionNumber) return; Stuff::SortedChainIteratorOf iterator(&dictionaryPages); int page_index = message_type - MWEntityManager::DictionaryPage0MessageID; DictionaryPage *page = iterator.Find(page_index); if (page == NULL) STOP(("Dictionary::Decode : Page in dictionary not found")); Check_Object(page); page->Decode(memory_stream, till, Connection::Local->GetID(), debugDictionaryLevel, dictionaryBandwidth); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DictionaryPage * Dictionary::MakeDictionaryPage(int page_number) { NetVerify(page_number > -1); NetVerify(page_number < MaximumPages); DictionaryPage *page = new DictionaryPage(page_number); Check_Object(page); dictionaryPages.AddValue(page, page_number); return page; } //########################################################################## //########################### DictionaryManager //########################################################################## //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DictionaryManager::DictionaryManager(int connection): Plug(DefaultData), dictionaryIndex(NULL, true) { activeDictionaryIndex = -1; activeDictionary = NULL; connectionID = connection; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // DictionaryManager::~DictionaryManager() { Stuff::SortedChainIteratorOf iterator(&dictionaryIndex); Stuff::Plug *plug; while ((plug = iterator.GetCurrent()) != NULL) { iterator.Remove(); Check_Object(plug); delete plug; } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Dictionary * DictionaryManager::MakeNewDictionary(int version_number, int debug_level, int bandwidth) { // server keeps old copies but the client remove them SortedChainIteratorOf iterator(&dictionaryIndex); if (!Application::GetInstance()->serverFlag) { // clients remove all old dictionaries Stuff::SortedChainIteratorOf iterator(&dictionaryIndex); Stuff::Plug *plug; while ((plug = iterator.GetCurrent()) != NULL) { iterator.Remove(); Check_Object(plug); delete plug; } } else { // we are the server, we only care about the last one and the new one... // remove everything but the old one and the new one... Stuff::SortedChainIteratorOf iterator(&dictionaryIndex); Stuff::Plug *plug; while ((plug = iterator.GetCurrent()) != NULL) { if (iterator.GetValue() != activeDictionaryIndex) { iterator.Remove(); Check_Object(plug); delete plug; } else { iterator.Next(); } } } activeDictionaryIndex = version_number; activeDictionary = new Dictionary(activeDictionaryIndex, connectionID, debug_level, bandwidth); Check_Object(activeDictionary); Dictionary* test = dictionaryIndex.Find(activeDictionaryIndex); if (test != NULL) { Unregister_Object(test); delete (test); } dictionaryIndex.AddValue(activeDictionary, activeDictionaryIndex); return activeDictionary; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // int DictionaryManager::GetNextDictionaryID() { int next_dictionary = activeDictionaryIndex; if (next_dictionary == 254) { next_dictionary = 0; } else { ++next_dictionary; } return next_dictionary; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Dictionary * DictionaryManager::GetCurrentDictionary() { NetVerify(activeDictionaryIndex >= 0); Check_Object(activeDictionary); return activeDictionary; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Dictionary * DictionaryManager::GetDictionary(int version) { // if it is already here we need to remove it... SortedChainIteratorOf iterator(&dictionaryIndex); Dictionary *dictionary = iterator.Find(version); return dictionary; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DictionaryManager::Encode(Time till) { activeDictionary->Encode(till); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // void DictionaryManager::Decode(int message_type, Stuff::MemoryStream* memory_stream) { NetVerify(message_type >= MWEntityManager::DictionaryPage0MessageID && message_type <= MWEntityManager::DictionaryPageMaxMessageID); if (activeDictionary == NULL) return; // change till to the packet latency... activeDictionary->Decode(message_type, memory_stream, 0.0f); }