begin structuring sim for networking
This commit is contained in:
parent
54b1759afe
commit
25a8a3c39a
@ -750,7 +750,7 @@
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Basic mixing/hashing
|
||||
//~ Basic mixing
|
||||
|
||||
// Based on Jon Maiga's "mx3"
|
||||
// https://jonkagstrom.com/mx3/mx3_rev2.html
|
||||
@ -768,23 +768,6 @@ Inline u64 MixU64s(u64 seed_a, u64 seed_b)
|
||||
return MixU64((seed_a * 3) + seed_b);
|
||||
}
|
||||
|
||||
#if IsLanguageC
|
||||
#define Fnv64Basis 0xCBF29CE484222325
|
||||
|
||||
// FNV-1a parameters for different hash sizes:
|
||||
// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters
|
||||
Inline u64 HashFnv64(u64 seed, String str)
|
||||
{
|
||||
u64 hash = seed;
|
||||
for (u64 i = 0; i < str.len; ++i)
|
||||
{
|
||||
hash ^= (u8)str.text[i];
|
||||
hash *= 0x100000001B3;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookdecl Core api
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@ void BootstrapCmdline(void)
|
||||
{
|
||||
CommandlineArg arg = tmp_args[i];
|
||||
CommandlineArgNode *n = PushStruct(perm, CommandlineArgNode);
|
||||
u64 hash = HashFnv64(Fnv64Basis, arg.name);
|
||||
u64 hash = HashString(arg.name);
|
||||
u64 bin_idx = hash % countof(Base.cmdline.arg_bins);
|
||||
n->arg = arg;
|
||||
n->hash = hash;
|
||||
@ -85,7 +85,7 @@ String StringFromCommandlineIdx(i32 idx)
|
||||
CommandlineArg CommandlineArgFromName(String name)
|
||||
{
|
||||
CommandlineArg result = Zi;
|
||||
u64 hash = HashFnv64(Fnv64Basis, name);
|
||||
u64 hash = HashString(name);
|
||||
for (CommandlineArgNode *n = Base.cmdline.arg_bins[hash % countof(Base.cmdline.arg_bins)]; n; n = n->next)
|
||||
{
|
||||
if (n->hash == hash && MatchString(n->arg.name, name))
|
||||
|
||||
@ -19,6 +19,7 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings)
|
||||
u64 num_entries = BB_ReadUBits(&br, 64);
|
||||
for (u64 i = 0; i < num_entries; ++i)
|
||||
{
|
||||
u64 store_hash = BB_ReadUBits(&br, 64);
|
||||
u64 name_start = BB_ReadUBits(&br, 64);
|
||||
u64 name_len = BB_ReadUBits(&br, 64);
|
||||
u64 data_start = BB_ReadUBits(&br, 64);
|
||||
@ -27,7 +28,7 @@ void BootstrapResources(u64 archive_strings_count, String *archive_strings)
|
||||
ResourceEntry *entry = PushStruct(perm, ResourceEntry);
|
||||
entry->name = STRING(name_len, archive.text + name_start);
|
||||
entry->data = STRING(data_len, archive.text + data_start);
|
||||
entry->hash = HashFnv64(Fnv64Basis, entry->name);
|
||||
entry->hash = HashStringEx(store_hash, entry->name);
|
||||
|
||||
ResourceEntryBin *bin = &Base.resource.bins[entry->hash % countof(Base.resource.bins)];
|
||||
SllQueuePushN(bin->first, bin->last, entry, next_in_bin);
|
||||
@ -50,7 +51,7 @@ b32 IsResourceNil(ResourceKey resource)
|
||||
ResourceKey ResourceKeyFromStore(ResourceStore *store, String name)
|
||||
{
|
||||
ResourceKey result = Zi;
|
||||
result.v = HashFnv64(store->v, name);
|
||||
result.v = HashStringEx(store->v, name);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -502,14 +502,21 @@ String PathFromString(Arena *arena, String str, u8 path_delimiter)
|
||||
|
||||
u64 HashStringEx(u64 seed, String str)
|
||||
{
|
||||
u64 result = HashFnv64(seed, str);
|
||||
// FNV-1a parameters for different hash sizes:
|
||||
// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters
|
||||
u64 result = seed + 0xCBF29CE484222325;
|
||||
for (u64 i = 0; i < str.len; ++i)
|
||||
{
|
||||
result ^= (u8)str.text[i];
|
||||
result *= 0x100000001B3;
|
||||
}
|
||||
result = MixU64(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
u64 HashString(String str)
|
||||
{
|
||||
return HashStringEx(Fnv64Basis, str);
|
||||
return HashStringEx(0, str);
|
||||
}
|
||||
|
||||
u64 HashF_(String fmt, ...)
|
||||
|
||||
@ -112,7 +112,7 @@ i64 TimeNs(void)
|
||||
|
||||
void TrueRand(String buffer)
|
||||
{
|
||||
BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, (u8 *)buffer.text, buffer.len, 0);
|
||||
BCryptGenRandom(BCRYPT_RNG_ALG_HANDLE, buffer.text, buffer.len, 0);
|
||||
}
|
||||
|
||||
CpuTopologyInfo GetCpuTopologyInfo(void)
|
||||
|
||||
@ -111,6 +111,7 @@ EmbedObj Embed(String store_name, String dir_path)
|
||||
EmbedObj result = Zi;
|
||||
|
||||
// Generate resource archive contents
|
||||
u64 store_hash = HashString(store_name);
|
||||
String arc_contents = Zi;
|
||||
{
|
||||
StringList files = Zi;
|
||||
@ -136,7 +137,6 @@ EmbedObj Embed(String store_name, String dir_path)
|
||||
entry_name.len -= dir_path.len + 1;
|
||||
entry_name.text += dir_path.len + 1;
|
||||
}
|
||||
entry_name = StringF(perm, "%F/%F", FmtString(store_name), FmtString(entry_name));
|
||||
for (u64 i = 0; i < entry_name.len; ++i)
|
||||
{
|
||||
if (entry_name.text[i] == '\\')
|
||||
@ -165,6 +165,7 @@ EmbedObj Embed(String store_name, String dir_path)
|
||||
|
||||
// Reserve entries space
|
||||
u64 entry_size = 0
|
||||
+ 8 // Store hash
|
||||
+ 8 // Name start
|
||||
+ 8 // Name end
|
||||
+ 8 // Data start
|
||||
@ -196,6 +197,7 @@ EmbedObj Embed(String store_name, String dir_path)
|
||||
u64 data_len = BB_GetNumBytesWritten(&bw) - data_start;
|
||||
|
||||
// Write entry
|
||||
BB_WriteUBits(&entries_bw, store_hash, 64);
|
||||
BB_WriteUBits(&entries_bw, name_start, 64);
|
||||
BB_WriteUBits(&entries_bw, name_len, 64);
|
||||
BB_WriteUBits(&entries_bw, data_start, 64);
|
||||
@ -457,6 +459,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
String shader_store_name = Lit("ShadersStore");
|
||||
String c_out_file = F_GetFull(perm, StringF(perm, "%F_gen.c", FmtString(cmdline.leaf_layer_name)));
|
||||
String gpu_out_file = F_GetFull(perm, StringF(perm, "%F_gen.g", FmtString(cmdline.leaf_layer_name)));
|
||||
u64 shader_store_hash = HashString(shader_store_name);
|
||||
|
||||
if (lane->idx == 0 && GetBuildStatus() == 0)
|
||||
{
|
||||
@ -505,8 +508,8 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
String full = F_GetFullCrossPlatform(perm, StringF(perm, "%F/%F", FmtString(token_parent_dir), FmtString(arg_dir)));
|
||||
if (F_IsDir(full))
|
||||
{
|
||||
u64 hash = HashFnv64(Fnv64Basis, StringF(perm, "%F/", FmtString(store_name)));
|
||||
String line = StringF(perm, "ResourceStore %F = { 0x%F };", FmtString(store_name), FmtHex(hash));
|
||||
u64 store_hash = HashString(store_name);
|
||||
String line = StringF(perm, "ResourceStore %F = { 0x%F };", FmtString(store_name), FmtHex(store_hash));
|
||||
PushStringToList(perm, &c_store_lines, line);
|
||||
}
|
||||
else
|
||||
@ -531,8 +534,8 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
: kind == M_EntryKind_ComputeShader ? Lit("ComputeShader")
|
||||
: Lit("");
|
||||
String shader_name = arg0_tok->s;
|
||||
u64 hash = HashFnv64(Fnv64Basis, StringF(perm, "%F/%F", FmtString(shader_store_name), FmtString(shader_name)));
|
||||
String line = StringF(perm, "%F %F = { 0x%F };", FmtString(shader_type), FmtString(shader_name), FmtHex(hash));
|
||||
u64 shader_resource_hash = HashStringEx(shader_store_hash, shader_name);
|
||||
String line = StringF(perm, "%F %F = { 0x%F };", FmtString(shader_type), FmtString(shader_name), FmtHex(shader_resource_hash));
|
||||
PushStringToList(perm, &c_shader_lines, line);
|
||||
}
|
||||
else
|
||||
|
||||
@ -97,7 +97,7 @@ M_TokenFileList M_TokensFromSrcDirs(Arena *arena, StringList src_dirs)
|
||||
if (StringEndsWith(file_name, Lit(".lay")))
|
||||
{
|
||||
String tmp_full = F_GetFull(scratch.arena, file_name);
|
||||
u64 hash = HashFnv64(Fnv64Basis, tmp_full);
|
||||
u64 hash = HashString(tmp_full);
|
||||
if (DictValueFromHash(dedup_dict, hash) == 0)
|
||||
{
|
||||
SetDictValue(scratch.arena, dedup_dict, hash, 1);
|
||||
@ -255,7 +255,7 @@ M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList lexed)
|
||||
for (u64 i = 0; i < countof(M_entry_kind_rules); ++i)
|
||||
{
|
||||
char *rule_cstr = M_entry_kind_rules[i];
|
||||
u64 rule_hash = HashFnv64(Fnv64Basis, StringFromCstrNoLimit(rule_cstr));
|
||||
u64 rule_hash = HashString(StringFromCstrNoLimit(rule_cstr));
|
||||
SetDictValue(scratch.arena, rules_dict, rule_hash, i + 1);
|
||||
}
|
||||
|
||||
@ -280,7 +280,7 @@ M_LayerList M_LayersFromTokenFiles(Arena *arena, M_TokenFileList lexed)
|
||||
{
|
||||
M_Entry *entry = M_PushEntry(arena, layer, M_EntryKind_Unknown, entry_token, args_count, arg_tokens);
|
||||
{
|
||||
u64 entry_hash = HashFnv64(Fnv64Basis, entry_token->s);
|
||||
u64 entry_hash = HashString(entry_token->s);
|
||||
u64 kind_plus_1 = DictValueFromHash(rules_dict, entry_hash);
|
||||
if (kind_plus_1 > 0)
|
||||
{
|
||||
@ -390,7 +390,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
|
||||
|
||||
String name = name_entry->arg_tokens[0]->s;
|
||||
|
||||
u64 name_hash = HashFnv64(Fnv64Basis, name);
|
||||
u64 name_hash = HashString(name);
|
||||
DictEntry *ptr_dict_entry = EnsureDictEntry(scratch.arena, layer_ptr_to_state, (u64)layer);
|
||||
DictEntry *name_dict_entry = EnsureDictEntry(scratch.arena, layer_name_to_state, name_hash);
|
||||
|
||||
@ -418,7 +418,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
|
||||
for (StringListNode *sln = starting_layer_names.first; sln; sln = sln->next)
|
||||
{
|
||||
String name = sln->s;
|
||||
u64 name_hash = HashFnv64(Fnv64Basis, name);
|
||||
u64 name_hash = HashString(name);
|
||||
IterState *state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, name_hash, (u64)&NilIterState);
|
||||
M_Layer *layer = state->layer;
|
||||
if (layer->valid)
|
||||
@ -497,7 +497,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
|
||||
if (should_include)
|
||||
{
|
||||
String downstream_layer_name = downstream_layer_token->s;
|
||||
u64 hash = HashFnv64(Fnv64Basis, downstream_layer_name);
|
||||
u64 hash = HashString(downstream_layer_name);
|
||||
IterState *downstream_layer_state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, hash, (u64)&NilIterState);
|
||||
M_Layer *downstream_layer = downstream_layer_state->layer;
|
||||
if (downstream_layer->valid)
|
||||
@ -538,7 +538,7 @@ M_Layer M_FlattenEntries(Arena *arena, M_LayerList unflattened, StringList start
|
||||
if (dep_token->valid)
|
||||
{
|
||||
String dep_name = dep_token->s;
|
||||
u64 hash = HashFnv64(Fnv64Basis, dep_name);
|
||||
u64 hash = HashString(dep_name);
|
||||
IterState *dep_layer_state = (IterState *)DictValueOrNilFromHash(layer_name_to_state, hash, (u64)&NilIterState);
|
||||
M_Layer *dep_layer = dep_layer_state->layer;
|
||||
if (dep_layer->valid)
|
||||
|
||||
@ -58,7 +58,7 @@ void N_ReleaseHost(N_Host *host)
|
||||
|
||||
u64 N_HashFromAddress(PLT_Address address)
|
||||
{
|
||||
return HashFnv64(Fnv64Basis, StringFromStruct(&address));
|
||||
return HashString(StringFromStruct(&address));
|
||||
}
|
||||
|
||||
N_Channel *N_ChannelFromAddress(N_Host *host, PLT_Address address)
|
||||
@ -227,9 +227,9 @@ void N_ReleaseChannel(N_Channel *channel)
|
||||
|
||||
u64 N_HashFromMsg(N_ChannelId channel_id, u64 msg_id)
|
||||
{
|
||||
u64 result = Fnv64Basis;
|
||||
result = HashFnv64(result, StringFromStruct(&channel_id));
|
||||
result = HashFnv64(result, StringFromStruct(&msg_id));
|
||||
u64 result = 0;
|
||||
result = HashStringEx(result, StringFromStruct(&channel_id));
|
||||
result = HashStringEx(result, StringFromStruct(&msg_id));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
418
src/pp/pp.c
418
src/pp/pp.c
@ -6,6 +6,10 @@ Readonly P_Ent P_NilEnt = {
|
||||
.look = { 0, -1 },
|
||||
};
|
||||
|
||||
Readonly P_Frame P_NilFrame = {
|
||||
0
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Bootstrap
|
||||
|
||||
@ -37,14 +41,19 @@ b32 P_IsEntNil(P_Ent *ent)
|
||||
return ent == 0 || ent == &P_NilEnt;
|
||||
}
|
||||
|
||||
b32 P_MatchKey(P_Key a, P_Key b)
|
||||
b32 P_IsFrameNil(P_Frame *frame)
|
||||
{
|
||||
return a.v == b.v;
|
||||
return frame == 0 || frame == &P_NilFrame;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Key helpers
|
||||
|
||||
b32 P_MatchKey(P_Key a, P_Key b)
|
||||
{
|
||||
return a.v == b.v;
|
||||
}
|
||||
|
||||
P_Key P_RandKey(void)
|
||||
{
|
||||
// TODO: Don't use true randomness for entity keys. It's overkill & non-deterministic.
|
||||
@ -73,91 +82,6 @@ String P_NameFromTileKind(P_TileKind kind)
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Delta helpers
|
||||
|
||||
void P_UpdateWorldFromDelta(Arena *arena, P_World *world, P_Delta *delta)
|
||||
{
|
||||
// FIXME: Bounds check tile deltas
|
||||
if (0)
|
||||
{
|
||||
}
|
||||
//- Reset
|
||||
if (delta->kind == P_DeltaKind_Reset)
|
||||
{
|
||||
// FIXME: Free list entities
|
||||
world->ents_count = 0;
|
||||
world->first_ent = 0;
|
||||
world->last_ent = 0;
|
||||
ZeroStructs(world->tiles, P_TilesCount);
|
||||
ZeroStructs(world->ent_bins, world->ent_bins_count);
|
||||
}
|
||||
//- Raw ent
|
||||
if (delta->kind == P_DeltaKind_RawEnt)
|
||||
{
|
||||
P_Key key = delta->ent.key;
|
||||
P_Ent *ent = P_EntFromKey(world, key);
|
||||
if (!ent->valid)
|
||||
{
|
||||
// FIXME: Use ent free list
|
||||
ent = PushStructNoZero(arena, P_Ent);
|
||||
*ent = P_NilEnt;
|
||||
ent->key = key;
|
||||
P_EntBin *bin = &world->ent_bins[ent->key.v % world->ent_bins_count];
|
||||
DllQueuePushNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin);
|
||||
DllQueuePush(world->first_ent, world->last_ent, ent);
|
||||
++world->ents_count;
|
||||
}
|
||||
P_Ent *old_next = ent->next;
|
||||
P_Ent *old_prev = ent->prev;
|
||||
P_Ent *old_next_in_bin = ent->next_in_bin;
|
||||
P_Ent *old_prev_in_bin = ent->prev_in_bin;
|
||||
{
|
||||
P_Ent *src = &delta->ent;
|
||||
*ent = *src;
|
||||
}
|
||||
ent->next = old_next;
|
||||
ent->prev = old_prev;
|
||||
ent->next_in_bin = old_next_in_bin;
|
||||
ent->prev_in_bin = old_prev_in_bin;
|
||||
ent->valid = 1;
|
||||
}
|
||||
//- Raw tiles
|
||||
else if (delta->kind == P_DeltaKind_RawTiles)
|
||||
{
|
||||
Rng2I32 range = delta->tile_range;
|
||||
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
|
||||
{
|
||||
i32 src_tile_y = tile_y - range.p0.y;
|
||||
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
|
||||
{
|
||||
i32 src_tile_x = tile_x - range.p0.x;
|
||||
Vec2 src_tile_pos = VEC2(src_tile_x, src_tile_y);
|
||||
i32 src_tile_idx = P_TileIdxFromTilePos(src_tile_pos);
|
||||
u8 src_tile = delta->raw_tiles[src_tile_idx];
|
||||
|
||||
Vec2 tile_pos = VEC2(tile_x, tile_y);
|
||||
i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
|
||||
world->tiles[tile_idx] = src_tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
//- Tile range
|
||||
else if (delta->kind == P_DeltaKind_Tile)
|
||||
{
|
||||
P_TileKind tile = delta->tile_kind;
|
||||
Rng2I32 range = delta->tile_range;
|
||||
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
|
||||
{
|
||||
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
|
||||
{
|
||||
Vec2 tile_pos = VEC2(tile_x, tile_y);
|
||||
i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
|
||||
world->tiles[tile_idx] = (u8)tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Shape helpers
|
||||
@ -1106,12 +1030,14 @@ Vec2 P_EdgePointFromShape(P_Shape shape, Vec2 dir)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Lookup helpers
|
||||
|
||||
P_Ent *P_EntFromKeyEx(P_World *world, P_Key key, i64 tick)
|
||||
P_Ent *P_EntFromKey(P_Frame *frame, P_Key key)
|
||||
{
|
||||
P_Ent *result = &P_NilEnt;
|
||||
if (!P_IsKeyNil(key) && world->ent_bins_count > 0)
|
||||
P_World *world = frame->world;
|
||||
if (!P_IsKeyNil(key) && frame->tick > 0 && frame->ents_count > 0 && frame->ent_bins_count > 0)
|
||||
{
|
||||
P_EntBin *bin = &world->ent_bins[key.v % world->ent_bins_count];
|
||||
i64 tick = frame->tick;
|
||||
P_EntBin *bin = &frame->ent_bins[key.v % frame->ent_bins_count];
|
||||
for (P_Ent *e = bin->first; e; e = e->next_in_bin)
|
||||
{
|
||||
if (e->key.v == key.v)
|
||||
@ -1124,20 +1050,15 @@ P_Ent *P_EntFromKeyEx(P_World *world, P_Key key, i64 tick)
|
||||
return result;
|
||||
}
|
||||
|
||||
P_Ent *P_EntFromKey(P_World *world, P_Key key)
|
||||
{
|
||||
return P_EntFromKeyEx(world, key, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Iteration helpers
|
||||
|
||||
P_Ent *P_FirstEnt(P_World *world)
|
||||
P_Ent *P_FirstEnt(P_Frame *frame)
|
||||
{
|
||||
P_Ent *result = &P_NilEnt;
|
||||
if (world->first_ent)
|
||||
if (frame->first_ent)
|
||||
{
|
||||
result = world->first_ent;
|
||||
result = frame->first_ent;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -1159,51 +1080,10 @@ P_Ent *P_PushTempEnt(Arena *arena, P_EntList *list)
|
||||
++list->count;
|
||||
P_Ent *ent = &n->ent;
|
||||
*ent = P_NilEnt;
|
||||
ent->valid = 1;
|
||||
ent->exists = 1;
|
||||
return ent;
|
||||
}
|
||||
|
||||
void P_SpawnEntsFromList(Arena *arena, P_World *world, P_EntList ents)
|
||||
{
|
||||
for (P_EntListNode *n = ents.first; n; n = n->next)
|
||||
{
|
||||
P_Ent *src = &n->ent;
|
||||
P_Key key = src->key;
|
||||
if (!P_IsKeyNil(src->key))
|
||||
{
|
||||
P_EntBin *bin = &world->ent_bins[key.v % world->ent_bins_count];
|
||||
P_Ent *dst = bin->first;
|
||||
for (; dst; dst = dst->next_in_bin)
|
||||
{
|
||||
if (P_MatchKey(dst->key, key))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!dst)
|
||||
{
|
||||
// FIXME: Use free list
|
||||
dst = PushStructNoZero(arena, P_Ent);
|
||||
DllQueuePush(world->first_ent, world->last_ent, dst);
|
||||
DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin);
|
||||
}
|
||||
P_Ent *old_next = dst->next;
|
||||
P_Ent *old_prev = dst->prev;
|
||||
P_Ent *old_next_in_bin = dst->next_in_bin;
|
||||
P_Ent *old_prev_in_bin = dst->prev_in_bin;
|
||||
{
|
||||
*dst = *src;
|
||||
}
|
||||
dst->next = old_next;
|
||||
dst->prev = old_prev;
|
||||
dst->next_in_bin = old_next_in_bin;
|
||||
dst->prev_in_bin = old_prev_in_bin;
|
||||
++world->ents_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Debug draw
|
||||
|
||||
@ -1267,3 +1147,263 @@ void P_DebugDrawShape(P_Shape shape, Vec4 srgb)
|
||||
P_tl.debug_draw_nodes_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ World
|
||||
|
||||
P_World *P_AcquireWorld(void)
|
||||
{
|
||||
P_World *world = 0;
|
||||
{
|
||||
Arena *arena = AcquireArena(Gibi(64));
|
||||
world = PushStruct(arena, P_World);
|
||||
world->arena = arena;
|
||||
}
|
||||
world->frames_arena = AcquireArena(Gibi(64));
|
||||
world->statics_arena = AcquireArena(Gibi(64));
|
||||
|
||||
world->first_frame = &P_NilFrame;
|
||||
world->last_frame = &P_NilFrame;
|
||||
world->frame_bins_count = Kibi(1);
|
||||
world->frame_bins = PushStructs(world->arena, P_FrameBin, world->frame_bins_count);
|
||||
|
||||
// TODO
|
||||
|
||||
world->tiles = PushStructs(world->arena, u8, P_TilesCount);
|
||||
|
||||
TrueRand(StringFromStruct(&world->seed));
|
||||
return world;
|
||||
}
|
||||
|
||||
void P_UpdateWorldFromSnapshots(P_World *world, P_SnapshotList snapshots)
|
||||
{
|
||||
b32 tiles_dirty = 0;
|
||||
for (P_SnapshotNode *n = snapshots.first; n; n = n->next)
|
||||
{
|
||||
P_Snapshot *snapshot = &n->snapshot;
|
||||
// FIXME: Process intermediate ticks
|
||||
if (snapshot->tick > world->last_frame->tick)
|
||||
{
|
||||
P_Frame *src_frame = P_FrameFromTick(world, snapshot->src_tick);
|
||||
P_Frame *frame = P_PushFrame(world, src_frame, snapshot->tick);
|
||||
world->seed = snapshot->world_seed;
|
||||
frame->time_ns = snapshot->time_ns;
|
||||
|
||||
if (frame->ents_count == 0)
|
||||
{
|
||||
for (P_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
|
||||
{
|
||||
P_Delta *delta = &dn->delta;
|
||||
// FIXME: Bounds check tile deltas
|
||||
if (0)
|
||||
{
|
||||
}
|
||||
//- Reset
|
||||
else if (delta->kind == P_DeltaKind_Reset)
|
||||
{
|
||||
// FIXME: Free list entities
|
||||
frame->ents_count = 0;
|
||||
frame->first_ent = 0;
|
||||
frame->last_ent = 0;
|
||||
ZeroStructs(world->tiles, P_TilesCount);
|
||||
ZeroStructs(frame->ent_bins, frame->ent_bins_count);
|
||||
tiles_dirty = 1;
|
||||
}
|
||||
//- Raw ent
|
||||
else if (delta->kind == P_DeltaKind_RawEnt)
|
||||
{
|
||||
P_Ent tmp_ent = delta->ent;
|
||||
P_EntListNode tmp_ent_node = Zi;
|
||||
tmp_ent_node.ent = tmp_ent;
|
||||
P_EntList ent_list = Zi;
|
||||
ent_list.first = &tmp_ent_node;
|
||||
ent_list.last = &tmp_ent_node;
|
||||
P_SpawnEntsFromList(frame, ent_list);
|
||||
}
|
||||
//- Raw tiles
|
||||
else if (delta->kind == P_DeltaKind_RawTiles)
|
||||
{
|
||||
Rng2I32 range = delta->tile_range;
|
||||
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
|
||||
{
|
||||
i32 src_tile_y = tile_y - range.p0.y;
|
||||
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
|
||||
{
|
||||
i32 src_tile_x = tile_x - range.p0.x;
|
||||
Vec2 src_tile_pos = VEC2(src_tile_x, src_tile_y);
|
||||
i32 src_tile_idx = P_TileIdxFromTilePos(src_tile_pos);
|
||||
u8 src_tile = delta->raw_tiles[src_tile_idx];
|
||||
|
||||
Vec2 tile_pos = VEC2(tile_x, tile_y);
|
||||
i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
|
||||
world->tiles[tile_idx] = src_tile;
|
||||
}
|
||||
}
|
||||
tiles_dirty = 1;
|
||||
}
|
||||
//- Tile range
|
||||
else if (delta->kind == P_DeltaKind_Tile)
|
||||
{
|
||||
P_TileKind tile = delta->tile_kind;
|
||||
Rng2I32 range = delta->tile_range;
|
||||
for (i32 tile_y = range.p0.y; tile_y < range.p1.y; ++tile_y)
|
||||
{
|
||||
for (i32 tile_x = range.p0.x; tile_x < range.p1.x; ++tile_x)
|
||||
{
|
||||
Vec2 tile_pos = VEC2(tile_x, tile_y);
|
||||
i32 tile_idx = P_TileIdxFromTilePos(tile_pos);
|
||||
world->tiles[tile_idx] = (u8)tile;
|
||||
}
|
||||
}
|
||||
tiles_dirty = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Real prune
|
||||
// for (P_Ent *ent = P_FirstEnt(frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
// {
|
||||
// ent->exists = 0;
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Rehash statics
|
||||
// if (tiles_dirty)
|
||||
// {
|
||||
// }
|
||||
}
|
||||
|
||||
void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents)
|
||||
{
|
||||
P_World *world = frame->world;
|
||||
for (P_EntListNode *n = ents.first; n; n = n->next)
|
||||
{
|
||||
P_Ent *src = &n->ent;
|
||||
P_Key key = src->key;
|
||||
if (!P_IsKeyNil(src->key))
|
||||
{
|
||||
P_EntBin *bin = &frame->ent_bins[key.v % frame->ent_bins_count];
|
||||
P_Ent *dst = bin->first;
|
||||
for (; dst; dst = dst->next_in_bin)
|
||||
{
|
||||
if (dst->key.v == key.v)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!dst)
|
||||
{
|
||||
// FIXME: Use free list
|
||||
dst = PushStructNoZero(world->arena, P_Ent);
|
||||
DllQueuePush(frame->first_ent, frame->last_ent, dst);
|
||||
DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin);
|
||||
}
|
||||
P_Ent *old_next = dst->next;
|
||||
P_Ent *old_prev = dst->prev;
|
||||
P_Ent *old_next_in_bin = dst->next_in_bin;
|
||||
P_Ent *old_prev_in_bin = dst->prev_in_bin;
|
||||
{
|
||||
*dst = *src;
|
||||
}
|
||||
dst->next = old_next;
|
||||
dst->prev = old_prev;
|
||||
dst->next_in_bin = old_next_in_bin;
|
||||
dst->prev_in_bin = old_prev_in_bin;
|
||||
++frame->ents_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
P_Frame *P_FrameFromTick(P_World *world, i64 tick)
|
||||
{
|
||||
P_Frame *result = &P_NilFrame;
|
||||
if (world->frame_bins_count > 0)
|
||||
{
|
||||
u64 hash = MixU64(tick);
|
||||
P_FrameBin *bin = &world->frame_bins[hash % world->frame_bins_count];
|
||||
for (P_Frame *frame = bin->first; frame; frame = frame->next_in_bin)
|
||||
{
|
||||
if (frame->tick == tick)
|
||||
{
|
||||
result = frame;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void P_ClearFrames(P_World *world, i64 tick_min, i64 tick_max)
|
||||
{
|
||||
// TODO: Fast path for when range encompasses all frames in the world
|
||||
// TODO: Don't need linear search
|
||||
P_Frame *frame = world->first_frame;
|
||||
while (!P_IsFrameNil(frame))
|
||||
{
|
||||
P_Frame *next_frame = frame->next;
|
||||
if (frame->tick >= tick_min && frame->tick <= tick_max)
|
||||
{
|
||||
// FIXME: Freelist ents
|
||||
|
||||
// FIXME: Freelist frame
|
||||
|
||||
u64 hash = MixU64(frame->tick);
|
||||
P_FrameBin *bin = &world->frame_bins[hash % world->frame_bins_count];
|
||||
DllQueueRemoveNPZ(&P_NilFrame, world->first_frame, world->last_frame, frame, next, prev);
|
||||
DllQueueRemoveNPZ(0, bin->first, bin->last, frame, next_in_bin, prev_in_bin);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
frame = next_frame;
|
||||
}
|
||||
}
|
||||
|
||||
P_Frame *P_PushFrame(P_World *world, P_Frame *src_frame, i64 tick)
|
||||
{
|
||||
Assert(!(src_frame->world == world && tick <= src_frame->tick)); // Can't read from tick that is being overwritten by new tick
|
||||
P_ClearFrames(world, tick, I64Max);
|
||||
|
||||
P_Frame *frame = PushStruct(world->frames_arena, P_Frame);
|
||||
{
|
||||
// FIXME: Pull from freelist
|
||||
|
||||
frame->world = world;
|
||||
frame->tick = tick;
|
||||
frame->time_ns = src_frame->time_ns;
|
||||
|
||||
frame->ent_bins_count = Kibi(16);
|
||||
frame->ent_bins = PushStructs(world->frames_arena, P_EntBin, frame->ent_bins_count);
|
||||
|
||||
u64 hash = MixU64(tick);
|
||||
P_FrameBin *bin = &world->frame_bins[hash % world->frame_bins_count];
|
||||
|
||||
DllQueuePushNPZ(&P_NilFrame, world->first_frame, world->last_frame, frame, next, prev);
|
||||
DllQueuePushNPZ(0, bin->first, bin->last, frame, next_in_bin, prev_in_bin);
|
||||
}
|
||||
|
||||
for (P_Ent *src = P_FirstEnt(src_frame); !P_IsEntNil(src); src = P_NextEnt(src))
|
||||
{
|
||||
// FIXME: Pull from freelist
|
||||
P_Ent *dst = PushStruct(world->frames_arena, P_Ent);
|
||||
*dst = *src;
|
||||
P_EntBin *bin = &frame->ent_bins[src->key.v % frame->ent_bins_count];
|
||||
DllQueuePush(frame->first_ent, frame->last_ent, dst);
|
||||
DllQueuePushNP(bin->first, bin->last, dst, next_in_bin, prev_in_bin);
|
||||
++frame->ents_count;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Step
|
||||
|
||||
P_Frame *P_StepWorld(P_World *world, P_Frame *prev_frame, P_CmdList cmds)
|
||||
{
|
||||
P_Frame *result = &P_NilFrame;
|
||||
return result;
|
||||
}
|
||||
|
||||
105
src/pp/pp.h
105
src/pp/pp.h
@ -52,7 +52,6 @@ Struct(P_Ent)
|
||||
//- Persistent data
|
||||
|
||||
P_Key key;
|
||||
b32 valid;
|
||||
|
||||
//////////////////////////////
|
||||
//- Build data
|
||||
@ -62,7 +61,7 @@ Struct(P_Ent)
|
||||
b32 is_player;
|
||||
f32 health;
|
||||
|
||||
Xform last_xf;
|
||||
Xform prev_xf;
|
||||
Xform xf;
|
||||
|
||||
Vec2 move;
|
||||
@ -112,9 +111,22 @@ Struct(P_EntBin)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ World types
|
||||
|
||||
Struct(P_World)
|
||||
Struct(P_Frame)
|
||||
{
|
||||
u64 seed;
|
||||
//////////////////////////////
|
||||
//- Internal world state
|
||||
|
||||
struct P_World *world;
|
||||
|
||||
P_Frame *next;
|
||||
P_Frame *prev;
|
||||
|
||||
P_Frame *next_in_bin;
|
||||
P_Frame *prev_in_bin;
|
||||
|
||||
//////////////////////////////
|
||||
//- Frame state
|
||||
|
||||
i64 tick;
|
||||
i64 time_ns;
|
||||
|
||||
@ -124,6 +136,28 @@ Struct(P_World)
|
||||
|
||||
i64 ent_bins_count;
|
||||
P_EntBin *ent_bins;
|
||||
};
|
||||
|
||||
Struct(P_FrameBin)
|
||||
{
|
||||
P_Frame *first;
|
||||
P_Frame *last;
|
||||
};
|
||||
|
||||
Struct(P_World)
|
||||
{
|
||||
Arena *arena;
|
||||
Arena *frames_arena;
|
||||
Arena *statics_arena;
|
||||
|
||||
u64 seed;
|
||||
// P_Ent *first_free_ent;
|
||||
|
||||
P_Frame *first_frame;
|
||||
P_Frame *last_frame;
|
||||
i64 frame_bins_count;
|
||||
P_FrameBin *frame_bins;
|
||||
// P_Frame *first_free_frame;
|
||||
|
||||
u8 *tiles;
|
||||
};
|
||||
@ -155,7 +189,9 @@ Struct(P_DeltaNode)
|
||||
|
||||
Struct(P_Snapshot)
|
||||
{
|
||||
u64 seed;
|
||||
u64 world_seed;
|
||||
// i64 src_world_tick;
|
||||
i64 src_tick;
|
||||
i64 tick;
|
||||
i64 time_ns;
|
||||
|
||||
@ -170,6 +206,13 @@ Struct(P_SnapshotNode)
|
||||
P_Snapshot snapshot;
|
||||
};
|
||||
|
||||
Struct(P_SnapshotList)
|
||||
{
|
||||
i64 count;
|
||||
P_SnapshotNode *first;
|
||||
P_SnapshotNode *last;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Collision types
|
||||
|
||||
@ -306,6 +349,7 @@ Enum(P_CmdKind)
|
||||
|
||||
Struct(P_Cmd)
|
||||
{
|
||||
i64 tick;
|
||||
P_CmdKind kind;
|
||||
|
||||
// Delta
|
||||
@ -325,20 +369,25 @@ Struct(P_CmdNode)
|
||||
P_Cmd cmd;
|
||||
};
|
||||
|
||||
Struct(P_CmdList)
|
||||
{
|
||||
i64 count;
|
||||
P_CmdNode *first;
|
||||
P_CmdNode *last;
|
||||
};
|
||||
|
||||
Struct(P_InputState)
|
||||
{
|
||||
Arena *arena;
|
||||
P_CmdNode *first_cmd_node;
|
||||
P_CmdNode *last_cmd_node;
|
||||
u64 cmds_count;
|
||||
|
||||
P_CmdList cmds;
|
||||
};
|
||||
|
||||
Struct(P_OutputState)
|
||||
{
|
||||
Arena *arena;
|
||||
P_SnapshotNode *first_snapshot_node;
|
||||
P_SnapshotNode *last_snapshot_node;
|
||||
u64 snapshots_count;
|
||||
|
||||
P_SnapshotList snapshots;
|
||||
|
||||
P_DebugDrawNode *first_debug_draw_node;
|
||||
P_DebugDrawNode *last_debug_draw_node;
|
||||
@ -363,6 +412,7 @@ Struct(P_Ctx)
|
||||
|
||||
Struct(P_ThreadLocalCtx)
|
||||
{
|
||||
// TODO: Move this to world frame
|
||||
Arena *debug_arena;
|
||||
b32 debug_draw_enabled;
|
||||
P_DebugDrawNode *first_debug_draw_node;
|
||||
@ -373,6 +423,9 @@ Struct(P_ThreadLocalCtx)
|
||||
extern P_Ctx P;
|
||||
extern ThreadLocal P_ThreadLocalCtx P_tl;
|
||||
|
||||
extern Readonly P_Ent P_NilEnt;
|
||||
extern Readonly P_Frame P_NilFrame;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Bootstrap
|
||||
|
||||
@ -383,11 +436,12 @@ void P_Bootstrap(void);
|
||||
|
||||
b32 P_IsKeyNil(P_Key key);
|
||||
b32 P_IsEntNil(P_Ent *ent);
|
||||
b32 P_MatchKey(P_Key a, P_Key b);
|
||||
b32 P_IsFrameNil(P_Frame *frame);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Key helpers
|
||||
|
||||
b32 P_MatchKey(P_Key a, P_Key b);
|
||||
P_Key P_RandKey(void);
|
||||
|
||||
#define P_FmtKey(key) FmtHandle((key).v)
|
||||
@ -397,11 +451,6 @@ P_Key P_RandKey(void);
|
||||
|
||||
String P_NameFromTileKind(P_TileKind kind);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Delta helpers
|
||||
|
||||
void P_UpdateWorldFromDelta(Arena *arena, P_World *world, P_Delta *delta);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Shape helpers
|
||||
|
||||
@ -431,20 +480,18 @@ Vec2 P_EdgePointFromShape(P_Shape shape, Vec2 dir);
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Lookup helpers
|
||||
|
||||
P_Ent *P_EntFromKeyEx(P_World *world, P_Key key, i64 tick);
|
||||
P_Ent *P_EntFromKey(P_World *world, P_Key key);
|
||||
P_Ent *P_EntFromKey(P_Frame *frame, P_Key key);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Iteration helpers
|
||||
|
||||
P_Ent *P_FirstEnt(P_World *world);
|
||||
P_Ent *P_FirstEnt(P_Frame *frame);
|
||||
P_Ent *P_NextEnt(P_Ent *e);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ List helpers
|
||||
|
||||
P_Ent *P_PushTempEnt(Arena *arena, P_EntList *list);
|
||||
void P_SpawnEntsFromList(Arena *arena, P_World *world, P_EntList ents);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Debug draw
|
||||
@ -453,3 +500,19 @@ void P_DebugDrawPoint(Vec2 p, Vec4 srgb);
|
||||
void P_DebugDrawLine(Vec2 p0, Vec2 p1, Vec4 srgb);
|
||||
void P_DebugDrawRect(Rng2 rect, Vec4 srgb);
|
||||
void P_DebugDrawShape(P_Shape shape, Vec4 srgb);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ World
|
||||
|
||||
P_World *P_AcquireWorld(void);
|
||||
void P_UpdateWorldFromSnapshots(P_World *world, P_SnapshotList snapshots);
|
||||
void P_SpawnEntsFromList(P_Frame *frame, P_EntList ents);
|
||||
|
||||
P_Frame *P_FrameFromTick(P_World *world, i64 tick);
|
||||
void P_ClearFrames(P_World *world, i64 tick_min, i64 tick_max);
|
||||
P_Frame *P_PushFrame(P_World *world, P_Frame *src_frame, i64 tick);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Step
|
||||
|
||||
P_Frame *P_StepWorld(P_World *world, P_Frame *prev_frame, P_CmdList cmds);
|
||||
|
||||
@ -24,13 +24,11 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
Arena *frame_arena = AcquireArena(Gibi(64));
|
||||
P_tl.debug_arena = AcquireArena(Gibi(64));
|
||||
|
||||
Arena *world_arena = AcquireArena(Gibi(64));
|
||||
P_World *world = 0;
|
||||
P_World *world = P_AcquireWorld();
|
||||
|
||||
// TODO: Real per-client deltas
|
||||
b32 has_sent_initial_tick = 0;
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//- Sim loop
|
||||
|
||||
@ -39,65 +37,69 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
shutdown = Atomic32Fetch(&S.shutdown);
|
||||
P_tl.debug_draw_enabled = TweakBool("Simulation debug draw", 1);
|
||||
|
||||
ResetArena(frame_arena);
|
||||
|
||||
//////////////////////////////
|
||||
//- Swap
|
||||
|
||||
{
|
||||
b32 swapin = IsSwappedIn();
|
||||
b32 swapout = shutdown && IsSwappingOut();
|
||||
// {
|
||||
// b32 swapin = IsSwappedIn();
|
||||
// b32 swapout = shutdown && IsSwappingOut();
|
||||
|
||||
//- Swap in
|
||||
if (!world)
|
||||
{
|
||||
String packed = Zi;
|
||||
if (swapin)
|
||||
{
|
||||
packed = SwappedStateFromName(frame_arena, Lit("pp_sim.swp"));
|
||||
}
|
||||
P_UnpackedWorld unpacked = P_UnpackWorld(frame_arena, packed);
|
||||
// //- Swap in
|
||||
// if (!world)
|
||||
// {
|
||||
// String packed = Zi;
|
||||
// if (swapin)
|
||||
// {
|
||||
// packed = SwappedStateFromName(frame_arena, Lit("pp_sim.swp"));
|
||||
// }
|
||||
// P_UnpackedWorld unpacked = P_UnpackWorld(frame_arena, packed);
|
||||
|
||||
ResetArena(world_arena);
|
||||
world = PushStruct(world_arena, P_World);
|
||||
world->seed = unpacked.seed;
|
||||
world->tick = unpacked.tick;
|
||||
world->time_ns = unpacked.time_ns;
|
||||
if (world->seed == 0)
|
||||
{
|
||||
TrueRand(StringFromStruct(&world->seed));
|
||||
}
|
||||
// ResetArena(world_arena);
|
||||
// world = PushStruct(world_arena, P_World);
|
||||
// world->seed = unpacked.seed;
|
||||
// world_frame->tick = unpacked.tick;
|
||||
// world_frame->time_ns = unpacked.time_ns;
|
||||
// if (world->seed == 0)
|
||||
// {
|
||||
// TrueRand(StringFromStruct(&world->seed));
|
||||
// }
|
||||
|
||||
world->ent_bins_count = Kibi(16);
|
||||
world->ent_bins = PushStructs(world_arena, P_EntBin, world->ent_bins_count);
|
||||
// world_frame->ent_bins_count = Kibi(16);
|
||||
// world_frame->ent_bins = PushStructs(world_arena, P_EntBin, world_frame->ent_bins_count);
|
||||
|
||||
// Copy tiles
|
||||
world->tiles = PushStructsNoZero(world_arena, u8, P_TilesCount);
|
||||
CopyStructs(world->tiles, unpacked.tiles, P_TilesCount);
|
||||
// // Copy tiles
|
||||
// world->tiles = PushStructsNoZero(world_arena, u8, P_TilesCount);
|
||||
// CopyStructs(world->tiles, unpacked.tiles, P_TilesCount);
|
||||
|
||||
// Copy ents
|
||||
P_SpawnEntsFromList(world_arena, world, unpacked.ents);
|
||||
}
|
||||
// // Copy ents
|
||||
// P_SpawnEntsFromList(world_arena, world, unpacked.ents);
|
||||
// }
|
||||
|
||||
//- Swap out
|
||||
if (swapout)
|
||||
{
|
||||
String packed = P_PackWorld(frame_arena, world);
|
||||
WriteSwappedState(Lit("pp_sim.swp"), packed);
|
||||
}
|
||||
}
|
||||
// //- Swap out
|
||||
// if (swapout)
|
||||
// {
|
||||
// String packed = P_PackWorld(frame_arena, world);
|
||||
// WriteSwappedState(Lit("pp_sim.swp"), packed);
|
||||
// }
|
||||
// }
|
||||
|
||||
//////////////////////////////
|
||||
//- Begin sim frame
|
||||
|
||||
P_Frame *prev_world_frame = world->last_frame;
|
||||
P_Frame *world_frame = P_PushFrame(world, prev_world_frame, prev_world_frame->tick + 1);
|
||||
|
||||
// FIXME: Copy frame
|
||||
|
||||
|
||||
i64 frame_begin_ns = TimeNs();
|
||||
i64 sim_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND;
|
||||
f64 sim_dt = SecondsFromNs(sim_dt_ns);
|
||||
world->tick += 1;
|
||||
|
||||
//////////////////////////////
|
||||
//- Pop sim commands
|
||||
//- Pop commands
|
||||
|
||||
P_InputState *input = 0;
|
||||
LockTicketMutex(&P.sim_input_back_tm);
|
||||
@ -114,9 +116,9 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Update double-buffered entity data
|
||||
|
||||
for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
{
|
||||
ent->last_xf = ent->xf;
|
||||
ent->prev_xf = ent->xf;
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
@ -125,7 +127,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
// FIXME: Only accept save command from local user
|
||||
|
||||
b32 should_save = 0;
|
||||
for (P_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
|
||||
for (P_CmdNode *cmd_node = input->cmds.first; cmd_node; cmd_node = cmd_node->next)
|
||||
{
|
||||
P_Cmd *cmd = &cmd_node->cmd;
|
||||
if (cmd->kind == P_CmdKind_Save)
|
||||
@ -145,9 +147,11 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
// FIXME: Only accept world deltas from users that can edit
|
||||
|
||||
// FIXME: Only apply relevant cmds based on tick
|
||||
|
||||
i64 applied_user_deltas_count = 0;
|
||||
P_Delta **applied_user_deltas = PushStructsNoZero(frame_arena, P_Delta *, input->cmds_count);
|
||||
for (P_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
|
||||
P_Delta **applied_user_deltas = PushStructsNoZero(frame_arena, P_Delta *, input->cmds.count);
|
||||
for (P_CmdNode *cmd_node = input->cmds.first; cmd_node; cmd_node = cmd_node->next)
|
||||
{
|
||||
P_Cmd *cmd = &cmd_node->cmd;
|
||||
if (cmd->kind == P_CmdKind_Delta)
|
||||
@ -176,7 +180,20 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
if (allow)
|
||||
{
|
||||
P_UpdateWorldFromDelta(world_arena, world, delta);
|
||||
P_DeltaNode tmp_delta_node = Zi;
|
||||
tmp_delta_node.delta = *delta;
|
||||
|
||||
P_SnapshotNode tmp_snapshot_node = Zi;
|
||||
tmp_snapshot_node.snapshot.deltas_count = 1;
|
||||
tmp_snapshot_node.snapshot.first_delta_node = &tmp_delta_node;
|
||||
tmp_snapshot_node.snapshot.last_delta_node = &tmp_delta_node;
|
||||
|
||||
P_SnapshotList tmp_snapshot_list = Zi;
|
||||
tmp_snapshot_list.count = 1;
|
||||
tmp_snapshot_list.first = &tmp_snapshot_node;
|
||||
tmp_snapshot_list.last = &tmp_snapshot_node;
|
||||
|
||||
P_UpdateWorldFromSnapshots(world, tmp_snapshot_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -184,18 +201,20 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Update ent controls
|
||||
|
||||
for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
// FIXME: Only apply relevant cmds based on tick
|
||||
|
||||
for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
{
|
||||
ent->fire_presses = 0;
|
||||
}
|
||||
|
||||
for (P_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
|
||||
for (P_CmdNode *cmd_node = input->cmds.first; cmd_node; cmd_node = cmd_node->next)
|
||||
{
|
||||
P_Cmd cmd = cmd_node->cmd;
|
||||
if (cmd.kind == P_CmdKind_Control)
|
||||
{
|
||||
P_Ent *target = P_EntFromKey(world, cmd.target);
|
||||
if (target->valid)
|
||||
P_Ent *target = P_EntFromKey(world_frame, cmd.target);
|
||||
if (!P_IsEntNil(target))
|
||||
{
|
||||
target->move = ClampVec2Len(cmd.move, 1);
|
||||
target->look = cmd.look;
|
||||
@ -212,7 +231,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
// //////////////////////////////
|
||||
// //- Push bullets
|
||||
|
||||
// for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
// for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
// {
|
||||
// if (ent->fire_held)
|
||||
// {
|
||||
@ -227,7 +246,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Integrate control forces
|
||||
|
||||
for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
{
|
||||
// Xform xf = ent->xf;
|
||||
// Xform desired_xf = xf;
|
||||
@ -300,10 +319,10 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
constraints = PushStructs(frame_arena, P_Constraint, max_constraints);
|
||||
}
|
||||
|
||||
for (P_Ent *ent0 = P_FirstEnt(world); ent0->valid; ent0 = P_NextEnt(ent0))
|
||||
for (P_Ent *ent0 = P_FirstEnt(world_frame); !P_IsEntNil(ent0); ent0 = P_NextEnt(ent0))
|
||||
{
|
||||
P_Shape shape0 = P_WorldShapeFromEnt(ent0);
|
||||
for (P_Ent *ent1 = P_FirstEnt(world); ent1->valid; ent1 = P_NextEnt(ent1))
|
||||
for (P_Ent *ent1 = P_FirstEnt(world_frame); !P_IsEntNil(ent1); ent1 = P_NextEnt(ent1))
|
||||
{
|
||||
if (ent1 > ent0)
|
||||
{
|
||||
@ -338,7 +357,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
if (constraint)
|
||||
{
|
||||
constraint->last_touched_tick = world->tick;
|
||||
constraint->last_touched_tick = world_frame->tick;
|
||||
constraint->normal = collision.collision_normal;
|
||||
// constraint->friction = SqrtF32(ent0->friction * ent1->friction);
|
||||
constraint->friction = 0;
|
||||
@ -416,13 +435,13 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
// // Debug draw
|
||||
// {
|
||||
// // P_Ent *ent0 = P_EntFromKey(world, constraint->ent0);
|
||||
// // P_Ent *ent1 = P_EntFromKey(world, constraint->ent1);
|
||||
// // P_Ent *ent0 = P_EntFromKey(world_frame, constraint->ent0);
|
||||
// // P_Ent *ent1 = P_EntFromKey(world_frame, constraint->ent1);
|
||||
// Vec2 normal = constraint->normal;
|
||||
// Vec2 center0 = Zi;
|
||||
// Vec2 center1 = Zi;
|
||||
// if (ent0->valid) center0 = P_WorldShapeFromEnt(ent0).center_of_mass;
|
||||
// if (ent1->valid) center1 = P_WorldShapeFromEnt(ent1).center_of_mass;
|
||||
// if (!P_IsEntNil(ent0)) center0 = P_WorldShapeFromEnt(ent0).center_of_mass;
|
||||
// if (!P_IsEntNil(ent1)) center1 = P_WorldShapeFromEnt(ent1).center_of_mass;
|
||||
// Vec2 p0 = AddVec2(center0, vcp0);
|
||||
// Vec2 p1 = AddVec2(center1, vcp1);
|
||||
// P_DebugDrawPoint(p0, Color_Cyan);
|
||||
@ -457,15 +476,15 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
// constraints = PushStructs(frame_arena, P_Constraint, max_constraints);
|
||||
// }
|
||||
|
||||
// for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
// for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
// {
|
||||
// if (ent->is_player)
|
||||
// {
|
||||
// Xform last_xf = ent->last_xf;
|
||||
// Xform prev_xf = ent->prev_xf;
|
||||
// Xform xf = ent->xf;
|
||||
|
||||
// P_Shape local_shape = P_LocalShapeFromEnt(ent);
|
||||
// P_Shape last_world_shape = P_MulXformShape(last_xf, local_shape);
|
||||
// P_Shape last_world_shape = P_MulXformShape(prev_xf, local_shape);
|
||||
// P_Shape shape0 = P_WorldShapeFromEnt(ent);
|
||||
|
||||
// // TODO: Real constraint data
|
||||
@ -514,7 +533,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
// }
|
||||
// if (constraint)
|
||||
// {
|
||||
// constraint->last_touched_tick = world->tick;
|
||||
// constraint->last_touched_tick = world_frame->tick;
|
||||
// constraint->normal = collision.collision_normal;
|
||||
|
||||
// // TODO: Real masses
|
||||
@ -589,13 +608,13 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
// // Debug draw
|
||||
// {
|
||||
// P_Ent *ent0 = P_EntFromKey(world, constraint->ent0);
|
||||
// P_Ent *ent1 = P_EntFromKey(world, constraint->ent1);
|
||||
// P_Ent *ent0 = P_EntFromKey(world_frame, constraint->ent0);
|
||||
// P_Ent *ent1 = P_EntFromKey(world_frame, constraint->ent1);
|
||||
// Vec2 normal = constraint->normal;
|
||||
// Vec2 center0 = Zi;
|
||||
// Vec2 center1 = Zi;
|
||||
// if (ent0->valid) center0 = P_WorldShapeFromEnt(ent0).center_of_mass;
|
||||
// if (ent1->valid) center1 = P_WorldShapeFromEnt(ent1).center_of_mass;
|
||||
// if (!P_IsEntNil(ent0)) center0 = P_WorldShapeFromEnt(ent0).center_of_mass;
|
||||
// if (!P_IsEntNil(ent1)) center1 = P_WorldShapeFromEnt(ent1).center_of_mass;
|
||||
// Vec2 p0 = AddVec2(center0, vcp0);
|
||||
// Vec2 p1 = AddVec2(center1, vcp1);
|
||||
// P_DebugDrawPoint(p0, Color_Cyan);
|
||||
@ -616,9 +635,11 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
P_Constraint *constraint = &constraints[constraint_idx];
|
||||
b32 prune = 1;
|
||||
if (constraint->last_touched_tick == world->tick)
|
||||
if (constraint->last_touched_tick == world_frame->tick)
|
||||
{
|
||||
if (P_EntFromKey(world, constraint->ent0)->valid || P_EntFromKey(world, constraint->ent1)->valid)
|
||||
P_Ent *ent0 = P_EntFromKey(world_frame, constraint->ent0);
|
||||
P_Ent *ent1 = P_EntFromKey(world_frame, constraint->ent1);
|
||||
if (!P_IsEntNil(ent0) && !P_IsEntNil(ent1))
|
||||
{
|
||||
prune = 0;
|
||||
}
|
||||
@ -691,8 +712,8 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
P_Constraint *constraint = &constraints[constraint_idx];
|
||||
|
||||
P_Ent *ent0 = P_EntFromKey(world, constraint->ent0);
|
||||
P_Ent *ent1 = P_EntFromKey(world, constraint->ent1);
|
||||
P_Ent *ent0 = P_EntFromKey(world_frame, constraint->ent0);
|
||||
P_Ent *ent1 = P_EntFromKey(world_frame, constraint->ent1);
|
||||
|
||||
Vec2 v0 = ent0->solved_v;
|
||||
Vec2 v1 = ent1->solved_v;
|
||||
@ -716,12 +737,12 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
w1 += WedgeVec2(vcp1, impulse) * constraint->inv_i1;
|
||||
}
|
||||
|
||||
if (ent0->valid)
|
||||
if (!P_IsEntNil(ent0))
|
||||
{
|
||||
ent0->solved_v = v0;
|
||||
ent0->solved_w = w0;
|
||||
}
|
||||
if (ent1->valid)
|
||||
if (!P_IsEntNil(ent1))
|
||||
{
|
||||
ent1->solved_v = v1;
|
||||
ent1->solved_w = w1;
|
||||
@ -735,8 +756,8 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
P_Constraint *constraint = &constraints[constraint_idx];
|
||||
|
||||
P_Ent *ent0 = P_EntFromKey(world, constraint->ent0);
|
||||
P_Ent *ent1 = P_EntFromKey(world, constraint->ent1);
|
||||
P_Ent *ent0 = P_EntFromKey(world_frame, constraint->ent0);
|
||||
P_Ent *ent1 = P_EntFromKey(world_frame, constraint->ent1);
|
||||
|
||||
f32 inv_m0 = constraint->inv_m0;
|
||||
f32 inv_m1 = constraint->inv_m1;
|
||||
@ -749,11 +770,11 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
Vec2 center0 = constraint->static_center0;
|
||||
Vec2 center1 = constraint->static_center1;
|
||||
if (ent0->valid)
|
||||
if (!P_IsEntNil(ent0))
|
||||
{
|
||||
center0 = P_WorldShapeFromEnt(ent0).center_of_mass;
|
||||
}
|
||||
if (ent1->valid)
|
||||
if (!P_IsEntNil(ent1))
|
||||
{
|
||||
center1 = P_WorldShapeFromEnt(ent1).center_of_mass;
|
||||
}
|
||||
@ -844,12 +865,12 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
w1 += WedgeVec2(vcp1, impulse) * inv_i1;
|
||||
}
|
||||
|
||||
if (ent0->valid)
|
||||
if (!P_IsEntNil(ent0))
|
||||
{
|
||||
ent0->solved_v = v0;
|
||||
ent0->solved_w = w0;
|
||||
}
|
||||
if (ent1->valid)
|
||||
if (!P_IsEntNil(ent1))
|
||||
{
|
||||
ent1->solved_v = v1;
|
||||
ent1->solved_w = w1;
|
||||
@ -859,7 +880,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Integrate velocities
|
||||
|
||||
for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
{
|
||||
Xform xf = ent->xf;
|
||||
xf.og = AddVec2(xf.og, MulVec2(ent->solved_v, solver_dt));
|
||||
@ -884,7 +905,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Move bullets
|
||||
|
||||
for (P_Ent *bullet = P_FirstEnt(world); bullet->valid; bullet = P_NextEnt(bullet))
|
||||
for (P_Ent *bullet = P_FirstEnt(world_frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet))
|
||||
{
|
||||
if (bullet->is_bullet)
|
||||
{
|
||||
@ -903,12 +924,12 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
{
|
||||
P_EntList bullets_to_spawn = Zi;
|
||||
for (P_Ent *firer = P_FirstEnt(world); firer->valid; firer = P_NextEnt(firer))
|
||||
for (P_Ent *firer = P_FirstEnt(world_frame); !P_IsEntNil(firer); firer = P_NextEnt(firer))
|
||||
{
|
||||
if (firer->fire_held)
|
||||
// if (firer->fire_presses)
|
||||
{
|
||||
// i64 fire_delta_ns = world->time_ns - firer->last_fire_ns;
|
||||
// i64 fire_delta_ns = world_frame->time_ns - firer->last_fire_ns;
|
||||
|
||||
// i64 single_bullet_delta_ns = NsFromSeconds(1) / firer->fire_rate;
|
||||
|
||||
@ -920,7 +941,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
f32 spread = Tau * 0.01;
|
||||
f32 tweak_speed = TweakFloat("Bullet speed", 100, 1, 100);
|
||||
|
||||
b32 can_fire = (firer->last_fire_ns + NsFromSeconds(1.0 / fire_rate)) <= world->time_ns;
|
||||
b32 can_fire = (firer->last_fire_ns + NsFromSeconds(1.0 / fire_rate)) <= world_frame->time_ns;
|
||||
if (can_fire)
|
||||
{
|
||||
i64 tick_bullets_count = bullets_per_fire;
|
||||
@ -955,11 +976,11 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
bullet->bullet_firer = firer->key;
|
||||
}
|
||||
}
|
||||
firer->last_fire_ns = world->time_ns;
|
||||
firer->last_fire_ns = world_frame->time_ns;
|
||||
}
|
||||
}
|
||||
}
|
||||
P_SpawnEntsFromList(world_arena, world, bullets_to_spawn);
|
||||
P_SpawnEntsFromList(world_frame, bullets_to_spawn);
|
||||
}
|
||||
|
||||
|
||||
@ -970,7 +991,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
// TODO: Separate 'hits' from bullets, so that bullets can have multiple hits
|
||||
|
||||
for (P_Ent *bullet = P_FirstEnt(world); bullet->valid; bullet = P_NextEnt(bullet))
|
||||
for (P_Ent *bullet = P_FirstEnt(world_frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet))
|
||||
{
|
||||
if (bullet->is_bullet)
|
||||
{
|
||||
@ -984,7 +1005,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
P_RaycastResult victim_raycast = Zi;
|
||||
{
|
||||
f32 closest_len_sq = Inf;
|
||||
for (P_Ent *victim = P_FirstEnt(world); victim->valid; victim = P_NextEnt(victim))
|
||||
for (P_Ent *victim = P_FirstEnt(world_frame); !P_IsEntNil(victim); victim = P_NextEnt(victim))
|
||||
{
|
||||
if (victim->is_player && !P_MatchKey(victim->key, bullet->bullet_firer))
|
||||
{
|
||||
@ -1013,7 +1034,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
}
|
||||
|
||||
if (closest_victim->valid)
|
||||
if (!P_IsEntNil(closest_victim))
|
||||
{
|
||||
bullet->has_hit = 1;
|
||||
bullet->hit_entry = victim_raycast.p;
|
||||
@ -1064,12 +1085,12 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
// P_Bullet *bullet = &bullets[bullet_idx];
|
||||
|
||||
// // Raycast
|
||||
// for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
// for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
// {
|
||||
// Xform xf = ent->xf;
|
||||
// P_Shape world_shape = P_MulXformShape(xf, ent->local_shape);
|
||||
|
||||
// if (ent == P_FirstEnt(world))
|
||||
// if (ent == P_FirstEnt(world_frame))
|
||||
// {
|
||||
// bullet->start = AddVec2(world_shape.centroid, Vec2WithLen(ent->look, world_shape.radius));
|
||||
// bullet->dir = NormVec2(ent->look);
|
||||
@ -1123,12 +1144,12 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
// // P_Bullet *bullet = &bullets[bullet_idx];
|
||||
|
||||
// // // Raycast
|
||||
// // for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
// // for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
// // {
|
||||
// // Xform xf = ent->xf;
|
||||
// // P_Shape world_shape = P_MulXformShape(xf, ent->local_shape);
|
||||
|
||||
// // if (ent == P_FirstEnt(world))
|
||||
// // if (ent == P_FirstEnt(world_frame))
|
||||
// // {
|
||||
// // bullet->start = AddVec2(world_shape.centroid, Vec2WithLen(ent->look, world_shape.radius));
|
||||
// // bullet->dir = NormVec2(ent->look);
|
||||
@ -1164,7 +1185,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
if (P_tl.debug_draw_enabled)
|
||||
{
|
||||
for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
{
|
||||
P_Shape world_shape = P_WorldShapeFromEnt(ent);
|
||||
|
||||
@ -1209,12 +1230,12 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
P_OutputState *output = &P.sim_output_states[P.sim_output_back_idx];
|
||||
P_SnapshotNode *snapshot_node = PushStruct(output->arena, P_SnapshotNode);
|
||||
P_Snapshot *snapshot = &snapshot_node->snapshot;
|
||||
SllQueuePush(output->first_snapshot_node, output->last_snapshot_node, snapshot_node);
|
||||
++output->snapshots_count;
|
||||
SllQueuePush(output->snapshots.first, output->snapshots.last, snapshot_node);
|
||||
++output->snapshots.count;
|
||||
|
||||
snapshot->seed = world->seed;
|
||||
snapshot->tick = world->tick;
|
||||
snapshot->time_ns = world->time_ns;
|
||||
snapshot->world_seed = world->seed;
|
||||
snapshot->tick = world_frame->tick;
|
||||
snapshot->time_ns = world_frame->time_ns;
|
||||
|
||||
// Forward user edit deltas
|
||||
for (i64 applied_user_delta_idx = 0; applied_user_delta_idx < applied_user_deltas_count; ++applied_user_delta_idx)
|
||||
@ -1248,7 +1269,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
|
||||
// Push raw entity deltas
|
||||
for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
{
|
||||
P_Delta *delta = 0;
|
||||
{
|
||||
@ -1287,8 +1308,8 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
{
|
||||
i64 ents_to_prune_count = 0;
|
||||
P_Ent **ents_to_prune = PushStructsNoZero(frame_arena, P_Ent *, world->ents_count);
|
||||
for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
P_Ent **ents_to_prune = PushStructsNoZero(frame_arena, P_Ent *, world_frame->ents_count);
|
||||
for (P_Ent *ent = P_FirstEnt(world_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
{
|
||||
if (ent->exists <= 0)
|
||||
{
|
||||
@ -1302,10 +1323,10 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
// FIXME: Add to freelist
|
||||
// FIXME: Ensure sure prunes are received by user
|
||||
P_Ent *ent = ents_to_prune[prune_idx];
|
||||
P_EntBin *bin = &world->ent_bins[ent->key.v % world->ent_bins_count];
|
||||
P_EntBin *bin = &world_frame->ent_bins[ent->key.v % world_frame->ent_bins_count];
|
||||
DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin);
|
||||
DllQueueRemove(world->first_ent, world->last_ent, ent);
|
||||
world->ents_count -= 1;
|
||||
DllQueueRemove(world_frame->first_ent, world_frame->last_ent, ent);
|
||||
world_frame->ents_count -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1321,7 +1342,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
|
||||
i64 frame_end_ns = TimeNs();
|
||||
world->time_ns += sim_dt_ns;
|
||||
world_frame->time_ns += sim_dt_ns;
|
||||
|
||||
//////////////////////////////
|
||||
//- Sleep
|
||||
|
||||
@ -6,19 +6,20 @@ 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, "tick: %F\n", FmtSint(src_world->tick)).len;
|
||||
result.len += StringF(arena, "time: %F\n", FmtSint(src_world->time_ns)).len;
|
||||
result.len += StringF(arena, "tick: %F\n", FmtSint(src_frame->tick)).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_world); ent->valid; ent = P_NextEnt(ent))
|
||||
for (P_Ent *ent = P_FirstEnt(src_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
{
|
||||
// TODO: Pack bullets
|
||||
if (!ent->is_bullet)
|
||||
|
||||
@ -43,11 +43,12 @@ V_Cmd *V_PushVisCmd(String name)
|
||||
|
||||
P_Cmd *V_PushSimCmd(P_CmdKind kind)
|
||||
{
|
||||
V_Frame *frame = V_CurrentFrame();
|
||||
P_CmdNode *n = PushStruct(frame->arena, P_CmdNode);
|
||||
// FIXME: Free list
|
||||
Arena *perm = PermArena();
|
||||
P_CmdNode *n = PushStruct(perm, P_CmdNode);
|
||||
n->cmd.kind = kind;
|
||||
SllQueuePush(frame->first_sim_cmd_node, frame->last_sim_cmd_node, n);
|
||||
++frame->sim_cmds_count;
|
||||
SllQueuePush(V.sim_cmds.first, V.sim_cmds.last, n);
|
||||
++V.sim_cmds.count;
|
||||
return &n->cmd;
|
||||
}
|
||||
|
||||
@ -340,11 +341,9 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
P_DebugDrawNode *first_sim_debug_draw_node = 0;
|
||||
P_DebugDrawNode *last_sim_debug_draw_node = 0;
|
||||
|
||||
Arena *world_arena = AcquireArena(Gibi(64));
|
||||
P_World *world = PushStruct(world_arena, P_World);
|
||||
world->ent_bins_count = Kibi(16);
|
||||
world->ent_bins = PushStructs(world_arena, P_EntBin, world->ent_bins_count);
|
||||
world->tiles = PushStructs(world_arena, u8, P_TilesCount);
|
||||
P_World *sim_world = P_AcquireWorld();
|
||||
P_World *predict_world = P_AcquireWorld();
|
||||
P_World *blend_world = P_AcquireWorld();
|
||||
|
||||
Vec2I32 tiles_dims = VEC2I32(P_TilesPitch, P_TilesPitch);
|
||||
Vec2I32 cells_dims = VEC2I32(V_CellsPerMeter * P_WorldPitch, V_CellsPerMeter * P_WorldPitch);
|
||||
@ -471,7 +470,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
else
|
||||
{
|
||||
u64 hotkey_hash = HashFnv64(Fnv64Basis, StringFromStruct(&hotkey));
|
||||
u64 hotkey_hash = HashString(StringFromStruct(&hotkey));
|
||||
V_ShortcutBin *bin = &shortcut_bins[hotkey_hash % shortcut_bins_count];
|
||||
V_Shortcut *shortcut = PushStruct(perm, V_Shortcut);
|
||||
shortcut->hotkey_hash = hotkey_hash;
|
||||
@ -632,54 +631,77 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
frame->ui_dims.y = MaxF32(frame->ui_dims.y, 64);
|
||||
frame->draw_dims = frame->ui_dims;
|
||||
|
||||
//////////////////////////////
|
||||
//- Pop sim output
|
||||
// //////////////////////////////
|
||||
// //- Pop sim output
|
||||
|
||||
// P_OutputState *sim_output = 0;
|
||||
// LockTicketMutex(&P.sim_output_back_tm);
|
||||
// {
|
||||
// sim_output = &P.sim_output_states[P.sim_output_back_idx];
|
||||
// ++P.sim_output_back_idx;
|
||||
// if (P.sim_output_back_idx >= countof(P.sim_output_states))
|
||||
// {
|
||||
// P.sim_output_back_idx = 0;
|
||||
// }
|
||||
// }
|
||||
// UnlockTicketMutex(&P.sim_output_back_tm);
|
||||
|
||||
// //////////////////////////////
|
||||
// //- Apply sim snapshots
|
||||
|
||||
// // FIXME: Only apply latest snapshot
|
||||
|
||||
|
||||
|
||||
// // FIXME: Real ping
|
||||
// i64 ping_ns = NsFromSeconds(0.250);
|
||||
|
||||
// // TODO: Remove this (testing)
|
||||
|
||||
|
||||
|
||||
// // b32 received_unseen_tick = 0;
|
||||
// // b32 tiles_dirty = 0;
|
||||
// // b32 should_clear_particles = 0;
|
||||
// // for (P_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next)
|
||||
// // {
|
||||
// // P_Snapshot *snapshot = &n->snapshot;
|
||||
// // if (snapshot->tick > world->tick)
|
||||
// // {
|
||||
// // world->seed = snapshot->seed;
|
||||
// // world->tick = snapshot->tick;
|
||||
// // world->time_ns = snapshot->time_ns;
|
||||
// // for (P_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
|
||||
// // {
|
||||
// // P_Delta *delta = &dn->delta;
|
||||
// // if (delta->kind == P_DeltaKind_Reset)
|
||||
// // {
|
||||
// // tiles_dirty = 1;
|
||||
// // should_clear_particles = 1;
|
||||
// // }
|
||||
// // if (delta->kind == P_DeltaKind_RawTiles || delta->kind == P_DeltaKind_Tile)
|
||||
// // {
|
||||
// // tiles_dirty = 1;
|
||||
// // }
|
||||
// // P_UpdateWorldFromDelta(world, delta);
|
||||
// // }
|
||||
// // received_unseen_tick = 1;
|
||||
// // }
|
||||
// // }
|
||||
|
||||
|
||||
// {
|
||||
// P_SnapshotList sim_snapshots = sim_output->snapshots;
|
||||
// P_UpdateWorldFromSnapshots(sim_world, sim_snapshots);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
P_OutputState *sim_output = 0;
|
||||
LockTicketMutex(&P.sim_output_back_tm);
|
||||
{
|
||||
sim_output = &P.sim_output_states[P.sim_output_back_idx];
|
||||
++P.sim_output_back_idx;
|
||||
if (P.sim_output_back_idx >= countof(P.sim_output_states))
|
||||
{
|
||||
P.sim_output_back_idx = 0;
|
||||
}
|
||||
}
|
||||
UnlockTicketMutex(&P.sim_output_back_tm);
|
||||
|
||||
//////////////////////////////
|
||||
//- Apply sim snapshots
|
||||
|
||||
// FIXME: Only apply latest snapshot
|
||||
|
||||
b32 received_unseen_tick = 0;
|
||||
b32 tiles_dirty = 0;
|
||||
b32 should_clear_particles = 0;
|
||||
for (P_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next)
|
||||
{
|
||||
P_Snapshot *snapshot = &n->snapshot;
|
||||
if (snapshot->tick > world->tick)
|
||||
{
|
||||
world->seed = snapshot->seed;
|
||||
world->tick = snapshot->tick;
|
||||
world->time_ns = snapshot->time_ns;
|
||||
for (P_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
|
||||
{
|
||||
P_Delta *delta = &dn->delta;
|
||||
if (delta->kind == P_DeltaKind_Reset)
|
||||
{
|
||||
tiles_dirty = 1;
|
||||
should_clear_particles = 1;
|
||||
}
|
||||
if (delta->kind == P_DeltaKind_RawTiles || delta->kind == P_DeltaKind_Tile)
|
||||
{
|
||||
tiles_dirty = 1;
|
||||
}
|
||||
P_UpdateWorldFromDelta(world_arena, world, delta);
|
||||
}
|
||||
received_unseen_tick = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// //////////////////////////////
|
||||
// //- Update tiles from sim
|
||||
@ -782,7 +804,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
hotkey.shift = frame->held_buttons[Button_Shift];
|
||||
hotkey.alt = frame->held_buttons[Button_Alt];
|
||||
{
|
||||
u64 hotkey_hash = HashFnv64(Fnv64Basis, StringFromStruct(&hotkey));
|
||||
u64 hotkey_hash = HashString(StringFromStruct(&hotkey));
|
||||
V_ShortcutBin *bin = &shortcut_bins[hotkey_hash % shortcut_bins_count];
|
||||
V_Shortcut *shortcut = bin->first;
|
||||
for (; shortcut; shortcut = shortcut->next_in_bin)
|
||||
@ -848,7 +870,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
Vec2 look_ratio = Zi;
|
||||
look_ratio.y = 0.25;
|
||||
look_ratio.x = look_ratio.y / (16.0 / 9.0);
|
||||
P_Ent *player = P_EntFromKey(world, V.player_key);
|
||||
P_Ent *player = P_EntFromKey(blend_world->last_frame, V.player_key);
|
||||
target_camera_pos = P_WorldShapeFromEnt(player).centroid;
|
||||
target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(player->look, look_ratio));
|
||||
target_camera_zoom = 1;
|
||||
@ -1001,12 +1023,12 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Query entities
|
||||
|
||||
P_Ent *player = P_EntFromKey(world, V.player_key);
|
||||
P_Ent *player = P_EntFromKey(blend_world->last_frame, V.player_key);
|
||||
P_Ent *hovered_ent = &P_NilEnt;
|
||||
{
|
||||
// TODO: Real world query
|
||||
P_Shape cursor_shape = P_ShapeFromDesc(.count = 1, .points = { frame->world_cursor });
|
||||
for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
for (P_Ent *ent = P_FirstEnt(blend_world->last_frame); !P_IsEntNil(ent); ent = P_NextEnt(ent))
|
||||
{
|
||||
P_Shape ent_shape = P_WorldShapeFromEnt(ent);
|
||||
b32 is_hovered = P_CollisionResultFromShapes(ent_shape, cursor_shape).collision_points_count > 0;
|
||||
@ -2212,8 +2234,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
|
||||
{
|
||||
UI_BuildLabelF("World seed: 0x%F", FmtHex(world->seed));
|
||||
UI_BuildLabelF("Entities count: %F", FmtSint(world->ents_count));
|
||||
UI_BuildLabelF("World seed: 0x%F", FmtHex(blend_world->seed));
|
||||
UI_BuildLabelF("Entities count: %F", FmtSint(blend_world->last_frame->ents_count));
|
||||
}
|
||||
UI_BuildSpacer(UI_PIX(padding, 1), Axis_Y);
|
||||
{
|
||||
@ -2535,7 +2557,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
case V_CmdKind_delete:
|
||||
{
|
||||
if (hovered_ent->valid)
|
||||
if (!P_IsEntNil(hovered_ent))
|
||||
{
|
||||
P_Cmd *cmd = V_PushSimCmd(P_CmdKind_Delta);
|
||||
cmd->delta.kind = P_DeltaKind_RawEnt;
|
||||
@ -2553,10 +2575,10 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
} break;
|
||||
|
||||
case V_CmdKind_clear_particles:
|
||||
{
|
||||
should_clear_particles = 1;
|
||||
} break;
|
||||
// case V_CmdKind_clear_particles:
|
||||
// {
|
||||
// should_clear_particles = 1;
|
||||
// } break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2605,23 +2627,189 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
cmd->fire_presses = frame->fire_presses;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//- Pop sim output
|
||||
|
||||
P_OutputState *sim_output = 0;
|
||||
LockTicketMutex(&P.sim_output_back_tm);
|
||||
{
|
||||
sim_output = &P.sim_output_states[P.sim_output_back_idx];
|
||||
++P.sim_output_back_idx;
|
||||
if (P.sim_output_back_idx >= countof(P.sim_output_states))
|
||||
{
|
||||
P.sim_output_back_idx = 0;
|
||||
}
|
||||
}
|
||||
UnlockTicketMutex(&P.sim_output_back_tm);
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//- Apply sim snapshots
|
||||
|
||||
// FIXME: Only apply latest snapshot
|
||||
|
||||
|
||||
|
||||
// FIXME: Real ping
|
||||
i64 ping_ns = NsFromSeconds(0.250);
|
||||
|
||||
// TODO: Remove this (testing)
|
||||
|
||||
|
||||
|
||||
// b32 received_unseen_tick = 0;
|
||||
// b32 tiles_dirty = 0;
|
||||
// b32 should_clear_particles = 0;
|
||||
// for (P_SnapshotNode *n = sim_output->first_snapshot_node; n; n = n->next)
|
||||
// {
|
||||
// P_Snapshot *snapshot = &n->snapshot;
|
||||
// if (snapshot->tick > world->tick)
|
||||
// {
|
||||
// world->seed = snapshot->seed;
|
||||
// world->tick = snapshot->tick;
|
||||
// world->time_ns = snapshot->time_ns;
|
||||
// for (P_DeltaNode *dn = snapshot->first_delta_node; dn; dn = dn->next)
|
||||
// {
|
||||
// P_Delta *delta = &dn->delta;
|
||||
// if (delta->kind == P_DeltaKind_Reset)
|
||||
// {
|
||||
// tiles_dirty = 1;
|
||||
// should_clear_particles = 1;
|
||||
// }
|
||||
// if (delta->kind == P_DeltaKind_RawTiles || delta->kind == P_DeltaKind_Tile)
|
||||
// {
|
||||
// tiles_dirty = 1;
|
||||
// }
|
||||
// P_UpdateWorldFromDelta(world, delta);
|
||||
// }
|
||||
// received_unseen_tick = 1;
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// Apply snapshots to sim world
|
||||
{
|
||||
P_SnapshotList sim_snapshots = sim_output->snapshots;
|
||||
P_UpdateWorldFromSnapshots(sim_world, sim_snapshots);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//- Submit sim commands
|
||||
|
||||
i64 predict_to = sim_world->last_frame->tick + 10;
|
||||
|
||||
LockTicketMutex(&P.sim_input_back_tm);
|
||||
{
|
||||
P_InputState *v2s = &P.sim_input_states[P.sim_input_back_idx];
|
||||
for (P_CmdNode *src = frame->first_sim_cmd_node; src; src = src->next)
|
||||
for (P_CmdNode *src = V.sim_cmds.first; src; src = src->next)
|
||||
{
|
||||
P_CmdNode *cmd_node = PushStruct(v2s->arena, P_CmdNode);
|
||||
cmd_node->cmd = src->cmd;
|
||||
SllQueuePush(v2s->first_cmd_node, v2s->last_cmd_node, cmd_node);
|
||||
++v2s->cmds_count;
|
||||
cmd_node->cmd.tick = predict_to;
|
||||
SllQueuePush(v2s->cmds.first, v2s->cmds.last, cmd_node);
|
||||
++v2s->cmds.count;
|
||||
}
|
||||
}
|
||||
UnlockTicketMutex(&P.sim_input_back_tm);
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//- Predict
|
||||
|
||||
|
||||
// TODO: Only predict when new sim snapshot is received
|
||||
|
||||
// Predict
|
||||
P_Frame *predict_frame = 0;
|
||||
{
|
||||
// i64 step_count = predict_to - sim_world->last_frame->tick;
|
||||
|
||||
// // TODO: Preserve constraints?
|
||||
|
||||
// P_ClearFrames(predict_world, I64Min, I64Max);
|
||||
// P_Frame *base_predict_frame = P_PushFrame(predict_world, sim_world->last_frame, sim_world->last_frame->tick);
|
||||
// P_Frame *prev_predict_frame = base_predict_frame;
|
||||
// for (i64 step_idx = 0; step_idx < step_count; ++step_idx)
|
||||
// {
|
||||
// // P_CmdList step_cmds = V_StepCmdsFromTick(prev_predict_frame->tick + 1);
|
||||
|
||||
// P_CmdList step_cmds = Zi;
|
||||
// for (P_CmdNode *src = V.sim_cmds.first; src; src = src->next)
|
||||
// {
|
||||
// P_CmdNode *n = PushStructNoZero(frame->arena, P_CmdNode);
|
||||
// *n = *src;
|
||||
// SllQueuePush(step_cmds.first, step_cmds.last, n);
|
||||
// ++step_cmds.count;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// P_Frame *stepped = P_StepWorld(predict_world, prev_predict_frame, step_cmds);
|
||||
// prev_predict_frame = stepped;
|
||||
// }
|
||||
|
||||
predict_frame = sim_world->last_frame;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//- Update blended world
|
||||
|
||||
|
||||
|
||||
// TODO: Remove this
|
||||
P_Frame *blend_frame = 0;
|
||||
{
|
||||
// P_ResetWorldFromFrame(blended_world, predict_world->last_frame);
|
||||
// P_Frame *blend_frame = blended_world->last_frame;
|
||||
blend_frame = predict_frame;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: Compare tile hashes
|
||||
b32 tiles_dirty = 0;
|
||||
b32 should_clear_particles = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// {
|
||||
// i64 delay_ns = NsFromSeconds(100);
|
||||
|
||||
// P_Frame *right_frame = &P_NilFrame;
|
||||
// P_Frame *left_frame = &P_NilFrame;
|
||||
|
||||
// for (P_Frame *tmp =
|
||||
|
||||
|
||||
|
||||
|
||||
// P_Frame *right_frame = predict_world->last_frame;
|
||||
// P_Frame *left_frame = predict_world->left_frame;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -2636,7 +2824,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
|
||||
|
||||
for (P_Ent *bullet = P_FirstEnt(world); bullet->valid; bullet = P_NextEnt(bullet))
|
||||
for (P_Ent *bullet = P_FirstEnt(blend_frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet))
|
||||
{
|
||||
if (bullet->is_bullet)
|
||||
{
|
||||
@ -2816,7 +3004,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
if (0)
|
||||
{
|
||||
for (P_Ent *bullet = P_FirstEnt(world); bullet->valid; bullet = P_NextEnt(bullet))
|
||||
for (P_Ent *bullet = P_FirstEnt(blend_frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet))
|
||||
{
|
||||
if (bullet->is_bullet && bullet->has_hit)
|
||||
{
|
||||
@ -2893,7 +3081,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
|
||||
// {
|
||||
// for (P_Ent *firer = P_FirstEnt(world); firer->valid; firer = P_NextEnt(firer))
|
||||
// for (P_Ent *firer = P_FirstEnt(blend_frame); firer->valid; firer = P_NextEnt(firer))
|
||||
// {
|
||||
// if (firer->fire_held)
|
||||
// {
|
||||
@ -2908,7 +3096,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
// P_RaycastResult victim_raycast = Zi;
|
||||
// {
|
||||
// f32 closest_len_sq = Inf;
|
||||
// for (P_Ent *victim = P_FirstEnt(world); victim->valid; victim = P_NextEnt(victim))
|
||||
// for (P_Ent *victim = P_FirstEnt(blend_frame); victim->valid; victim = P_NextEnt(victim))
|
||||
// {
|
||||
// if (victim != firer)
|
||||
// {
|
||||
@ -2979,7 +3167,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
|
||||
// // for (P_QueryResult query = P_FirstRaycast(wrold, ray_start, ray_dir); query.
|
||||
// // P_RaycastWorldResult hits = P_RaycastWorld(world, ray_start, ray_dir)
|
||||
// // P_RaycastWorldResult hits = P_RaycastWorld(blend_frame, ray_start, ray_dir)
|
||||
// // {
|
||||
// // }
|
||||
// }
|
||||
@ -3018,91 +3206,91 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Debug draw
|
||||
|
||||
{
|
||||
// Copy debug draw data from sim
|
||||
if (received_unseen_tick)
|
||||
{
|
||||
ResetArena(sim_debug_arena);
|
||||
first_sim_debug_draw_node = 0;
|
||||
last_sim_debug_draw_node = 0;
|
||||
{
|
||||
i64 dst_idx = 0;
|
||||
P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, sim_output->debug_draw_nodes_count);
|
||||
for (P_DebugDrawNode *src = sim_output->first_debug_draw_node; src; src = src->next)
|
||||
{
|
||||
P_DebugDrawNode *dst = &dst_nodes[dst_idx];
|
||||
*dst = *src;
|
||||
dst_idx += 1;
|
||||
SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
// {
|
||||
// // Copy debug draw data from sim
|
||||
// if (received_unseen_tick)
|
||||
// {
|
||||
// ResetArena(sim_debug_arena);
|
||||
// first_sim_debug_draw_node = 0;
|
||||
// last_sim_debug_draw_node = 0;
|
||||
// {
|
||||
// i64 dst_idx = 0;
|
||||
// P_DebugDrawNode *dst_nodes = PushStructsNoZero(sim_debug_arena, P_DebugDrawNode, sim_output->debug_draw_nodes_count);
|
||||
// for (P_DebugDrawNode *src = sim_output->first_debug_draw_node; src; src = src->next)
|
||||
// {
|
||||
// P_DebugDrawNode *dst = &dst_nodes[dst_idx];
|
||||
// *dst = *src;
|
||||
// dst_idx += 1;
|
||||
// SllQueuePush(first_sim_debug_draw_node, last_sim_debug_draw_node, dst);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// Merge vis debug draws with sim debug draws
|
||||
P_DebugDrawNode *first_debug_draw_node = first_sim_debug_draw_node;
|
||||
P_DebugDrawNode *last_debug_draw_node = last_sim_debug_draw_node;
|
||||
if (P_tl.first_debug_draw_node)
|
||||
{
|
||||
if (last_debug_draw_node)
|
||||
{
|
||||
last_debug_draw_node->next = P_tl.first_debug_draw_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_debug_draw_node = P_tl.first_debug_draw_node;
|
||||
}
|
||||
last_debug_draw_node = P_tl.last_debug_draw_node;
|
||||
}
|
||||
// // Merge vis debug draws with sim debug draws
|
||||
// P_DebugDrawNode *first_debug_draw_node = first_sim_debug_draw_node;
|
||||
// P_DebugDrawNode *last_debug_draw_node = last_sim_debug_draw_node;
|
||||
// if (P_tl.first_debug_draw_node)
|
||||
// {
|
||||
// if (last_debug_draw_node)
|
||||
// {
|
||||
// last_debug_draw_node->next = P_tl.first_debug_draw_node;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// first_debug_draw_node = P_tl.first_debug_draw_node;
|
||||
// }
|
||||
// last_debug_draw_node = P_tl.last_debug_draw_node;
|
||||
// }
|
||||
|
||||
// Push draws
|
||||
for (P_DebugDrawNode *n = first_debug_draw_node; n; n = n->next)
|
||||
{
|
||||
Vec4 color = Vec4FromU32(n->srgb32);
|
||||
i32 detail = 24;
|
||||
f32 radius = 5;
|
||||
switch(n->kind)
|
||||
{
|
||||
case P_DebugDrawKind_Point:
|
||||
{
|
||||
Vec2 ui_p = MulXformV2(frame->xf.world_to_ui, n->point.p);
|
||||
V_DrawPoint(ui_p, color);
|
||||
} break;
|
||||
// // Push draws
|
||||
// for (P_DebugDrawNode *n = first_debug_draw_node; n; n = n->next)
|
||||
// {
|
||||
// Vec4 color = Vec4FromU32(n->srgb32);
|
||||
// i32 detail = 24;
|
||||
// f32 radius = 5;
|
||||
// switch(n->kind)
|
||||
// {
|
||||
// case P_DebugDrawKind_Point:
|
||||
// {
|
||||
// Vec2 ui_p = MulXformV2(frame->xf.world_to_ui, n->point.p);
|
||||
// V_DrawPoint(ui_p, color);
|
||||
// } break;
|
||||
|
||||
case P_DebugDrawKind_Line:
|
||||
{
|
||||
Vec2 ui_p0 = MulXformV2(frame->xf.world_to_ui, n->line.p0);
|
||||
Vec2 ui_p1 = MulXformV2(frame->xf.world_to_ui, n->line.p1);
|
||||
V_DrawLine(ui_p0, ui_p1, color);
|
||||
} break;
|
||||
// case P_DebugDrawKind_Line:
|
||||
// {
|
||||
// Vec2 ui_p0 = MulXformV2(frame->xf.world_to_ui, n->line.p0);
|
||||
// Vec2 ui_p1 = MulXformV2(frame->xf.world_to_ui, n->line.p1);
|
||||
// V_DrawLine(ui_p0, ui_p1, color);
|
||||
// } break;
|
||||
|
||||
case P_DebugDrawKind_Rect:
|
||||
{
|
||||
Rng2 ui_rect = Zi;
|
||||
ui_rect.p0 = MulXformV2(frame->xf.world_to_ui, n->rect.p0);
|
||||
ui_rect.p1 = MulXformV2(frame->xf.world_to_ui, n->rect.p1);
|
||||
V_DrawRect(ui_rect, color, V_DrawFlag_Line);
|
||||
} break;
|
||||
// case P_DebugDrawKind_Rect:
|
||||
// {
|
||||
// Rng2 ui_rect = Zi;
|
||||
// ui_rect.p0 = MulXformV2(frame->xf.world_to_ui, n->rect.p0);
|
||||
// ui_rect.p1 = MulXformV2(frame->xf.world_to_ui, n->rect.p1);
|
||||
// V_DrawRect(ui_rect, color, V_DrawFlag_Line);
|
||||
// } break;
|
||||
|
||||
case P_DebugDrawKind_Shape:
|
||||
{
|
||||
P_Shape ui_shape = P_MulXformShape(frame->xf.world_to_ui, n->shape);
|
||||
V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
// case P_DebugDrawKind_Shape:
|
||||
// {
|
||||
// P_Shape ui_shape = P_MulXformShape(frame->xf.world_to_ui, n->shape);
|
||||
// V_DrawShape(ui_shape, color, detail, V_DrawFlag_Line);
|
||||
// } break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// Reset vis debug draws
|
||||
ResetArena(P_tl.debug_arena);
|
||||
P_tl.first_debug_draw_node = 0;
|
||||
P_tl.last_debug_draw_node = 0;
|
||||
P_tl.debug_draw_nodes_count = 0;
|
||||
}
|
||||
// // Reset vis debug draws
|
||||
// ResetArena(P_tl.debug_arena);
|
||||
// P_tl.first_debug_draw_node = 0;
|
||||
// P_tl.last_debug_draw_node = 0;
|
||||
// P_tl.debug_draw_nodes_count = 0;
|
||||
// }
|
||||
|
||||
|
||||
//////////////////////////////
|
||||
//- Draw entities
|
||||
|
||||
// for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
// for (P_Ent *ent = P_FirstEnt(blend_frame); ent->valid; ent = P_NextEnt(ent))
|
||||
// {
|
||||
// Xform ent_to_world_xf = ent->xf;
|
||||
// Xform ent_to_draw_xf = MulXform(frame->xf.world_to_draw, ent_to_world_xf);
|
||||
@ -3260,7 +3448,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
G_CopyCpuToTexture(
|
||||
frame->cl,
|
||||
gpu_tiles, VEC3I32(0, 0, 0),
|
||||
world->tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1),
|
||||
blend_world->tiles, VEC3I32(tiles_dims.x, tiles_dims.y, 1),
|
||||
RNG3I32(VEC3I32(0, 0, 0), VEC3I32(tiles_dims.x, tiles_dims.y, 1))
|
||||
);
|
||||
G_DumbMemoryLayoutSync(frame->cl, gpu_tiles, G_Layout_DirectQueue_ShaderRead);
|
||||
@ -3372,28 +3560,28 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Prune ents
|
||||
|
||||
{
|
||||
i64 ents_to_prune_count = 0;
|
||||
P_Ent **ents_to_prune = PushStructsNoZero(frame->arena, P_Ent *, world->ents_count);
|
||||
for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
{
|
||||
if (ent->exists <= 0)
|
||||
{
|
||||
ents_to_prune[ents_to_prune_count] = ent;
|
||||
ents_to_prune_count += 1;
|
||||
}
|
||||
}
|
||||
// {
|
||||
// i64 ents_to_prune_count = 0;
|
||||
// P_Ent **ents_to_prune = PushStructsNoZero(frame->arena, P_Ent *, world->ents_count);
|
||||
// for (P_Ent *ent = P_FirstEnt(world); ent->valid; ent = P_NextEnt(ent))
|
||||
// {
|
||||
// if (ent->exists <= 0)
|
||||
// {
|
||||
// ents_to_prune[ents_to_prune_count] = ent;
|
||||
// ents_to_prune_count += 1;
|
||||
// }
|
||||
// }
|
||||
|
||||
for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx)
|
||||
{
|
||||
// FIXME: Add to free list
|
||||
P_Ent *ent = ents_to_prune[prune_idx];
|
||||
P_EntBin *bin = &world->ent_bins[ent->key.v % world->ent_bins_count];
|
||||
DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin);
|
||||
DllQueueRemove(world->first_ent, world->last_ent, ent);
|
||||
world->ents_count -= 1;
|
||||
}
|
||||
}
|
||||
// for (i64 prune_idx = 0; prune_idx < ents_to_prune_count; ++prune_idx)
|
||||
// {
|
||||
// // FIXME: Add to free list
|
||||
// P_Ent *ent = ents_to_prune[prune_idx];
|
||||
// P_EntBin *bin = &world->ent_bins[ent->key.v % world->ent_bins_count];
|
||||
// DllQueueRemoveNP(bin->first, bin->last, ent, next_in_bin, prev_in_bin);
|
||||
// DllQueueRemove(world->first_ent, world->last_ent, ent);
|
||||
// world->ents_count -= 1;
|
||||
// }
|
||||
// }
|
||||
|
||||
//////////////////////////////
|
||||
//- End frame
|
||||
|
||||
@ -260,7 +260,7 @@ Struct(V_Frame)
|
||||
Rng2 draw_selection;
|
||||
Rng2 world_selection;
|
||||
|
||||
// Commands
|
||||
// Vis commands
|
||||
i64 cmds_count;
|
||||
V_CmdNode *first_cmd_node;
|
||||
V_CmdNode *last_cmd_node;
|
||||
@ -271,11 +271,6 @@ Struct(V_Frame)
|
||||
f32 fire_held;
|
||||
f32 fire_presses;
|
||||
|
||||
// Sim cmds
|
||||
u64 sim_cmds_count;
|
||||
P_CmdNode *first_sim_cmd_node;
|
||||
P_CmdNode *last_sim_cmd_node;
|
||||
|
||||
// Emitters
|
||||
i64 emitters_count;
|
||||
V_EmitterNode *first_emitter_node;
|
||||
@ -291,6 +286,9 @@ Struct(V_Ctx)
|
||||
V_Panel *root_panel;
|
||||
V_Window *dragging_window;
|
||||
|
||||
// Sim commands
|
||||
P_CmdList sim_cmds;
|
||||
|
||||
// Atomic monotonically increasing allocation counter sequence for GPU particle ring buffer
|
||||
u32 particle_seq;
|
||||
|
||||
|
||||
@ -94,7 +94,7 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
|
||||
archive.lookup = InitDict(arena, (u64)((f64)num_files * TAR_ArchiveLookupTableCapacityFactor));
|
||||
for (TAR_Entry *entry = archive.head; entry; entry = entry->next)
|
||||
{
|
||||
u64 hash = HashFnv64(Fnv64Basis, entry->file_name);
|
||||
u64 hash = HashString(entry->file_name);
|
||||
SetDictValue(arena, archive.lookup, hash, (u64)entry);
|
||||
}
|
||||
|
||||
@ -113,7 +113,7 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
|
||||
{
|
||||
if (parent_dir_name.text[parent_dir_name.len - 1] == '/')
|
||||
{
|
||||
u64 hash = HashFnv64(Fnv64Basis, parent_dir_name);
|
||||
u64 hash = HashString(parent_dir_name);
|
||||
parent_entry = (TAR_Entry *)DictValueFromHash(archive.lookup, hash);
|
||||
break;
|
||||
}
|
||||
@ -133,7 +133,7 @@ TAR_Archive TAR_ArchiveFromString(Arena *arena, String data, String prefix)
|
||||
Readonly Global TAR_Entry g_nil_tar_entry = ZI;
|
||||
TAR_Entry *TAR_EntryFromName(TAR_Archive *archive, String name)
|
||||
{
|
||||
u64 hash = HashFnv64(Fnv64Basis, name);
|
||||
u64 hash = HashString(name);
|
||||
TAR_Entry *lookup = (TAR_Entry *)DictValueFromHash(archive->lookup, hash);
|
||||
return lookup ? lookup : &g_nil_tar_entry;
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ UI_Key UI_KeyFromString(String str)
|
||||
{
|
||||
u64 top_tag = UI_Top(Tag);
|
||||
UI_Key key = Zi;
|
||||
key.v = HashFnv64(top_tag, str);
|
||||
key.v = HashStringEx(top_tag, str);
|
||||
return key;
|
||||
}
|
||||
|
||||
@ -340,7 +340,7 @@ void UI_PushDefaults(void)
|
||||
case UI_StyleKind_FontSize: { desc.style.FontSize = 16.0f; } break;
|
||||
case UI_StyleKind_Tint: { desc.style.Tint = Color_White; } break;
|
||||
case UI_StyleKind_TextColor: { desc.style.TextColor = Color_White; } break;
|
||||
case UI_StyleKind_Tag: { desc.style.Tag = HashFnv64(Fnv64Basis, Lit("root")); } break;
|
||||
case UI_StyleKind_Tag: { desc.style.Tag = HashString(Lit("root")); } break;
|
||||
case UI_StyleKind_DebugColor: { desc.style.DebugColor = Rgba(1, 0, 1, 0.5); } break;
|
||||
case UI_StyleKind_InvisibleDebugColor: { desc.style.InvisibleDebugColor = Rgba(0, 1, 1, 0.25); } break;
|
||||
case UI_StyleKind_BackgroundTextureSliceUv: { desc.style.BackgroundTextureSliceUv = RNG2(VEC2(0, 0), VEC2(1, 1)); } break;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user