214 lines
6.4 KiB
C
214 lines
6.4 KiB
C
////////////////////////////////////////////////////////////
|
|
//~ World
|
|
|
|
String P_PackWorld(Arena *arena, P_World *src_world)
|
|
{
|
|
String result = Zi;
|
|
result.text = ArenaNext(arena, u8);
|
|
TempArena scratch = BeginScratch(arena);
|
|
P_Frame *src_frame = src_world->last_frame;
|
|
|
|
result.len += StringF(arena, "version: %F\n", FmtUint(P_Tv_Latest)).len;
|
|
|
|
result.len += StringF(arena, "\n").len;
|
|
result.len += StringF(arena, "seed: 0x%F\n", FmtHex(src_world->seed)).len;
|
|
result.len += StringF(arena, "time: %F\n", FmtSint(src_frame->time_ns)).len;
|
|
|
|
// Pack entities
|
|
// FIXME: Precision
|
|
result.len += PushString(arena, Lit("\nentities:\n")).len;
|
|
result.len += PushString(arena, Lit("{\n")).len;
|
|
for (P_Ent *ent = P_FirstEnt(src_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
|
{
|
|
// TODO: Pack bullets
|
|
if (!ent->is_bullet)
|
|
{
|
|
result.len += StringF(arena, " 0x%F:\n", FmtHex(ent->key.v)).len;
|
|
result.len += PushString(arena, Lit(" {\n")).len;
|
|
{
|
|
result.len += StringF(arena, " props: \n").len;
|
|
result.len += StringF(arena, " {\n").len;
|
|
{
|
|
if (ent->is_player)
|
|
{
|
|
result.len += PushString(arena, Lit(" player\n")).len;
|
|
}
|
|
if (ent->is_dummy)
|
|
{
|
|
result.len += PushString(arena, Lit(" dummy\n")).len;
|
|
}
|
|
if (ent->has_weapon)
|
|
{
|
|
result.len += PushString(arena, Lit(" has_weapon\n")).len;
|
|
}
|
|
if (ent->is_bullet)
|
|
{
|
|
result.len += PushString(arena, Lit(" bullet\n")).len;
|
|
}
|
|
}
|
|
result.len += StringF(arena, " }\n").len;
|
|
result.len += StringF(arena, " pos: \"%F\"\n", FmtFloat2(ent->xf.og)).len;
|
|
result.len += StringF(arena, " rot: \"%F\"\n", FmtFloat2(RightFromXform(ent->xf))).len;
|
|
result.len += StringF(arena, " exists: \"%F\"\n", FmtFloat(ent->exists)).len;
|
|
result.len += StringF(arena, " look: \"%F\"\n", FmtFloat2(ent->control.look)).len;
|
|
}
|
|
result.len += PushString(arena, Lit(" }\n")).len;
|
|
}
|
|
}
|
|
result.len += PushString(arena, Lit("}\n")).len;
|
|
|
|
// Pack tiles
|
|
// TODO: Compress tile data
|
|
result.len += PushString(arena, Lit("\ntiles:\n")).len;
|
|
result.len += PushString(arena, Lit("{\n")).len;
|
|
{
|
|
String tiles_str = Base64FromString(scratch.arena, STRING(P_TilesCount, src_world->tiles));
|
|
u64 tile_chars_per_line = 128;
|
|
u64 tile_char_pos = 0;
|
|
while (tile_char_pos < tiles_str.len)
|
|
{
|
|
result.len += PushString(arena, Lit(" ")).len;
|
|
String src = STRING(tile_chars_per_line, tiles_str.text + tile_char_pos);
|
|
src.len = MinU64(tile_chars_per_line, tiles_str.len - tile_char_pos);
|
|
result.len += PushString(arena, src).len;
|
|
result.len += PushString(arena, Lit("\n")).len;
|
|
tile_char_pos += tile_chars_per_line;
|
|
}
|
|
|
|
}
|
|
result.len += PushString(arena, Lit("}\n")).len;
|
|
|
|
EndScratch(scratch);
|
|
return result;
|
|
}
|
|
|
|
P_UnpackedWorld P_UnpackWorld(Arena *arena, String packed)
|
|
{
|
|
P_UnpackedWorld result = Zi;
|
|
TempArena scratch = BeginScratch(arena);
|
|
|
|
CR_Item *root = CR_ItemFromString(scratch.arena, packed);
|
|
|
|
// Unpack version
|
|
P_Tv version = 0;
|
|
for (CR_Item *root_item = root->first; root_item; root_item = root_item->next)
|
|
{
|
|
if (MatchString(root_item->name, Lit("version")))
|
|
{
|
|
version = CR_IntFromString(root_item->value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (CR_Item *top_item = root->first; top_item; top_item = top_item->next)
|
|
{
|
|
// Unpack metadata
|
|
if (MatchString(top_item->name, Lit("seed")))
|
|
{
|
|
result.seed = CR_IntFromString(top_item->value);
|
|
}
|
|
if (MatchString(top_item->name, Lit("time")))
|
|
{
|
|
result.time_ns = CR_IntFromString(top_item->value);
|
|
}
|
|
|
|
// Unpack entities
|
|
if (MatchString(top_item->name, Lit("entities")))
|
|
{
|
|
for (CR_Item *ent_item = top_item->first; ent_item; ent_item = ent_item->next)
|
|
{
|
|
P_Ent *ent = P_PushTempEnt(arena, &result.ents);
|
|
ent->key = (P_Key) { .v = CR_IntFromString(ent_item->name) };
|
|
for (CR_Item *attr = ent_item->first; attr; attr = attr->next)
|
|
{
|
|
if (MatchString(attr->name, Lit("props")))
|
|
{
|
|
for (CR_Item *prop = attr->first; prop; prop = prop->next)
|
|
{
|
|
if (MatchString(prop->value, Lit("player")))
|
|
{
|
|
ent->is_player = 1;
|
|
}
|
|
if (MatchString(prop->value, Lit("dummy")))
|
|
{
|
|
ent->is_dummy = 1;
|
|
}
|
|
if (MatchString(prop->value, Lit("has_weapon")))
|
|
{
|
|
ent->has_weapon = 1;
|
|
}
|
|
if (MatchString(prop->value, Lit("bullet")))
|
|
{
|
|
ent->is_bullet = 1;
|
|
}
|
|
}
|
|
}
|
|
if (MatchString(attr->name, Lit("pos")))
|
|
{
|
|
Vec2 pos = CR_Vec2FromString(attr->value);
|
|
ent->xf.og = pos;
|
|
}
|
|
if (MatchString(attr->name, Lit("rot")))
|
|
{
|
|
Vec2 rot = CR_Vec2FromString(attr->value);
|
|
ent->xf = XformWithWorldRotation(ent->xf, AngleFromVec2(rot));
|
|
}
|
|
if (MatchString(attr->name, Lit("exists")))
|
|
{
|
|
ent->exists = CR_FloatFromString(attr->value);
|
|
}
|
|
if (MatchString(attr->name, Lit("health")))
|
|
{
|
|
ent->health = CR_FloatFromString(attr->value);
|
|
}
|
|
if (MatchString(attr->name, Lit("look")))
|
|
{
|
|
Vec2 look = CR_Vec2FromString(attr->value);
|
|
ent->control.look = look;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Parse tiles
|
|
String tiles_base64 = Zi;
|
|
tiles_base64.text = ArenaNext(scratch.arena, u8);
|
|
for (CR_Item *tile_item = top_item->first; tile_item; tile_item = tile_item->next)
|
|
{
|
|
if (tile_item->name.len == 0)
|
|
{
|
|
tiles_base64.len += PushString(scratch.arena, tile_item->value).len;
|
|
}
|
|
}
|
|
if (StringLenFromBase64Len(tiles_base64.len) == P_TilesCount)
|
|
{
|
|
result.tiles = StringFromBase64(arena, tiles_base64).text;
|
|
}
|
|
}
|
|
|
|
if (!result.tiles)
|
|
{
|
|
result.tiles = PushStructs(arena, u8, P_TilesCount);
|
|
}
|
|
|
|
EndScratch(scratch);
|
|
return result;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////
|
|
//~ Message
|
|
|
|
String P_PackMessage(Arena *arena, P_Msg *msg)
|
|
{
|
|
String result = Zi;
|
|
// TODO
|
|
return result;
|
|
}
|
|
|
|
P_Msg P_UnpackMsg(Arena *arena, String packed)
|
|
{
|
|
P_Msg result = Zi;
|
|
// TODO
|
|
return result;
|
|
}
|