publish sim state

This commit is contained in:
jacob 2025-11-12 15:00:05 -06:00
parent 13b942efb2
commit cd40046afc
10 changed files with 143 additions and 431 deletions

View File

@ -1,308 +0,0 @@
SharedAppState shared_app_state = ZI;
////////////////////////////////////////////////////////////
//~ Write directory
String InitializeAppWriteDirectory(Arena *arena, String write_dir)
{
TempArena scratch = BeginScratch(arena);
/* Create write path */
String base_write_dir = P_GetWritePath(scratch.arena);
String write_path_fmt = base_write_dir.len > 0 ? Lit("%F/%F/") : Lit("%F%F/");
String write_path = FormatString(
arena,
write_path_fmt,
FmtString(base_write_dir),
FmtString(write_dir)
);
/* Create write dir if not present */
if (!P_IsDir(write_path))
{
P_MkDir(write_path);
/* TODO: handle failure */
}
EndScratch(scratch);
return write_path;
}
String CatAppWritePath(Arena *arena, String filename)
{
SharedAppState *g = &shared_app_state;
return CatString(arena, g->write_path, filename);
}
////////////////////////////////////////////////////////////
//~ Default settings
P_WindowSettings GetDefaultAppWindowSettings(P_Window *window)
{
__prof;
Vec2I32 monitor_size = P_GetWindowMonitorSize(window);
i32 width = 1280;
i32 height = RoundF32ToI32(width / (f32)(DEFAULT_CAMERA_WIDTH / DEFAULT_CAMERA_HEIGHT));
i32 x = RoundF32ToI32(monitor_size.x / 2.f - width / 2);
i32 y = RoundF32ToI32(monitor_size.y / 2.f - height / 2);
return (P_WindowSettings)
{
.title = WINDOW_TITLE,
.floating_x = x,
.floating_y = y,
.floating_width = width,
.floating_height = height
};
}
////////////////////////////////////////////////////////////
//~ Args
/* TODO: Remove this and do real argument parsing */
AppArgList ParseAppArgs(Arena *arena, String args_str)
{
AppArgList result = ZI;
i64 mode = 0;
i64 i = 0;
i64 key_start = -1;
i64 key_end = -1;
i64 value_start = -1;
i64 value_end = -1;
while (i < (i64)args_str.len)
{
u8 c = args_str.text[i];
switch (mode)
{
default: break;
case 0:
{
if (c == '-')
{
mode = 1;
key_start = i + 1;
}
++i;
} break;
case 1:
{
if (c == '=')
{
key_end = i;
value_start = i + 1;
mode = 2;
}
++i;
} break;
case 2:
{
if (c == '-' || i == (i64)args_str.len - 1)
{
if (c == '-')
{
value_end = i;
}
else
{
value_end = i + 1;
}
if (key_start >= 0 && key_end > key_start && key_end <= (i64)args_str.len && value_start >= 0 && value_end > value_start && value_end <= (i64)args_str.len)
{
String key = PushString(arena, STRING(key_end - key_start, args_str.text + key_start));
String value = PushString(arena, STRING(value_end - value_start, args_str.text + value_start));
AppArg *arg = PushStruct(arena, AppArg);
arg->key = key;
arg->value = value;
if (result.last)
{
result.last->next = arg;
}
else
{
result.first = arg;
}
result.last = arg;
++result.count;
}
key_start = i + 1;
mode = 1;
}
++i;
} break;
}
}
return result;
}
////////////////////////////////////////////////////////////
//~ @hookdef Entry point
void Startup(void)
{
__prof;
TempArena scratch = BeginScratchNoConflict();
SharedAppState *g = &shared_app_state;
String args_str = Lit("");
AppArgList args = ParseAppArgs(scratch.arena, args_str);
String logfile_name = Lit("log.log");
String settings_file_name = Lit("settings.txt");
String connect_address = ZI;
for (AppArg *arg = args.first; arg; arg = arg->next)
{
String key = arg->key;
String value = arg->value;
if (MatchString(key, Lit("log")))
{
logfile_name = value;
}
else if (MatchString(key, Lit("settings")))
{
settings_file_name = value;
}
else if (MatchString(key, Lit("connect")))
{
connect_address = value;
}
}
LAX args;
LAX logfile_name;
LAX settings_file_name;
LAX connect_address;
LAX GetDefaultAppWindowSettings;
#if !RtcIsEnabled
/* Verify test modes aren't left on by accident in release mode */
StaticAssert(BITBUFF_DEBUG == 0);
StaticAssert(BITBUFF_TEST == 0);
#endif
#if BITBUFF_TEST
BB_Test();
#endif
g->arena = AcquireArena(Gibi(64));
g->write_path = InitializeAppWriteDirectory(g->arena, Lit(WRITE_DIR));
/* Startup logging */
#if 0
{
TempArena temp = BeginTempArena(scratch.arena);
String logfile_dir = CatString(temp.arena, g->write_path, Lit("logs/"));
String logfile_path = CatString(temp.arena, logfile_dir, logfile_name);
P_MkDir(logfile_dir);
LogStartup(logfile_path);
LogInfoF("Start of logs");
EndTempArena(temp);
}
LogInfoF("App started with args \"%F\" (%F parsed)", FmtString(args_str), FmtUint(args.count));
for (AppArg *arg = args.first; arg; arg = arg->next)
{
LogInfoF("Parsed arg: key = \"%F\", value = \"%F\"", FmtString(arg->key), FmtString(arg->value));
}
#endif
#if 0
/* Read window settings from file */
{
TempArena temp = BeginTempArena(scratch.arena);
P_WindowSettings window_settings = ZI;
String settings_path = CatAppWritePath(temp.arena, settings_file_name);
LogInfoF("Looking for settings file \"%F\"", FmtString(settings_path));
if (P_IsFile(settings_path))
{
LogInfoF("Settings file found");
P_File settings_file = P_OpenFileRead(settings_path);
String file_data = P_ReadFile(temp.arena, settings_file);
P_CloseFile(settings_file);
LogInfoF("Deserializing settings file data: %F", FmtString(file_data));
String error = ZI;
P_WindowSettings *deser = SETTINGS_WindowSettingsFromString(temp.arena, file_data, &error);
if (error.len > 0)
{
LogInfoF("Failed to load settings file with error - %F", FmtString(error));
String msg = StringF(temp.arena,
"Failed to loading settings file \"%F\":\n"
"------------\n"
"%F\n"
"------------\n"
"To stop this error from appearing, either fix the issue above or delete the file from the system.",
FmtString(settings_path),
FmtString(error));
Panic(msg);
}
LogInfoF("Settings file loaded successfully");
window_settings = *deser;
}
else
{
LogInfoF("Settings file not found, loading default");
window_settings = GetDefaultAppWindowSettings(window);
}
PushStringToBuff(StringFromArray(window_settings.title), Lit(WINDOW_TITLE));
P_UpdateWindowSettings(window, &window_settings);
EndTempArena(temp);
}
#endif
#if 0
/* Global systems */
RES_Startup();
W_Startup();
GPU_Startup();
/* Subsystems */
AC_StartupReceipt asset_cache_sr = AC_Startup();
TTF_Startup();
S_StartupReceipt sprite_sr = S_Startup();
MIX_StartupReceipt mixer_sr = MIX_Startup();
D_StartupReceipt draw_sr = D_Startup();
/* Interface systems */
SimStartupReceipt sim_sr = StartupSim();
PB_StartupReceipt playback_sr = PB_Startup(&mixer_sr);
UserStartupReceipt user_sr = StartupUser(&sprite_sr, &draw_sr, &asset_cache_sr, &mixer_sr, &sim_sr, connect_address);
#endif
PpMain();
#if 0
/* Write window settings to file */
{
__profn("Write settings file");
TempArena temp = BeginTempArena(scratch.arena);
String window_settings_path = CatAppWritePath(temp.arena, settings_file_name);
P_WindowSettings settings = P_GetWindowSettings(window);
String str = SETTINGS_StringFromWindowSettings(temp.arena, &settings);
LogInfoF("Serialized window settings: %F", FmtString(str));
LogInfoF("Writing settings file to path \"%F\"", FmtString(window_settings_path));
P_File settings_file = P_OpenFileWrite(window_settings_path);
P_WriteFile(settings_file, str);
P_CloseFile(settings_file);
LogInfoF("Finished writing settings file");
EndTempArena(temp);
}
#endif
#if 0
P_ReleaseWindow(window);
#endif
//LogInfoF("Program exited normally");
EndScratch(scratch);
}

View File

@ -1,39 +0,0 @@
////////////////////////////////////////////////////////////
//~ App arg types
Struct(AppArg)
{
String key;
String value;
AppArg *next;
};
Struct(AppArgList)
{
AppArg *first;
AppArg *last;
u64 count;
};
////////////////////////////////////////////////////////////
//~ State types
Struct(SharedAppState)
{
Arena *arena;
String write_path;
} extern shared_app_state;
////////////////////////////////////////////////////////////
//~ App functions
//- Write path
String InitializeAppWriteDirectory(Arena *arena, String write_dir);
String CatAppWritePath(Arena *arena, String filename);
//- Default window settings
P_WindowSettings GetDefaultAppWindowSettings(P_Window *window);
//- App args
AppArgList ParseAppArgs(Arena *arena, String args_str);

View File

@ -1,24 +0,0 @@
@Layer app
//- Dependencies
@Dep base
@Dep platform
@Dep ttf
@Dep gpu
@Dep sprite
@Dep watch
@Dep sound
@Dep font
@Dep asset_cache
@Dep mixer
@Dep settings
@Dep net
@Dep resource
@Dep playback
@Dep pp
//- Api
@IncludeC app.h
//- Impl
@IncludeC app.c

View File

@ -7,7 +7,6 @@
@Dep collider @Dep collider
@Dep net @Dep net
@Dep mixer @Dep mixer
@Dep rendertest
@Dep playback @Dep playback
@Dep platform @Dep platform
@Dep window @Dep window

View File

@ -1,16 +1,22 @@
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Key types //~ Key types
#define PP_NilKey ((PP_Key) { 0 }) #define PP_NilEntKey ((PP_EntKey) { 0 })
#define PP_RootEntKey ((PP_EntKey) { .v.hi = 0x75ebb7a47d1ca753, .v.lo = 0x2d505fc8961e5576 })
Struct(PP_EntKey) Struct(PP_EntKey)
{ {
U128 v; U128 v;
}; };
Struct(PP_EntNum) ////////////////////////////////////////////////////////////
//~ Shape types
Struct(PP_Shape)
{ {
u64 v; f32 radius;
u32 points_count;
Vec2 points[8];
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -36,6 +42,8 @@ Struct(PP_Ent)
PP_EntKey prev; PP_EntKey prev;
PP_EntKey key; PP_EntKey key;
PP_Shape shape;
} extern Readonly PP_nil_ent; } extern Readonly PP_nil_ent;
////////////////////////////// //////////////////////////////
@ -55,12 +63,11 @@ Struct(PP_EntList)
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ Ent lookup types //~ Lookup types
Struct(PP_EntLookupBin) Struct(PP_EntLookupBin)
{ {
PP_EntNum first; i32 _;
PP_EntNum last;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
@ -69,12 +76,14 @@ Struct(PP_EntLookupBin)
Struct(PP_World) Struct(PP_World)
{ {
i64 tick; i64 tick;
PP_Ent *ents; PP_Ent *ents;
i64 ents_count; i64 ents_count;
};
PP_EntLookupBin *bins; Struct(PP_WorldNode)
i64 bins_count; {
PP_WorldNode *next;
PP_World world;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -8,10 +8,15 @@ void PP_Startup(void)
PP_SharedState *shared = &PP_shared_state; PP_SharedState *shared = &PP_shared_state;
/* Initialize shared state */ /* Initialize shared state */
for (u64 i = 0; i < countof(shared->v2s); ++i) for (u64 i = 0; i < countof(shared->sim_input_states); ++i)
{ {
PP_VisToSimState *v2s = &shared->v2s[i]; PP_SimInputState *input = &shared->sim_input_states[i];
v2s->arena = AcquireArena(Gibi(64)); input->arena = AcquireArena(Gibi(64));
}
for (u64 i = 0; i < countof(shared->sim_output_states); ++i)
{
PP_SimOutputState *output = &shared->sim_output_states[i];
output->arena = AcquireArena(Gibi(64));
} }
/* Create job pools */ /* Create job pools */
@ -40,6 +45,27 @@ JobDef(PP_SimWorker, sig, job_id)
Arena *frame_arena = AcquireArena(Gibi(64)); Arena *frame_arena = AcquireArena(Gibi(64));
Arena *perm = PermArena(); Arena *perm = PermArena();
//- World data
Arena *ents_arena = AcquireArena(Gibi(64));
PP_Ent *ents = ArenaFirst(ents_arena, PP_Ent);
i64 tick = 0;
/* Create root ent */
{
PP_Ent *root_ent = PushStruct(ents_arena, PP_Ent);
*root_ent = PP_nil_ent;
root_ent->key = PP_RootEntKey;
}
/* Create test ent */
{
PP_Ent *test_ent = PushStruct(ents_arena, PP_Ent);
*test_ent = PP_nil_ent;
test_ent->parent = PP_RootEntKey;
test_ent->shape.points_count = 1;
test_ent->shape.radius = 0.25;
}
////////////////////////////// //////////////////////////////
//- Begin sim loop //- Begin sim loop
@ -56,22 +82,22 @@ JobDef(PP_SimWorker, sig, job_id)
////////////////////////////// //////////////////////////////
//- Pop sim commands //- Pop sim commands
PP_VisToSimState *v2s = 0; PP_SimInputState *input = 0;
LockTicketMutex(&shared->v2s_back_tm); LockTicketMutex(&shared->sim_input_back_tm);
{ {
v2s = &shared->v2s[shared->v2s_back_idx]; input = &shared->sim_input_states[shared->sim_input_back_idx];
++shared->v2s_back_idx; ++shared->sim_input_back_idx;
if (shared->v2s_back_idx >= countof(shared->v2s)) if (shared->sim_input_back_idx >= countof(shared->sim_input_states))
{ {
shared->v2s_back_idx = 0; shared->sim_input_back_idx = 0;
} }
} }
UnlockTicketMutex(&shared->v2s_back_tm); UnlockTicketMutex(&shared->sim_input_back_tm);
////////////////////////////// //////////////////////////////
//- Process sim commands //- Process sim commands
for (PP_SimCmdNode *cmd_node = v2s->first_cmd_node; cmd_node; cmd_node = cmd_node->next) for (PP_SimCmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
{ {
PP_SimCmd cmd = cmd_node->cmd; PP_SimCmd cmd = cmd_node->cmd;
switch (cmd.kind) switch (cmd.kind)
@ -83,28 +109,51 @@ JobDef(PP_SimWorker, sig, job_id)
} }
} }
//////////////////////////////
//- Publish sim state
LockTicketMutex(&shared->sim_output_back_tm);
{
PP_SimOutputState *output = &shared->sim_output_states[shared->sim_output_back_idx];
PP_WorldNode *world_node = PushStruct(output->arena, PP_WorldNode);
PP_World *world = &world_node->world;
SllQueuePush(output->first_world_node, output->last_world_node, world_node);
++output->worlds_count;
world->ents_count = ArenaCount(ents_arena, PP_Ent);
world->tick = tick;
world->ents = PushStructsNoZero(output->arena, PP_Ent, world->ents_count);
for (i64 ent_idx = 0; ent_idx < world->ents_count; ++ent_idx)
{
PP_Ent *ent = &ents[ent_idx];
world->ents[ent_idx] = *ent;
}
}
UnlockTicketMutex(&shared->sim_output_back_tm);
////////////////////////////// //////////////////////////////
//- End sim frame //- End sim frame
/* Reset front v2s */ /* Reset front input state */
{ {
Arena *arena = v2s->arena; Arena *arena = input->arena;
ResetArena(arena); ResetArena(arena);
ZeroStruct(v2s); ZeroStruct(input);
v2s->arena = arena; input->arena = arena;
} }
shutdown = Atomic32Fetch(&shared->shutdown);
i64 frame_end_ns = TimeNs(); i64 frame_end_ns = TimeNs();
++tick;
////////////////////////////// //////////////////////////////
//- Sleep //- Sleep
if (!Atomic32Fetch(&shared->shutdown))
{ {
i64 step_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND; i64 step_dt_ns = NsFromSeconds(1) / SIM_TICKS_PER_SECOND;
P_SleepFrame(frame_begin_ns, step_dt_ns); P_SleepFrame(frame_begin_ns, step_dt_ns);
} }
shutdown = Atomic32Fetch(&shared->shutdown);
} }
} }
@ -185,6 +234,17 @@ JobDef(PP_VisWorker, sig, job_id)
////////////////////////////// //////////////////////////////
//- Begin vis loop //- Begin vis loop
Arena *ents_arena = AcquireArena(Gibi(64));
PP_Ent *ents = ArenaFirst(ents_arena, PP_Ent);
i64 tick = 0;
b32 shutdown = 0; b32 shutdown = 0;
while (!shutdown) while (!shutdown)
{ {
@ -218,6 +278,33 @@ JobDef(PP_VisWorker, sig, job_id)
UI_Push(Height, UI_GROW(1, 0)); UI_Push(Height, UI_GROW(1, 0));
UI_Push(Parent, UI_BuildColumnEx(UI_KeyF("AAH"))); UI_Push(Parent, UI_BuildColumnEx(UI_KeyF("AAH")));
//////////////////////////////
//- Pop sim output
PP_SimOutputState *sim_output = 0;
LockTicketMutex(&shared->sim_output_back_tm);
{
sim_output = &shared->sim_output_states[shared->sim_output_back_idx];
++shared->sim_output_back_idx;
if (shared->sim_output_back_idx >= countof(shared->sim_output_states))
{
shared->sim_output_back_idx = 0;
}
}
UnlockTicketMutex(&shared->sim_output_back_tm);
{
PP_WorldNode *last = sim_output->last_world_node;
if (last && last->world.tick > tick)
{
ResetArena(ents_arena);
ents = PushStructsNoZero(ents_arena, PP_Ent, last->world.ents_count);
CopyStructs(ents, last->world.ents, last->world.ents_count);
tick = last->world.tick;
}
}
////////////////////////////// //////////////////////////////
//- Process controller events vis cmds //- Process controller events vis cmds
@ -370,9 +457,9 @@ JobDef(PP_VisWorker, sig, job_id)
////////////////////////////// //////////////////////////////
//- Submit sim commands //- Submit sim commands
LockTicketMutex(&shared->v2s_back_tm); LockTicketMutex(&shared->sim_input_back_tm);
{ {
PP_VisToSimState *v2s = &shared->v2s[shared->v2s_back_idx]; PP_SimInputState *v2s = &shared->sim_input_states[shared->sim_input_back_idx];
for (PP_EntListNode *ent_node = spawn_ents.first; ent_node; ent_node = ent_node->next) for (PP_EntListNode *ent_node = spawn_ents.first; ent_node; ent_node = ent_node->next)
{ {
PP_SimCmdNode *cmd_node = PushStruct(v2s->arena, PP_SimCmdNode); PP_SimCmdNode *cmd_node = PushStruct(v2s->arena, PP_SimCmdNode);
@ -382,7 +469,7 @@ JobDef(PP_VisWorker, sig, job_id)
++v2s->cmds_count; ++v2s->cmds_count;
} }
} }
UnlockTicketMutex(&shared->v2s_back_tm); UnlockTicketMutex(&shared->sim_input_back_tm);
////////////////////////////// //////////////////////////////
//- End vis frame //- End vis frame

View File

@ -94,9 +94,10 @@ Global Readonly PP_VisCmdDesc PP_vis_cmd_descs[PP_VisCmdKind_Count] = {
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
//~ State types //~ State types
#define PP_VisToSimStatesCount 2 #define PP_SimInputStatesCount 2
#define PP_SimOutputStatesCount 2
Struct(PP_VisToSimState) Struct(PP_SimInputState)
{ {
Arena *arena; Arena *arena;
PP_SimCmdNode *first_cmd_node; PP_SimCmdNode *first_cmd_node;
@ -104,6 +105,14 @@ Struct(PP_VisToSimState)
u64 cmds_count; u64 cmds_count;
}; };
Struct(PP_SimOutputState)
{
Arena *arena;
PP_WorldNode *first_world_node;
PP_WorldNode *last_world_node;
u64 worlds_count;
};
Struct(PP_SharedState) Struct(PP_SharedState)
{ {
Atomic32 shutdown; Atomic32 shutdown;
@ -111,9 +120,14 @@ Struct(PP_SharedState)
i64 workers_count; i64 workers_count;
//- Vis -> Sim //- Vis -> Sim
TicketMutex v2s_back_tm; TicketMutex sim_input_back_tm;
i32 v2s_back_idx; i32 sim_input_back_idx;
PP_VisToSimState v2s[PP_VisToSimStatesCount]; PP_SimInputState sim_input_states[PP_SimInputStatesCount];
//- Sim -> Vis
TicketMutex sim_output_back_tm;
i32 sim_output_back_idx;
PP_SimOutputState sim_output_states[PP_SimOutputStatesCount];
} extern PP_shared_state; } extern PP_shared_state;

View File

@ -1,6 +0,0 @@
////////////////////////////////////////////////////////////
//~ Startup
void RT_Startup(void)
{
}

View File

@ -1,4 +0,0 @@
////////////////////////////////////////////////////////////
//~ Startup
void RT_Startup(void);

View File

@ -1,16 +0,0 @@
@Layer rendertest
//- Dependencies
@Dep gpu
@Dep sprite
@Dep font
@Dep collider
//- Api
@IncludeC rendertest.h
//- Impl
@IncludeC rendertest.c
//- Startup
@Startup RT_Startup