#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 //if data type doesn't match then it will be compile time error //NOTE: if context is optional then you can call contextOrNull, and it will return null if T doesn't exists auto maxMonsters = s.template context(); auto& dmgRange = s.template context>(); s.container(o.monsters, maxMonsters, [&dmgRange] (S& s, 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); }); }); } } //context can contain multiple types by wrapping these types in std::tuple //in serialization function we can get type that we need like this: // s.template context(); //this templated version also works if our context is the same as cast: // struct MyContext {...}; // ... // s.template context(); //NOTE: // if your context has no additional usage outside of serialization flow, // then you can create it internally via configuration (see inheritance.cpp) using Context = std::tuple>; //use fixed-size buffer using Buffer = std::vector; using namespace bitsery; // define adapter types, using OutputAdapter = OutputBufferAdapter; using InputAdapter = InputBufferAdapter; 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{}; auto writtenSize = quickSerialization(ctx, OutputAdapter{buffer}, data); MyTypes::GameState res{}; auto state = quickDeserialization(ctx, InputAdapter{buffer.begin(), writtenSize}, res); assert(state.first == ReaderError::NoError && state.second); }