@@ -12,6 +12,12 @@ class AresByteStream : public std::vector<byte> {
this->reserve(Reserve);
};

// IStream operations

/**
* reads {Length} bytes from {pStm} into its storage
*/
public:
bool ReadFromStream(IStream *pStm, const size_t Length) {
this->reserve(this->size() + Length);
auto tmp = new byte[Length];
@@ -25,18 +31,94 @@ class AresByteStream : public std::vector<byte> {
return result;
}

/**
* writes all internal storage to {pStm}
*/
public:
bool WriteToStream(IStream *pStm) {
ULONG out;
const size_t Length(this->size());
auto pv = reinterpret_cast<void *>(this->data());
auto success = pStm->Write(pv, Length, &out);
return SUCCEEDED(success) && out == Length;
}


// primitive save/load - should not be specialized

/**
* if it has {Size} bytes left, casts the first {Size} unread bytes to a {<T>} and assigns it to {Value}
* moves the internal position forward
*/
public:
template<typename T>
bool Read(T &Value, const size_t Size) {
if(this->size() <= this->CurrentOffset + Size) {
return false;
}
auto Position = &this[this->CurrentOffset];
this->CurrentOffset += Size;
Value = *(reinterpret_cast<T *>(Position));
return true;
bool Read(T &Value, const size_t Size = sizeof(T));

/**
* ensures there are at least {Size} bytes left in the internal storage, casts those bytes to a {<T>} and assigns {Value} to that casted buffer
* moves the internal position forward
*/
public:
template<typename T>
bool Write(const T &Value, const size_t Size);


/**
* attempts to read the data from internal storage into {Value}
* updates {Offset} with the amount of data read, if successful
*/
public:
template<typename T>
bool Load(T &Value, size_t &Offset);

/**
* attempts to write the data from internal storage into {Value}
*/
public:
template<typename T>
bool Save(const T &Value);
};

template<typename T>
bool AresByteStream::Read(T &Value, const size_t Size) {
if(this->size() <= this->CurrentOffset + Size) {
return false;
}
auto Position = &this[this->CurrentOffset];
this->CurrentOffset += Size;
Value = *(reinterpret_cast<T *>(Position));
return true;
};

template<typename T>
bool AresByteStream::Write(const T &Value, const size_t Size) {
if(this->size() <= this->CurrentOffset + Size) {
this->reserve(this->CurrentOffset + Size);
}
auto Position = &this[this->CurrentOffset];
this->CurrentOffset += Size;
*(reinterpret_cast<T *>(Position)) = Value;
return true;
};

template<typename T>
bool AresByteStream::Load(T &Value, size_t &Offset) {
const auto sz = sizeof(T);
if(Offset + sz > this->size()) {
return false;
}
Offset += sz;
return this->Read(Value, sz);
}

template<typename T>
bool AresByteStream::Save(const T &Value) {
return this->Write(Value, sizeof(T));
};


// helper classes - voodoo power

template<typename T>
class AresStreamWriter {
public:
@@ -46,87 +128,106 @@ class AresStreamWriter {
template<typename T>
class AresStreamReader {
public:
AresStreamReader(AresByteStream &Stm, T &Value, bool RegisterForChange = false);
AresStreamReader(AresByteStream &Stm, T &Value, size_t &Offset, bool RegisterForChange = false);
};


// helper functions for type inference
// what an onion
namespace Savegame {
template <typename T>
AresStreamReader<T> ReadAresStream(AresByteStream &Stm, T &Value, size_t &Offset, bool RegisterForChange = false)
{ return AresStreamReader<T>(Stm, Value, Offset, RegisterForChange); }

template <typename T>
AresStreamReader<VectorClass<T>> ReadAresStream(AresByteStream &Stm, VectorClass<T> &Value, size_t &Offset, bool RegisterForChange)
{ return AresStreamReader<VectorClass<T>>(Stm, Value, Offset, RegisterForChange); }

template <typename T>
AresStreamReader<DynamicVectorClass<T>> ReadAresStream(AresByteStream &Stm, DynamicVectorClass<T> &Value, size_t &Offset, bool RegisterForChange)
{ return AresStreamReader<DynamicVectorClass<T>>(Stm, Value, Offset, RegisterForChange); }

template <typename T>
AresStreamWriter<T> WriteAresStream(AresByteStream &Stm, const T &Value)
{ return AresStreamWriter<T>(Stm, Value); }

template <typename T>
AresStreamWriter<VectorClass<T>> WriteAresStream(AresByteStream &Stm, const VectorClass<T> &Value)
{ return AresStreamWriter<VectorClass<T>>(Stm, Value); }

template <typename T>
AresStreamWriter<DynamicVectorClass<T>> WriteAresStream(AresByteStream &Stm, const DynamicVectorClass<T> &Value)
{ return AresStreamWriter<DynamicVectorClass<T>>(Stm, Value); }
};


template<typename T>
AresStreamWriter<T>::AresStreamWriter(AresByteStream &Stm, const T &Value) {
const auto sz = sizeof(T);
Stm.reserve(Stm.size() + sz);
auto ptr = reinterpret_cast<const byte *>(&Value);
Stm.insert(Stm.end(), ptr, ptr + sz);
Stm.Save(Value);
};

template<typename T>
AresStreamReader<T>::AresStreamReader(AresByteStream &Stm, T &Value, bool RegisterForChange) {
const auto sz = sizeof(T);
Stm.Read(Value, sz);
AresStreamReader<T>::AresStreamReader(AresByteStream &Stm, T &Value, size_t &Offset, bool RegisterForChange) {
Stm.Load(Value, Offset);
if(RegisterForChange) {
AresSwizzle::Instance.RegisterPointerForChange(Value);
}
return true;
}

template<typename T>
inline bool AresByteStream::LoadFromStream(T &Value, const size_t Size, size_t &Offset, bool RegisterForChange) {
const auto sz = sizeof(T);
if(Offset >= Size) {
return false;
}
if(Offset + sz > Size) {
return false;
}
Offset += sz;
return this->LoadFromStream(Value, RegisterForChange);
}

template<typename T>
inline bool AresByteStream::LoadValueFromStream(T &Value, const size_t Size) {
return this->Read(Value, Size);
}
// specializations

/* template specifications to save/load more complex types */
template<typename T>
inline bool AresByteStream::SaveToStream(const DynamicVectorClass<T> &Value) {
this->SaveToStream(Value.Capacity);
this->SaveToStream(Value.IsInitialized);
this->SaveToStream(Value.Count);
this->SaveToStream(Value.CapacityIncrement);

for(auto ix = 0; ix < Value.Count; ++ix) {
this->SaveToStream(Value.Items[ix]);
}

return true;
class AresStreamWriter<DynamicVectorClass<T>> {
public:
AresStreamWriter(AresByteStream &Stm, const DynamicVectorClass<T> &Value) {
Stm.Save(Value.Capacity);
Stm.Save(Value.IsInitialized);
Stm.Save(Value.Count);
Stm.Save(Value.CapacityIncrement);

for(auto ix = 0; ix < Value.Count; ++ix) {
Stm.Save(Value.Items[ix]);
}
};
};

template<typename T>
inline bool AresByteStream::LoadValueFromStream(DynamicVectorClass<T> &Value, const size_t Size) {
Value.Purge();
int Capacity;
this->LoadValueFromStream(Capacity, sizeof(Capacity));
Value.SetCapacity(Capacity);
int Count;
this->LoadValueFromStream(Count, sizeof(Count));

this->LoadValueFromStream(Value.CapacityIncrement, sizeof(Value.CapacityIncrement));
for(auto ix = 0; ix < Count; ++ix) {
this->LoadFromStream(Value[ix]);
class AresStreamReader<DynamicVectorClass<T>> {
public:
AresStreamReader(AresByteStream &Stm, DynamicVectorClass<T> &Value, size_t &Offset, bool RegisterForChange) {
Value.Purge();
int Capacity;
Stm.Load(Capacity, Offset);
Value.SetCapacity(Capacity);
int Count;
Stm.Load(Count, Offset);

Stm.Load(Value.CapacityIncrement, sizeof(Value.CapacityIncrement));
for(auto ix = 0; ix < Count; ++ix) {
Stm.Load(Value[ix], Offset);
}
if(RegisterForChange) {
for(auto ix = 0; ix < Count; ++ix) {
AresSwizzle::Instance.RegisterPointerForChange(Value[ix]);
}
}
}
return true;
};

#include "../Ext/BuildingType/PrismForwarding.h"
#include "../Ext/Building/PrismForwarding.h"

template<>
inline bool AresByteStream::SaveToStream(const BuildingExtras::cPrismForwarding &Value) {
this->SaveToStream(Value.Senders);
this->SaveToStream(Value.SupportTarget);
this->SaveToStream(Value.PrismChargeDelay);
this->SaveToStream(Value.DamageReserve);
this->SaveToStream(Value.ModifierReserve);
return true;
class AresStreamWriter<BuildingExtras::cPrismForwarding> {
public:
AresStreamWriter(AresByteStream &Stm, const BuildingExtras::cPrismForwarding &Value) {
Savegame::WriteAresStream(Stm, Value.Senders);
Stm.Save(Value.SupportTarget);
Stm.Save(Value.PrismChargeDelay);
Stm.Save(Value.DamageReserve);
Stm.Save(Value.ModifierReserve);
}
};

#endif

@@ -59,33 +59,35 @@ class AresSwizzle {
void RegisterPointerForChange(T &ptr);
};

template<typename T>
class ObjectSwizzler {
public:
ObjectSwizzler(T &Object);
};

template<typename T>
void AresSwizzle::RegisterPointerForChange(T &ptr) {
this->RegisterForChange(reinterpret_cast<void **>(&ptr));
};

template<typename T>
void ObjectSwizzler<T>::ObjectSwizzler(T &Object) {
//nop
class ObjectSwizzler {
public:
ObjectSwizzler(T &Object) {
};
};

template<typename T>
void ObjectSwizzler<VectorClass<T> >::ObjectSwizzler(VectorClass<T> &Object) {
for (auto ii = 0; ii < Object.Capacity; ++ii) {
AresSwizzle::Instance.RegisterPointerForChange(&(Object.Items[ii]));
class ObjectSwizzler<VectorClass<T> > {
public:
ObjectSwizzler(VectorClass<T> &Object) {
for (auto ii = 0; ii < Object.Capacity; ++ii) {
AresSwizzle::Instance.RegisterPointerForChange(&(Object.Items[ii]));
}
}
};

template<typename T>
void ObjectSwizzler<DynamicVectorClass<T> >::ObjectSwizzler(DynamicVectorClass<T> &Object) {
for (auto ii = 0; ii < Object.Count; ++ii) {
AresSwizzle::Instance.RegisterPointerForChange(&(Object.Items[ii]));
class ObjectSwizzler<DynamicVectorClass<T> > {
public:
ObjectSwizzler(DynamicVectorClass<T> &Object) {
for (auto ii = 0; ii < Object.Count; ++ii) {
AresSwizzle::Instance.RegisterPointerForChange(&(Object.Items[ii]));
}
}
};