/* * Copyright (c) 2014, Oculus VR, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * */ #include "NativeTypes.hpp" #include "DS_List.hpp" #include "RakMemoryOverride.hpp" #include "BitStream.hpp" #ifndef __VARIABLE_LIST_DELTA_TRACKER #define __VARIABLE_LIST_DELTA_TRACKER namespace RakNet { /// Class to write a series of variables, copy the contents to memory, and return if the newly written value is different than what was last written /// Can also encode the reads, writes, and results directly to/from a bitstream class VariableListDeltaTracker { public: VariableListDeltaTracker(); ~VariableListDeltaTracker(); // Call before using a series of WriteVar void StartWrite(void); bool IsPastEndOfList(void) const {return nextWriteIndex>=variableList.Size();} /// Records the passed value of the variable to memory, and returns true if the value is different from the write before that (or if it is the first write) /// \pre Call StartWrite() before doing the first of a series of calls to WriteVar or other functions that call WriteVar /// \note Variables must be of the same type, written in the same order, each time template bool WriteVar(const VarType &varData) { RakNet::BitStream temp; temp.Write(varData); if (nextWriteIndex>=variableList.Size()) { variableList.Push(VariableLastValueNode(temp.GetData(),temp.GetNumberOfBytesUsed()),_FILE_AND_LINE_); nextWriteIndex++; return true; // Different because it's new } if (temp.GetNumberOfBytesUsed()!=variableList[nextWriteIndex].byteLength) { variableList[nextWriteIndex].lastData=(char*) rakRealloc_Ex(variableList[nextWriteIndex].lastData, temp.GetNumberOfBytesUsed(),_FILE_AND_LINE_); variableList[nextWriteIndex].byteLength=temp.GetNumberOfBytesUsed(); memcpy(variableList[nextWriteIndex].lastData,temp.GetData(),temp.GetNumberOfBytesUsed()); nextWriteIndex++; variableList[nextWriteIndex].isDirty=false; return true; // Different because the serialized size is different } if (variableList[nextWriteIndex].isDirty==false && memcmp(temp.GetData(),variableList[nextWriteIndex].lastData, variableList[nextWriteIndex].byteLength)==0) { nextWriteIndex++; return false; // Same because not dirty and memcmp is the same } variableList[nextWriteIndex].isDirty=false; memcpy(variableList[nextWriteIndex].lastData,temp.GetData(),temp.GetNumberOfBytesUsed()); nextWriteIndex++; return true; // Different because dirty or memcmp was different } /// Calls WriteVar. If the variable has changed, writes true, and writes the variable. Otherwise writes false. template bool WriteVarToBitstream(const VarType &varData, RakNet::BitStream *bitStream) { bool wasDifferent = WriteVar(varData); bitStream->Write(wasDifferent); if (wasDifferent) { bitStream->Write(varData); return true; } return false; } /// Calls WriteVarToBitstream(). Additionally, adds the boolean result of WriteVar() to boolean bit array template bool WriteVarToBitstream(const VarType &varData, RakNet::BitStream *bitStream, unsigned char *bArray, unsigned short writeOffset) { if (WriteVarToBitstream(varData,bitStream)==true) { BitSize_t numberOfBitsMod8 = writeOffset & 7; if ( numberOfBitsMod8 == 0 ) bArray[ writeOffset >> 3 ] = 0x80; else bArray[ writeOffset >> 3 ] |= 0x80 >> ( numberOfBitsMod8 ); // Set the bit to 1 return true; } else { if ( ( writeOffset & 7 ) == 0 ) bArray[ writeOffset >> 3 ] = 0; return false; } } /// Paired with a call to WriteVarToBitstream(), will read a variable if it had changed. Otherwise the values remains the same. template static bool ReadVarFromBitstream(VarType &varData, RakNet::BitStream *bitStream) { bool wasWritten; if (bitStream->Read(wasWritten)==false) return false; if (wasWritten) { if (bitStream->Read(varData)==false) return false; } return wasWritten; } /// Variables flagged dirty will cause WriteVar() to return true, even if the variable had not otherwise changed /// This updates all the variables in the list, where in each index \a varsWritten is true, so will the variable at the corresponding index be flagged dirty void FlagDirtyFromBitArray(unsigned char *bArray); /// \internal struct VariableLastValueNode { VariableLastValueNode(); VariableLastValueNode(const unsigned char *data, int _byteLength); ~VariableLastValueNode(); char *lastData; unsigned int byteLength; bool isDirty; }; protected: /// \internal DataStructures::List variableList; /// \internal unsigned int nextWriteIndex; }; } #endif