1 #pragma once 2 3 #include "stdafx.h" 4 5 class Snapshotable; 6 7 template<typename T> 8 struct ArrayInfo 9 { 10 T* Array; 11 uint32_t ElementCount; 12 }; 13 14 template<typename T> 15 struct VectorInfo 16 { 17 vector<T>* Vector; 18 }; 19 20 template<typename T> 21 struct ValueInfo 22 { 23 T* Value; 24 T DefaultValue; 25 }; 26 27 struct SnapshotInfo 28 { 29 Snapshotable* Entity; 30 }; 31 32 template<typename T> 33 struct EmptyInfo 34 { 35 T Empty; 36 }; 37 38 class Snapshotable 39 { 40 private: 41 uint8_t* _stream; 42 uint32_t _position; 43 uint32_t _streamSize; 44 uint32_t _stateVersion = 0; 45 46 bool _inBlock = false; 47 uint8_t* _blockBuffer = nullptr; 48 uint32_t _blockSize = 0; 49 uint32_t _blockPosition = 0; 50 51 bool _saving; 52 53 private: EnsureCapacity(uint32_t typeSize)54 void EnsureCapacity(uint32_t typeSize) 55 { 56 //Make sure the current block/stream is large enough to fit the next write 57 uint32_t oldSize; 58 uint32_t sizeRequired; 59 uint8_t *oldBuffer; 60 if(_inBlock) { 61 oldBuffer = _blockBuffer; 62 oldSize = _blockSize; 63 sizeRequired = _blockPosition + typeSize; 64 } else { 65 oldBuffer = _stream; 66 oldSize = _streamSize; 67 sizeRequired = _position + typeSize; 68 } 69 70 uint8_t *newBuffer = nullptr; 71 uint32_t newSize = oldSize * 2; 72 if(oldSize < sizeRequired) { 73 while(newSize < sizeRequired) { 74 newSize *= 2; 75 } 76 77 newBuffer = new uint8_t[newSize]; 78 memcpy(newBuffer, oldBuffer, oldSize); 79 delete[] oldBuffer; 80 } 81 82 if(newBuffer) { 83 if(_inBlock) { 84 _blockBuffer = newBuffer; 85 _blockSize = newSize; 86 } else { 87 _stream = newBuffer; 88 _streamSize = newSize; 89 } 90 } 91 } 92 93 template<typename T> 94 void StreamElement(T &value, T defaultValue = T()) 95 { 96 if(_saving) { 97 uint8_t* bytes = (uint8_t*)&value; 98 int typeSize = sizeof(T); 99 100 EnsureCapacity(typeSize); 101 102 for(int i = 0; i < typeSize; i++) { 103 if(_inBlock) { 104 _blockBuffer[_blockPosition++] = bytes[i]; 105 } else { 106 _stream[_position++] = bytes[i]; 107 } 108 } 109 } else { 110 if(_inBlock) { 111 if(_blockPosition + sizeof(T) <= _blockSize) { 112 memcpy(&value, _blockBuffer + _blockPosition, sizeof(T)); 113 _blockPosition += sizeof(T); 114 } else { 115 value = defaultValue; 116 _blockPosition = _blockSize; 117 } 118 } else { 119 if(_position + sizeof(T) <= _streamSize) { 120 memcpy(&value, _stream + _position, sizeof(T)); 121 _position += sizeof(T); 122 } else { 123 value = defaultValue; 124 _position = _streamSize; 125 } 126 } 127 } 128 } 129 130 template<typename T> InternalStream(EmptyInfo<T> & info)131 void InternalStream(EmptyInfo<T> &info) 132 { 133 if(_inBlock) { 134 _blockPosition += sizeof(T); 135 } else { 136 _position += sizeof(T); 137 } 138 } 139 140 template<typename T> InternalStream(ArrayInfo<T> & info)141 void InternalStream(ArrayInfo<T> &info) 142 { 143 T* pointer = info.Array; 144 145 uint32_t count = info.ElementCount; 146 StreamElement<uint32_t>(count); 147 148 if(!_saving) { 149 //Reset array to 0 before loading from file 150 memset(info.Array, 0, sizeof(T) * info.ElementCount); 151 } 152 153 //Load the number of elements requested, or the maximum possible (based on what is present in the save state) 154 for(uint32_t i = 0; i < info.ElementCount && i < count; i++) { 155 StreamElement<T>(*pointer); 156 pointer++; 157 } 158 } 159 160 template<typename T> InternalStream(VectorInfo<T> & info)161 void InternalStream(VectorInfo<T> &info) 162 { 163 vector<T> *vector = info.Vector; 164 165 uint32_t count = (uint32_t)vector->size(); 166 StreamElement<uint32_t>(count); 167 168 if(!_saving) { 169 vector->resize(count); 170 memset(vector->data(), 0, sizeof(T)*count); 171 } 172 173 //Load the number of elements requested 174 T* pointer = vector->data(); 175 for(uint32_t i = 0; i < count; i++) { 176 StreamElement<T>(*pointer); 177 pointer++; 178 } 179 } 180 181 template<typename T> InternalStream(ValueInfo<T> & info)182 void InternalStream(ValueInfo<T> &info) 183 { 184 StreamElement<T>(*info.Value, info.DefaultValue); 185 } 186 187 template<typename T> InternalStream(T & value)188 void InternalStream(T &value) 189 { 190 StreamElement<T>(value); 191 } 192 InternalStream(SnapshotInfo & info)193 void InternalStream(SnapshotInfo &info) 194 { 195 if(info.Entity != nullptr) { 196 Stream(info.Entity); 197 } 198 } 199 RecursiveStream()200 void RecursiveStream() 201 { 202 } 203 204 template<typename T, typename... T2> RecursiveStream(T & value,T2 &...args)205 void RecursiveStream(T &value, T2&... args) 206 { 207 InternalStream(value); 208 RecursiveStream(args...); 209 } 210 211 void StreamStartBlock(); 212 void StreamEndBlock(); 213 214 protected: 215 virtual void StreamState(bool saving) = 0; 216 GetStateVersion()217 uint32_t GetStateVersion() { return _stateVersion; } 218 219 void Stream(Snapshotable* snapshotable); 220 221 template<typename... T> Stream(T &...args)222 void Stream(T&... args) 223 { 224 StreamStartBlock(); 225 RecursiveStream(args...); 226 StreamEndBlock(); 227 } 228 229 public: ~Snapshotable()230 virtual ~Snapshotable() {} 231 232 void SaveSnapshot(ostream* file); 233 void LoadSnapshot(istream* file, uint32_t stateVersion); 234 235 static void WriteEmptyBlock(ostream* file); 236 static void SkipBlock(istream* file); 237 };