#include #include #include #include #include namespace MyTypes { struct Monster { Monster() = default; Monster(std::string _name, uint32_t minDmg, uint32_t maxDmg) :name{_name}, minDamage{minDmg}, maxDamage{maxDmg} {} std::string name{}; uint32_t minDamage{}; uint32_t maxDamage{}; //... }; struct GameState { std::vector monsters; }; //default flow for monster template void serialize (S& s, Monster& o) { s.text1b(o.name, 20); s.value4b(o.minDamage); s.value4b(o.maxDamage); } template void serialize(S& s, GameState &o) { //we can have multiple types in context with std::tuple //this cast also works if our context is the same as cast auto maxMonsters = s.template context(); //all data from context is always pointer //if data type doesn't match then it will be compile time error auto dmgRange = s.template context>(); s.container(o.monsters, *maxMonsters, [&s, dmgRange] (Monster& m) { s.text1b(m.name, 20); //we know min/max damage range for monsters, so we can use this range instead of full value bitsery::ext::ValueRange range{dmgRange->first, dmgRange->second}; //enable bit packing s.enableBitPacking([&m, &range](typename S::BPEnabledType& sbp) { sbp.ext(m.minDamage, range); sbp.ext(m.maxDamage, range); }); }); } } using namespace bitsery; //use fixed-size buffer using Buffer = std::vector; using OutputAdapter = OutputBufferAdapter; using InputAdapter = InputBufferAdapter; //context can contain multiple types //it would make more sense to define separate structure for context, but for sake of this example make it more complex //in serialization function we can cast it like this: // s.template context(); //if we want to get whole tuple, just call s.context() without template paramter. //this templated version also works if our context is the same as cast: // struct MyContext {...}; // ... // s.template context(); using Context = std::tuple>; //NOTE: // if your context has no additional usage outside of serialization flow, // then you can create it internally via configuration (see inheritance.cpp) int main() { MyTypes::GameState data{}; data.monsters.push_back({"weaksy", 100, 200}); data.monsters.push_back({"bigsy", 500, 1000}); data.monsters.push_back({"tootoo", 350, 750}); //set context Context ctx{}; //max monsters std::get<0>(ctx) = 4; //damage range std::get<1>(ctx).first = 100; std::get<1>(ctx).second = 1000; //create buffer to store data to Buffer buffer{}; //pass game mode object to serializer as context BasicSerializer, Context> ser{buffer, &ctx}; ser.object(data); auto& w = AdapterAccess::getWriter(ser); w.flush(); auto writtenSize = w.writtenBytesCount(); MyTypes::GameState res{}; BasicDeserializer , Context> des { InputAdapter{buffer.begin(), writtenSize}, &ctx}; des.object(res); auto& r = AdapterAccess::getReader(des); assert(r.error() == ReaderError::NoError && r.isCompletedSuccessfully()); }