create application directory in appdata
This commit is contained in:
parent
a00fcf3fba
commit
2bfc0d2ab2
@ -33,6 +33,10 @@
|
||||
#error Missing compile time definition for 'IsHotSwappingEnabled'
|
||||
#endif
|
||||
|
||||
#ifndef DefaultAppName
|
||||
#error Default application name not defined
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Machine context
|
||||
|
||||
@ -784,6 +788,7 @@ u64 MixU64s(u64 seed_a, u64 seed_b)
|
||||
|
||||
#if IsLanguageC
|
||||
StringList GetRawCommandline(void);
|
||||
String GetAppDirectory(void);
|
||||
void Echo(String msg);
|
||||
b32 Panic(String msg);
|
||||
Callstack CaptureCallstack(u64 skip_frames);
|
||||
|
||||
@ -177,24 +177,31 @@ Vec4 CR_Vec4FromString(String str)
|
||||
|
||||
b32 ok = 1;
|
||||
|
||||
if (StringBeginsWith(str, Lit("(")))
|
||||
{
|
||||
str.text += 1;
|
||||
str.len -= 1;
|
||||
}
|
||||
if (StringEndsWith(str, Lit(")")))
|
||||
{
|
||||
str.len -= 1;
|
||||
}
|
||||
// if (StringBeginsWith(str, Lit("(")))
|
||||
// {
|
||||
// str.text += 1;
|
||||
// str.len -= 1;
|
||||
// }
|
||||
// if (StringEndsWith(str, Lit(")")))
|
||||
// {
|
||||
// str.len -= 1;
|
||||
// }
|
||||
|
||||
u64 pos = 0;
|
||||
u64 parts_found = 0;
|
||||
String part = Zi;
|
||||
part.text = str.text;
|
||||
if (StringBeginsWith(str, Lit("(")))
|
||||
{
|
||||
part.text += 1;
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
while (pos < str.len && parts_found < 4)
|
||||
{
|
||||
u8 c = str.text[pos];
|
||||
if (c == ',' || c == ')' || pos + 1 >= str.len)
|
||||
u8 next_c = 0;
|
||||
if (c == ',' || c == ')')
|
||||
{
|
||||
part.len = (str.text + pos) - part.text;
|
||||
f64 part_float = CR_FloatFromString(part);
|
||||
@ -347,16 +354,7 @@ CR_Item *CR_ItemFromString(Arena *arena, String str)
|
||||
|
||||
if (text_end != -1)
|
||||
{
|
||||
if (!cur_item)
|
||||
{
|
||||
cur_item = PushStruct(arena, CR_Item);
|
||||
cur_item->parent = top_item->item;
|
||||
DllQueuePush(cur_item->parent->first, cur_item->parent->last, cur_item);
|
||||
cur_item->parent->count += 1;
|
||||
}
|
||||
|
||||
is_escaped = 0;
|
||||
text_is_string = 0;
|
||||
|
||||
String src_text = Zi;
|
||||
if (text_end > text_start)
|
||||
@ -365,8 +363,12 @@ CR_Item *CR_ItemFromString(Arena *arena, String str)
|
||||
src_text.text = str.text + text_start;
|
||||
}
|
||||
|
||||
if (is_name)
|
||||
if (!cur_item)
|
||||
{
|
||||
cur_item = PushStruct(arena, CR_Item);
|
||||
cur_item->parent = top_item->item;
|
||||
DllQueuePush(cur_item->parent->first, cur_item->parent->last, cur_item);
|
||||
cur_item->parent->count += 1;
|
||||
}
|
||||
|
||||
// FIXME: Arrays always have an item even if empty
|
||||
@ -406,9 +408,8 @@ CR_Item *CR_ItemFromString(Arena *arena, String str)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
mode = Mode_None;
|
||||
text_is_string = 0;
|
||||
}
|
||||
|
||||
pos += 1;
|
||||
|
||||
@ -482,6 +482,21 @@ String StringFromArray(Arena *arena, StringArray a)
|
||||
return result;
|
||||
}
|
||||
|
||||
String PathFromString(Arena *arena, String str, u8 path_delimiter)
|
||||
{
|
||||
String result = Zi;
|
||||
result = PushString(arena, str);
|
||||
for (u64 char_idx = 0; char_idx < result.len; ++char_idx)
|
||||
{
|
||||
u8 c = result.text[char_idx];
|
||||
if ((c == '\\' || c == '/') && c != path_delimiter)
|
||||
{
|
||||
result.text[char_idx] = path_delimiter;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ String list helpers
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Formatting types
|
||||
|
||||
#define DefaultFmtPrecision 3
|
||||
#define DefaultFmtPrecision 6
|
||||
#define Base16Chars ("0123456789abcdef")
|
||||
|
||||
Enum(FmtArgKind)
|
||||
@ -100,6 +100,7 @@ b32 StringContains(String str, String substring);
|
||||
b32 StringBeginsWith(String str, String substring);
|
||||
b32 StringEndsWith(String str, String substring);
|
||||
String StringFromArray(Arena *arena, StringArray a);
|
||||
String PathFromString(Arena *arena, String str, u8 path_delimiter);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Trimming helpers
|
||||
|
||||
@ -189,6 +189,11 @@ void SleepSeconds(f64 seconds)
|
||||
}
|
||||
}
|
||||
|
||||
String GetAppDirectory(void)
|
||||
{
|
||||
return W32.appdir_path;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookimpl Swap
|
||||
|
||||
@ -206,7 +211,7 @@ String SwappedStateFromName(Arena *arena, String name)
|
||||
{
|
||||
TempArena scratch = BeginScratch(arena);
|
||||
String result = Zi;
|
||||
String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name));
|
||||
String path = StringF(scratch.arena, "%F/swap/%F.swp", FmtString(GetAppDirectory()), FmtString(name));
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
HANDLE handle = CreateFileW(path_wstr, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
@ -234,11 +239,11 @@ String SwappedStateFromName(Arena *arena, String name)
|
||||
void WriteSwappedState(String name, String data)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
// TODO: Use directory non-relative to executable
|
||||
CreateDirectoryW(L"ppswap", 0);
|
||||
String result = Zi;
|
||||
String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name));
|
||||
String dir_path = PathFromString(scratch.arena, StringF(scratch.arena, "%F/swap", FmtString(GetAppDirectory())), '\\');
|
||||
String path = PathFromString(scratch.arena, StringF(scratch.arena, "%F/%F.swp", FmtString(dir_path), FmtString(name)), '\\');
|
||||
wchar_t *dir_path_wstr = WstrFromString(scratch.arena, dir_path);
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
SHCreateDirectoryExW(0, dir_path_wstr, 0);
|
||||
HANDLE handle = CreateFileW(path_wstr, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||
if (handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
@ -277,16 +282,14 @@ void ExitNow(i32 code)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Log
|
||||
|
||||
void W32_BootstrapLogs(String logfile_path)
|
||||
void W32_BootstrapLogs(void)
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
W32.logs_arena = AcquireArena(Gibi(64));
|
||||
W32.log_msgs_arena = AcquireArena(Gibi(64));
|
||||
W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent);
|
||||
if (logfile_path.len > 0)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
{
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, logfile_path);
|
||||
String logfile_path = StringF(perm, "%F/log.log", FmtString(GetAppDirectory()));
|
||||
wchar_t *path_wstr = WstrFromString(perm, logfile_path);
|
||||
W32.logfile = CreateFileW(
|
||||
path_wstr,
|
||||
FILE_APPEND_DATA,
|
||||
@ -296,10 +299,8 @@ void W32_BootstrapLogs(String logfile_path)
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0
|
||||
);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
}
|
||||
Atomic32Set(&W32.logs_initialized, 1);
|
||||
LogInfoF("Log file path: %F", FmtString(logfile_path));
|
||||
}
|
||||
|
||||
void W32_Log(i32 level, String msg)
|
||||
@ -443,8 +444,8 @@ i32 W32_Main(void)
|
||||
W32_InitCurrentThread(Lit("Main"));
|
||||
|
||||
// Get raw args from command line
|
||||
{
|
||||
Arena *perm = PermArena();
|
||||
{
|
||||
StringList args_list = Zi;
|
||||
{
|
||||
LPCWSTR cmdline_wstr = GetCommandLineW();
|
||||
@ -469,10 +470,78 @@ i32 W32_Main(void)
|
||||
// Bootstrap command line
|
||||
BootstrapCmdline();
|
||||
|
||||
// Init app directory
|
||||
String appdir_error = Zi;
|
||||
{
|
||||
String appdir_path = Zi;
|
||||
CommandlineArg appdir_arg = CommandlineArgFromName(Lit("appdir"));
|
||||
CommandlineArg appname_arg = CommandlineArgFromName(Lit("appname"));
|
||||
if (appdir_arg.exists && appdir_arg.value.len > 0)
|
||||
{
|
||||
appdir_path = appdir_arg.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
String appname = Lit(Stringize(DefaultAppName));
|
||||
if (appname_arg.exists && appname_arg.value.len > 0)
|
||||
{
|
||||
appname = appname_arg.value;
|
||||
}
|
||||
|
||||
wchar_t *path_wstr = 0;
|
||||
HRESULT hr = SHGetKnownFolderPath(&FOLDERID_LocalAppData, 0, 0, &path_wstr);
|
||||
if (!SUCCEEDED(hr))
|
||||
{
|
||||
Panic(Lit("Failed to locate AppData directory"));
|
||||
}
|
||||
appdir_path = StringFromWstrNoLimit(perm, path_wstr);
|
||||
CoTaskMemFree(path_wstr);
|
||||
appdir_path = PathFromString(perm, StringF(perm, "%F\\Cabin\\%F\\", FmtString(appdir_path), FmtString(appname)), '/');
|
||||
}
|
||||
// Create app dir
|
||||
{
|
||||
String path = PathFromString(perm, appdir_path, '\\');
|
||||
wchar_t *path_wstr = WstrFromString(perm, appdir_path);
|
||||
i32 err_code = SHCreateDirectoryExW(0, path_wstr, 0);
|
||||
String err = StringF(perm, "Error code %F", FmtSint(err_code));
|
||||
switch (err_code)
|
||||
{
|
||||
default: break;
|
||||
case ERROR_BAD_PATHNAME:
|
||||
{
|
||||
err = Lit("Bad path name");
|
||||
} break;
|
||||
case ERROR_FILENAME_EXCED_RANGE:
|
||||
{
|
||||
err = Lit("Path name too long");
|
||||
} break;
|
||||
case ERROR_CANCELLED:
|
||||
{
|
||||
err = Lit("User canceled the operation");
|
||||
} break;
|
||||
}
|
||||
if (err_code != ERROR_SUCCESS && err_code != ERROR_ALREADY_EXISTS && err_code != ERROR_FILE_EXISTS)
|
||||
{
|
||||
appdir_error = StringF(
|
||||
perm,
|
||||
"Failed to initialize app directory at \"%F\": %F",
|
||||
FmtString(path),
|
||||
FmtString(err)
|
||||
);
|
||||
wchar_t *msg_wstr = WstrFromString(perm, appdir_error);
|
||||
MessageBoxExW(0, msg_wstr, L"Warning", MB_ICONWARNING | MB_SETFOREGROUND | MB_TOPMOST, 0);
|
||||
}
|
||||
}
|
||||
W32.appdir_path = appdir_path;
|
||||
}
|
||||
|
||||
// Bootstrap log system
|
||||
// FIXME: Remove hardcoded log path
|
||||
W32_BootstrapLogs(Lit("log.log"));
|
||||
W32_BootstrapLogs();
|
||||
LogInfoF("Main thread ID: %F", FmtUint(ThreadId()));
|
||||
if (appdir_error.len > 0)
|
||||
{
|
||||
LogError(appdir_error);
|
||||
}
|
||||
|
||||
// Bootstrap resource system
|
||||
{
|
||||
|
||||
@ -68,6 +68,7 @@ Struct(W32_Ctx)
|
||||
i64 ns_per_qpc;
|
||||
|
||||
StringList raw_command_line;
|
||||
String appdir_path;
|
||||
|
||||
//- Application control flow
|
||||
|
||||
@ -107,7 +108,7 @@ BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Log
|
||||
|
||||
void W32_BootstrapLogs(String logfile_path);
|
||||
void W32_BootstrapLogs();
|
||||
void W32_Log(i32 level, String msg);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
@ -349,6 +349,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
PushStringToList(perm, &cp.defs, Lit("-DIsUnoptimized=1"));
|
||||
PushStringToList(perm, &cp.defs, Lit("-DIsTestingEnabled=0"));
|
||||
PushStringToList(perm, &cp.defs, Lit("-DIsHotSwappingEnabled=1"));
|
||||
PushStringToList(perm, &cp.defs, StringF(perm, "-DDefaultAppName=%F", FmtString(cmdline.leaf_layer_name)));
|
||||
}
|
||||
|
||||
//- Msvc
|
||||
@ -1015,7 +1016,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
||||
|
||||
if (lane->idx == 0)
|
||||
{
|
||||
EchoLine(StringF(perm, "Runtime: %Fs", FmtFloat(SecondsFromNs(TimeNs()))));
|
||||
EchoLine(StringF(perm, "Runtime: %Fs", FmtFloat(SecondsFromNs(TimeNs()), .p = 3)));
|
||||
ExitNow(GetBuildStatus());
|
||||
}
|
||||
}
|
||||
|
||||
@ -39,6 +39,10 @@
|
||||
#define IsHotSwappingEnabled 0
|
||||
#endif
|
||||
|
||||
#ifndef DefaultAppName
|
||||
#define DefaultAppName meta
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Includes
|
||||
|
||||
|
||||
@ -77,10 +77,8 @@ void PLT_Bootstrap(void);
|
||||
// NOTE: File paths use forward slash '/' as delimiter
|
||||
|
||||
//- File system helpers
|
||||
String PLT_GetWritePath(Arena *arena);
|
||||
b32 PLT_IsFile(String path);
|
||||
b32 PLT_IsDir(String path);
|
||||
void PLT_MkDir(String path);
|
||||
|
||||
//- File creation
|
||||
PLT_File PLT_OpenFileRead(String path);
|
||||
|
||||
@ -212,25 +212,6 @@ void PLT_W32_SyncTimerForever(WaveLaneCtx *lane)
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ @hookimpl File system
|
||||
|
||||
String PLT_GetWritePath(Arena *arena)
|
||||
{
|
||||
u16 *p = 0;
|
||||
// TODO: cache this?
|
||||
HRESULT result = SHGetKnownFolderPath(
|
||||
&FOLDERID_LocalAppData,
|
||||
0,
|
||||
0,
|
||||
&p
|
||||
);
|
||||
String path = Zi;
|
||||
if (result == S_OK)
|
||||
{
|
||||
path = PLT_W32_StringFromWin32Path(arena, p);
|
||||
}
|
||||
CoTaskMemFree(p);
|
||||
return path;
|
||||
}
|
||||
|
||||
b32 PLT_IsFile(String path)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
@ -249,47 +230,16 @@ b32 PLT_IsDir(String path)
|
||||
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
|
||||
void PLT_MkDir(String path)
|
||||
b32 PLT_MkDir(String path)
|
||||
{
|
||||
TempArena scratch = BeginScratchNoConflict();
|
||||
i32 err = 0;
|
||||
{
|
||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||
int err_code = SHCreateDirectory(0, path_wstr);
|
||||
String err = Zi;
|
||||
switch (err_code)
|
||||
{
|
||||
default: break;
|
||||
|
||||
case ERROR_BAD_PATHNAME:
|
||||
{
|
||||
err = Lit("Bad path name");
|
||||
} break;
|
||||
|
||||
case ERROR_FILENAME_EXCED_RANGE:
|
||||
{
|
||||
err = Lit("Path name too long");
|
||||
} break;
|
||||
|
||||
case ERROR_FILE_EXISTS:
|
||||
{
|
||||
err = Lit("A file already exists at this location");
|
||||
} break;
|
||||
|
||||
case ERROR_CANCELLED:
|
||||
{
|
||||
err = Lit("User canceled the operation");
|
||||
} break;
|
||||
}
|
||||
if (err.len > 0)
|
||||
{
|
||||
String msg = StringF(
|
||||
scratch.arena,
|
||||
"Failed to create directory \"%F\": %F",
|
||||
FmtString(path),
|
||||
FmtString(err)
|
||||
);
|
||||
Panic(msg);
|
||||
err = SHCreateDirectory(0, path_wstr);
|
||||
}
|
||||
EndScratch(scratch);
|
||||
return err == ERROR_SUCCESS || err == ERROR_ALREADY_EXISTS || err == ERROR_FILE_EXISTS;
|
||||
}
|
||||
|
||||
PLT_File PLT_OpenFileRead(String path)
|
||||
|
||||
@ -2,7 +2,6 @@ S_Ctx S = Zi;
|
||||
ThreadLocal S_ThreadLocalCtx S_tl = Zi;
|
||||
|
||||
Readonly S_Ent S_NilEnt = {
|
||||
.last_xf = CompXformIdentity,
|
||||
.xf = CompXformIdentity,
|
||||
.look = { 0, -1 },
|
||||
};
|
||||
@ -220,6 +219,30 @@ Rng2 S_BoundingBoxFromShape(S_Shape shape)
|
||||
return result;
|
||||
}
|
||||
|
||||
S_Shape S_LocalShapeFromEnt(S_Ent *ent)
|
||||
{
|
||||
S_Shape result = Zi;
|
||||
|
||||
// TODO: This is a temporary hack. Use prefab-lookup table.
|
||||
if (ent->is_player)
|
||||
{
|
||||
result = S_ShapeFromDesc(
|
||||
.mass = 10,
|
||||
.count = 1,
|
||||
.radius = 0.3,
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
S_Shape S_WorldShapeFromEnt(S_Ent *ent)
|
||||
{
|
||||
S_Shape local = S_LocalShapeFromEnt(ent);
|
||||
S_Shape world = S_MulXformShape(ent->xf, local);
|
||||
return world;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Collision
|
||||
|
||||
@ -1254,7 +1277,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
String packed = Zi;
|
||||
if (swapin)
|
||||
{
|
||||
packed = SwappedStateFromName(frame_arena, Lit("pp_sim.swp"));
|
||||
packed = SwappedStateFromName(frame_arena, Lit("pp_sim"));
|
||||
}
|
||||
S_UnpackedWorld unpacked = S_UnpackWorld(frame_arena, packed);
|
||||
|
||||
@ -1263,6 +1286,10 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
world->seed = unpacked.seed;
|
||||
world->tick = unpacked.tick;
|
||||
world->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, S_EntBin, world->ent_bins_count);
|
||||
@ -1279,7 +1306,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
if (swapout)
|
||||
{
|
||||
String packed = S_PackWorld(frame_arena, world);
|
||||
WriteSwappedState(Lit("pp_sim.swp"), packed);
|
||||
WriteSwappedState(Lit("pp_sim"), packed);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1309,9 +1336,30 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
//////////////////////////////
|
||||
//- Update double-buffered entity data
|
||||
|
||||
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||
// for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||
// {
|
||||
// ent->last_xf = ent->xf;
|
||||
// }
|
||||
|
||||
//////////////////////////////
|
||||
//- Process save commands
|
||||
|
||||
// FIXME: Only accept save command from local user
|
||||
|
||||
b32 should_save = 0;
|
||||
for (S_CmdNode *cmd_node = input->first_cmd_node; cmd_node; cmd_node = cmd_node->next)
|
||||
{
|
||||
ent->last_xf = ent->xf;
|
||||
S_Cmd *cmd = &cmd_node->cmd;
|
||||
if (cmd->kind == S_CmdKind_Save)
|
||||
{
|
||||
should_save = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (should_save)
|
||||
{
|
||||
String path = Lit("HAH");
|
||||
LogInfoF("Saving world to %F", FmtString(path));
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
@ -1410,7 +1458,8 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
desired_xf = XformWithWorldRotation(xf, AngleFromVec2(ent->look));
|
||||
}
|
||||
desired_xf.og = AddVec2(xf.og, MulVec2(ent->move, ent->move_speed));
|
||||
f32 move_speed = TweakFloat("Player move speed", 6.5, 0, 20);
|
||||
desired_xf.og = AddVec2(xf.og, MulVec2(ent->move, move_speed * sim_dt));
|
||||
|
||||
Vec2 pos_diff = SubVec2(desired_xf.og, xf.og);
|
||||
f32 angle_diff = UnwindAngleF32(RotationFromXform(desired_xf) - RotationFromXform(xf));
|
||||
@ -1436,55 +1485,45 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
|
||||
|
||||
|
||||
// for (i32 tile_y = bb_tiles.p0.y; tile_y < bb_tiles.p1.y; ++tile_y)
|
||||
|
||||
// for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||
// {
|
||||
// for (i32 tile_x = bb_tiles.p0.x; tile_x < bb_tiles.p1.x; ++tile_x)
|
||||
// if (ent->is_player)
|
||||
// {
|
||||
// Vec2I32 tile_pos = VEC2I32(tile_x, tile_y);
|
||||
// S_TileKind tile = S_TileFromPos(tile_pos);
|
||||
// Xform last_xf = ent->last_xf;
|
||||
// S_Shape last_world_shape = S_MulXformShape(last_xf, ent->local_shape);
|
||||
|
||||
// Xform xf = ent->xf;
|
||||
// S_Shape world_shape = S_MulXformShape(xf, ent->local_shape);
|
||||
|
||||
// Rng2 bb0 = S_BoundingBoxFromShape(last_world_shape);
|
||||
// Rng2 bb1 = S_BoundingBoxFromShape(world_shape);
|
||||
|
||||
// if (constraints_count < max_constraints)
|
||||
// {
|
||||
// S_Constraint *constraint = &constraints[constraints_count];
|
||||
|
||||
// // TODO: Real constraint data
|
||||
|
||||
// constraint->ent0 = ent->key;
|
||||
// constraint->shape0 = world_shape;
|
||||
|
||||
// Rng2 test_rect = Zi;
|
||||
// test_rect.p0 = VEC2(-1, -1);
|
||||
// test_rect.p1 = VEC2(1, 1);
|
||||
// constraint->shape1 = S_ShapeFromDesc(
|
||||
// .radius = 0.5,
|
||||
// .count = 4,
|
||||
// .points[0] = VEC2(test_rect.p0.x, test_rect.p0.y),
|
||||
// .points[1] = VEC2(test_rect.p1.x, test_rect.p0.y),
|
||||
// .points[2] = VEC2(test_rect.p1.x, test_rect.p1.y),
|
||||
// .points[3] = VEC2(test_rect.p0.x, test_rect.p1.y),
|
||||
// );
|
||||
|
||||
// constraints_count += 1;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||
{
|
||||
if (ent->is_player)
|
||||
{
|
||||
Xform last_xf = ent->last_xf;
|
||||
S_Shape last_world_shape = S_MulXformShape(last_xf, ent->local_shape);
|
||||
|
||||
Xform xf = ent->xf;
|
||||
S_Shape world_shape = S_MulXformShape(xf, ent->local_shape);
|
||||
|
||||
Rng2 bb0 = S_BoundingBoxFromShape(last_world_shape);
|
||||
Rng2 bb1 = S_BoundingBoxFromShape(world_shape);
|
||||
|
||||
if (constraints_count < max_constraints)
|
||||
{
|
||||
S_Constraint *constraint = &constraints[constraints_count];
|
||||
|
||||
// TODO: Real constraint data
|
||||
|
||||
constraint->ent0 = ent->key;
|
||||
constraint->shape0 = world_shape;
|
||||
|
||||
Rng2 test_rect = Zi;
|
||||
test_rect.p0 = VEC2(-1, -1);
|
||||
test_rect.p1 = VEC2(1, 1);
|
||||
constraint->shape1 = S_ShapeFromDesc(
|
||||
.radius = 0.5,
|
||||
.count = 4,
|
||||
.points[0] = VEC2(test_rect.p0.x, test_rect.p0.y),
|
||||
.points[1] = VEC2(test_rect.p1.x, test_rect.p0.y),
|
||||
.points[2] = VEC2(test_rect.p1.x, test_rect.p1.y),
|
||||
.points[3] = VEC2(test_rect.p0.x, test_rect.p1.y),
|
||||
);
|
||||
|
||||
constraints_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////
|
||||
//- Solve constraints
|
||||
@ -1643,8 +1682,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
i64 tick_bullets_count = bullets_per_fire;
|
||||
if (tick_bullets_count > 0)
|
||||
{
|
||||
Xform firer_xf = firer->xf;
|
||||
S_Shape firer_world_shape = S_MulXformShape(firer_xf, firer->local_shape);
|
||||
S_Shape firer_world_shape = S_WorldShapeFromEnt(firer);
|
||||
|
||||
Vec2 pos = S_EdgePointFromShape(firer_world_shape, firer->look);
|
||||
|
||||
@ -1706,8 +1744,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
if (victim->is_player && !S_MatchKey(victim->key, bullet->bullet_firer))
|
||||
{
|
||||
Xform victim_xf = victim->xf;
|
||||
S_Shape victim_world_shape = S_MulXformShape(victim_xf, victim->local_shape);
|
||||
S_Shape victim_world_shape = S_WorldShapeFromEnt(victim);
|
||||
|
||||
S_RaycastResult entrance_raycast = S_RaycastShape(victim_world_shape, ray_start, ray_dir);
|
||||
Vec2 entrance = entrance_raycast.p;
|
||||
@ -1885,8 +1922,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
||||
{
|
||||
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||
{
|
||||
Xform xf = ent->xf;
|
||||
S_Shape world_shape = S_MulXformShape(xf, ent->local_shape);
|
||||
S_Shape world_shape = S_WorldShapeFromEnt(ent);
|
||||
|
||||
// Draw aabb
|
||||
{
|
||||
|
||||
@ -62,12 +62,8 @@ Struct(S_Ent)
|
||||
b32 is_player;
|
||||
f32 health;
|
||||
|
||||
Xform last_xf;
|
||||
Xform xf;
|
||||
|
||||
S_Shape local_shape;
|
||||
|
||||
f32 move_speed;
|
||||
Vec2 move;
|
||||
Vec2 look;
|
||||
f32 fire_held;
|
||||
@ -245,6 +241,7 @@ Struct(S_SnapshotNode)
|
||||
Enum(S_CmdKind)
|
||||
{
|
||||
S_CmdKind_Nop,
|
||||
S_CmdKind_Save,
|
||||
S_CmdKind_Delta,
|
||||
S_CmdKind_Control,
|
||||
};
|
||||
@ -394,6 +391,9 @@ S_Shape S_ShapeFromDescEx(S_ShapeDesc desc);
|
||||
S_Shape S_MulXformShape(Xform xf, S_Shape shape);
|
||||
Rng2 S_BoundingBoxFromShape(S_Shape shape);
|
||||
|
||||
S_Shape S_LocalShapeFromEnt(S_Ent *ent);
|
||||
S_Shape S_WorldShapeFromEnt(S_Ent *ent);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Collision
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
////////////////////////////////////////////////////////////
|
||||
//~ Tile types
|
||||
|
||||
#define S_WorldPitch 80.0
|
||||
#define S_WorldPitch 60.0
|
||||
#define S_TilesPitch (S_WorldPitch * 2)
|
||||
#define S_TilesCount (S_TilesPitch * S_TilesPitch)
|
||||
|
||||
|
||||
@ -15,6 +15,11 @@ String S_PackWorld(Arena *arena, S_World *src_world)
|
||||
|
||||
result.len += StringF(arena, "version: %F\n", FmtUint(S_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;
|
||||
|
||||
// Pack entities
|
||||
// FIXME: Precision
|
||||
result.len += PushString(arena, Lit("\nentities:\n")).len;
|
||||
@ -24,14 +29,23 @@ String S_PackWorld(Arena *arena, S_World *src_world)
|
||||
result.len += StringF(arena, " 0x%F:\n", FmtHex(ent->key.v)).len;
|
||||
result.len += PushString(arena, Lit(" {\n")).len;
|
||||
{
|
||||
result.len += StringF(arena, " props: \n").len;
|
||||
result.len += StringF(arena, " {\n").len;
|
||||
{
|
||||
if (ent->is_player)
|
||||
{
|
||||
result.len += PushString(arena, Lit(" player\n")).len;
|
||||
}
|
||||
if (ent->is_bullet)
|
||||
{
|
||||
result.len += PushString(arena, Lit(" bullet\n")).len;
|
||||
}
|
||||
}
|
||||
result.len += StringF(arena, " }\n").len;
|
||||
result.len += StringF(arena, " pos: \"%F\"\n", FmtFloat2(ent->xf.og)).len;
|
||||
result.len += StringF(arena, " rot: \"%F\"\n", FmtFloat2(RightFromXform(ent->xf))).len;
|
||||
result.len += StringF(arena, " exists: \"%F\"\n", FmtFloat(ent->exists)).len;
|
||||
result.len += StringF(arena, " look: \"%F\"\n", FmtFloat2(ent->look)).len;
|
||||
if (ent->is_player)
|
||||
{
|
||||
result.len += PushString(arena, Lit(" player: true\n")).len;
|
||||
}
|
||||
}
|
||||
result.len += PushString(arena, Lit(" }\n")).len;
|
||||
}
|
||||
@ -69,7 +83,7 @@ S_UnpackedWorld S_UnpackWorld(Arena *arena, String packed)
|
||||
|
||||
CR_Item *root = CR_ItemFromString(scratch.arena, packed);
|
||||
|
||||
// Get version
|
||||
// Unpack version
|
||||
S_Tv version = 0;
|
||||
for (CR_Item *root_item = root->first; root_item; root_item = root_item->next)
|
||||
{
|
||||
@ -82,47 +96,67 @@ S_UnpackedWorld S_UnpackWorld(Arena *arena, String packed)
|
||||
|
||||
for (CR_Item *top_item = root->first; top_item; top_item = top_item->next)
|
||||
{
|
||||
// Parse entities
|
||||
// Unpack metadata
|
||||
if (MatchString(top_item->name, Lit("seed")))
|
||||
{
|
||||
result.seed = CR_IntFromString(top_item->value);
|
||||
}
|
||||
if (MatchString(top_item->name, Lit("tick")))
|
||||
{
|
||||
result.tick = CR_IntFromString(top_item->value);
|
||||
}
|
||||
if (MatchString(top_item->name, Lit("time")))
|
||||
{
|
||||
result.time_ns = CR_IntFromString(top_item->value);
|
||||
}
|
||||
|
||||
// Unpack entities
|
||||
if (MatchString(top_item->name, Lit("entities")))
|
||||
{
|
||||
for (CR_Item *ent_item = top_item->first; ent_item; ent_item = ent_item->next)
|
||||
{
|
||||
S_Ent *ent = S_PushTempEnt(arena, &result.ents);
|
||||
ent->key = (S_Key) { .v = CR_IntFromString(ent_item->name) };
|
||||
for (CR_Item *prop = ent_item->first; prop; prop = prop->next)
|
||||
for (CR_Item *attr = ent_item->first; attr; attr = attr->next)
|
||||
{
|
||||
if (MatchString(prop->name, Lit("pos")))
|
||||
if (MatchString(attr->name, Lit("props")))
|
||||
{
|
||||
Vec2 pos = CR_Vec2FromString(prop->value);
|
||||
ent->xf.og = pos;
|
||||
}
|
||||
if (MatchString(prop->name, Lit("rot")))
|
||||
for (CR_Item *prop = attr->first; prop; prop = prop->next)
|
||||
{
|
||||
Vec2 rot = CR_Vec2FromString(prop->value);
|
||||
ent->xf = XformWithWorldRotation(ent->xf, AngleFromVec2(rot));
|
||||
}
|
||||
if (MatchString(prop->name, Lit("exists")))
|
||||
{
|
||||
ent->exists = CR_FloatFromString(prop->value);
|
||||
}
|
||||
if (MatchString(prop->name, Lit("health")))
|
||||
{
|
||||
ent->health = CR_FloatFromString(prop->value);
|
||||
}
|
||||
if (MatchString(prop->name, Lit("look")))
|
||||
{
|
||||
Vec2 look = CR_Vec2FromString(prop->value);
|
||||
ent->look = look;
|
||||
}
|
||||
if (MatchString(prop->name, Lit("player")) && CR_BoolFromString(prop->value))
|
||||
if (MatchString(prop->value, Lit("player")))
|
||||
{
|
||||
ent->is_player = 1;
|
||||
ent->has_weapon = 1;
|
||||
}
|
||||
// if (MatchString(prop->name, Lit("bullet")) && CR_BoolFromString(prop->value))
|
||||
// {
|
||||
// ent->is_bullet = 1;
|
||||
// }
|
||||
if (MatchString(prop->value, Lit("bullet")))
|
||||
{
|
||||
ent->is_bullet = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (MatchString(attr->name, Lit("pos")))
|
||||
{
|
||||
Vec2 pos = CR_Vec2FromString(attr->value);
|
||||
ent->xf.og = pos;
|
||||
}
|
||||
if (MatchString(attr->name, Lit("rot")))
|
||||
{
|
||||
Vec2 rot = CR_Vec2FromString(attr->value);
|
||||
ent->xf = XformWithWorldRotation(ent->xf, AngleFromVec2(rot));
|
||||
}
|
||||
if (MatchString(attr->name, Lit("exists")))
|
||||
{
|
||||
ent->exists = CR_FloatFromString(attr->value);
|
||||
}
|
||||
if (MatchString(attr->name, Lit("health")))
|
||||
{
|
||||
ent->health = CR_FloatFromString(attr->value);
|
||||
}
|
||||
if (MatchString(attr->name, Lit("look")))
|
||||
{
|
||||
Vec2 look = CR_Vec2FromString(attr->value);
|
||||
ent->look = look;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -148,160 +182,3 @@ S_UnpackedWorld S_UnpackWorld(Arena *arena, String packed)
|
||||
EndScratch(scratch);
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// ////////////////////////////////////////////////////////////
|
||||
// //~ Transcode
|
||||
|
||||
// S_TranscodeResult S_TranscodeWorld(Arena *arena, S_World *src_world, String src_packed, b32 pack)
|
||||
// {
|
||||
// S_TranscodeResult result = Zi;
|
||||
// result.ok = 1;
|
||||
// result.version = S_Tv_Latest;
|
||||
|
||||
// //////////////////////////////
|
||||
// //- Init bitbuff
|
||||
|
||||
// u32 level_magic = 0xa2bf209c;
|
||||
|
||||
// BB_Buff bb = Zi;
|
||||
// BB_Writer bw = Zi;
|
||||
// BB_Reader br = Zi;
|
||||
// if (pack)
|
||||
// {
|
||||
// bb = BB_AcquireDynamicBuff(Gibi(4));
|
||||
// bw = BB_WriterFromBuff(&bb);
|
||||
// BB_WriteUBits(&bw, level_magic, 32);
|
||||
// BB_WriteUBits(&bw, result.version, 32);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// bb = BB_BuffFromString(src_packed);
|
||||
// br = BB_ReaderFromBuff(&bb);
|
||||
// result.ok = BB_ReadUBits(&br, 32) == level_magic;
|
||||
// result.version = (S_Tv)BB_ReadUBits(&br, 32);
|
||||
// result.unpacked = PushStruct(arena, S_World);
|
||||
// }
|
||||
|
||||
// //////////////////////////////
|
||||
// //- Transcode world metadata
|
||||
|
||||
// if (pack)
|
||||
// {
|
||||
// BB_WriteUBits(&bw, src_world->seed, 64);
|
||||
// BB_WriteIBits(&bw, src_world->tick, 64);
|
||||
// BB_WriteIBits(&bw, src_world->time_ns, 64);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// result.unpacked->seed = BB_ReadUBits(&br, 64);
|
||||
// result.unpacked->tick = BB_ReadIBits(&br, 64);
|
||||
// result.unpacked->time_ns = BB_ReadIBits(&br, 64);
|
||||
// }
|
||||
|
||||
// //////////////////////////////
|
||||
// //- Transcode tiles
|
||||
|
||||
// // TODO: Compress tile data
|
||||
|
||||
// if (pack)
|
||||
// {
|
||||
// String tiles_str = Zi;
|
||||
// tiles_str.len = S_TilesCount;
|
||||
// tiles_str.text = src_world->tiles;
|
||||
// BB_WriteUBits(&bw, tiles_str.len, 64);
|
||||
// BB_WriteBytes(&bw, tiles_str);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// u64 raw_tiles_count = BB_ReadUBits(&br, 64);
|
||||
// u8 *raw_tiles = BB_ReadBytesRaw(&br, raw_tiles_count);
|
||||
// if (raw_tiles && raw_tiles_count == S_TilesCount)
|
||||
// {
|
||||
// result.unpacked->tiles = PushStructsNoZero(arena, u8, raw_tiles_count);
|
||||
// CopyBytes(result.unpacked->tiles, raw_tiles, raw_tiles_count);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// result.unpacked->tiles = PushStructs(arena, u8, S_TilesCount);
|
||||
// result.ok = 0;
|
||||
// }
|
||||
// }
|
||||
|
||||
// //////////////////////////////
|
||||
// //- Transcode entities
|
||||
|
||||
// // TODO: Compress entity data
|
||||
|
||||
// if (result.ok)
|
||||
// {
|
||||
// if (pack)
|
||||
// {
|
||||
// u32 ent_size = sizeof(S_Ent);
|
||||
// u32 ent_align = alignof(S_Ent);
|
||||
// i64 ents_count = src_world->ents_count;
|
||||
// BB_WriteUBits(&bw, ent_size, 32);
|
||||
// BB_WriteUBits(&bw, ent_align, 32);
|
||||
// BB_WriteUBits(&bw, ents_count, 64);
|
||||
// for (S_Ent *ent = S_FirstEnt(src_world); ent->valid; ent = S_NextEnt(ent))
|
||||
// {
|
||||
// BB_WriteBytes(&bw, StringFromStruct(ent));
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// i64 ent_size = BB_ReadUBits(&br, 32);
|
||||
// i64 ent_align = BB_ReadUBits(&br, 32);
|
||||
// i64 ents_count = BB_ReadUBits(&br, 64);
|
||||
// if (ent_size == sizeof(S_Ent) && ent_align == alignof(S_Ent))
|
||||
// {
|
||||
// for (i64 i = 0; i < ents_count; ++i)
|
||||
// {
|
||||
// S_Ent *raw_ent = (S_Ent *)BB_ReadBytesRaw(&br, sizeof(S_Ent));
|
||||
// if (raw_ent)
|
||||
// {
|
||||
// S_Ent *ent = PushStructNoZero(arena, S_Ent);
|
||||
// {
|
||||
// CopyBytes(ent, raw_ent, ent_size);
|
||||
// ent->valid = 1;
|
||||
// }
|
||||
// DllQueuePush(result.unpacked->first_ent, result.unpacked->last_ent, ent);
|
||||
// result.unpacked->ents_count += 1;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// result.ok = 0;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// result.ok = 0;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// //////////////////////////////
|
||||
// //- Finalize
|
||||
|
||||
// if (result.ok)
|
||||
// {
|
||||
// if (pack)
|
||||
// {
|
||||
// result.packed = BB_GetWritten(arena, &bw);
|
||||
// BB_ReleaseDynamicBuff(&bb);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (!result.unpacked->seed)
|
||||
// {
|
||||
// TrueRand(StringFromStruct(&result.unpacked->seed));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// return result;
|
||||
// }
|
||||
|
||||
@ -274,7 +274,7 @@ V_WidgetTheme V_GetWidgetTheme(void)
|
||||
theme.icon_font = UI_BuiltinIconFont();
|
||||
|
||||
// theme.font_size = 14;
|
||||
theme.font_size = TweakFloat("Font size", 14, 6, 50, .precision = 0);
|
||||
theme.font_size = TweakFloat("Font size", 14, 8, 24, .precision = 0);
|
||||
theme.h1 = 2.00;
|
||||
theme.h2 = 1.50;
|
||||
theme.h3 = 1.25;
|
||||
@ -558,7 +558,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
else
|
||||
{
|
||||
String swap_encoded = SwappedStateFromName(frame->arena, Lit("pp_vis.swp"));
|
||||
String swap_encoded = SwappedStateFromName(frame->arena, Lit("pp_vis"));
|
||||
bb = BB_BuffFromString(swap_encoded);
|
||||
br = BB_ReaderFromBuff(&bb);
|
||||
}
|
||||
@ -586,7 +586,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
// Write swapout
|
||||
if (swapout)
|
||||
{
|
||||
WriteSwappedState(Lit("pp_vis.swp"), STRING(BB_GetNumBytesWritten(&bw), BB_GetWrittenRaw(&bw)));
|
||||
WriteSwappedState(Lit("pp_vis"), STRING(BB_GetNumBytesWritten(&bw), BB_GetWrittenRaw(&bw)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -861,7 +861,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
look_ratio.y = 0.25;
|
||||
look_ratio.x = look_ratio.y / (16.0 / 9.0);
|
||||
S_Ent *player = S_EntFromKey(world, V.player_key);
|
||||
target_camera_pos = MulXformV2(player->xf, player->local_shape.centroid);
|
||||
target_camera_pos = S_WorldShapeFromEnt(player).centroid;
|
||||
target_camera_pos = AddVec2(target_camera_pos, MulVec2Vec2(player->look, look_ratio));
|
||||
target_camera_zoom = 1;
|
||||
}
|
||||
@ -1010,7 +1010,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
S_Shape cursor_shape = S_ShapeFromDesc(.count = 1, .points = { frame->world_cursor });
|
||||
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||
{
|
||||
S_Shape ent_shape = S_MulXformShape(ent->xf, ent->local_shape);
|
||||
S_Shape ent_shape = S_WorldShapeFromEnt(ent);
|
||||
b32 is_hovered = S_CollisionResultFromShapes(ent_shape, cursor_shape).collision_points_count > 0;
|
||||
if (is_hovered)
|
||||
{
|
||||
@ -2379,9 +2379,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
UI_Push(BackgroundColor, color);
|
||||
UI_Push(Width, UI_GROW(1, 0));
|
||||
UI_Push(Height, UI_FNT(1.5, 1));
|
||||
UI_Push(BorderColor, Rgb(0.25, 0.25, 0.25));
|
||||
UI_Push(Rounding, UI_RPIX(0));
|
||||
UI_Push(BorderSize, 1);
|
||||
UI_Push(BorderSize, 0);
|
||||
UI_Push(ChildAlignment, UI_Region_Left);
|
||||
UI_PushCP(UI_BuildRow());
|
||||
{
|
||||
@ -2517,13 +2516,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
*ent = S_NilEnt;
|
||||
ent->key = V.player_key;
|
||||
ent->xf = XformFromPos(player_pos);
|
||||
ent->move_speed = 0.075;
|
||||
ent->is_player = 1;
|
||||
ent->local_shape = S_ShapeFromDesc(
|
||||
.mass = 10,
|
||||
.count = 1,
|
||||
.radius = 0.3,
|
||||
);
|
||||
ent->has_weapon = 1;
|
||||
ent->exists = 1;
|
||||
}
|
||||
@ -2537,13 +2530,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
*ent = S_NilEnt;
|
||||
ent->key = S_RandKey();
|
||||
ent->xf = XformFromPos(frame->world_cursor);
|
||||
ent->move_speed = 0.075;
|
||||
ent->is_player = 1;
|
||||
ent->local_shape = S_ShapeFromDesc(
|
||||
.mass = 10,
|
||||
.count = 1,
|
||||
.radius = 0.3,
|
||||
);
|
||||
ent->has_weapon = 1;
|
||||
ent->exists = 1;
|
||||
} break;
|
||||
@ -2560,6 +2547,14 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
}
|
||||
} break;
|
||||
|
||||
case V_CmdKind_save_level:
|
||||
{
|
||||
if (frame->is_editing)
|
||||
{
|
||||
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Save);
|
||||
}
|
||||
} break;
|
||||
|
||||
case V_CmdKind_clear_particles:
|
||||
{
|
||||
should_clear_particles = 1;
|
||||
@ -2582,7 +2577,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
||||
f32 fire_presses = fire_held && !last_frame->held_buttons[Button_M1];
|
||||
Vec2 look = Zi;
|
||||
{
|
||||
Vec2 center = MulXformV2(player->xf, player->local_shape.centroid);
|
||||
Vec2 center = S_WorldShapeFromEnt(player).centroid;
|
||||
look = SubVec2(frame->world_cursor, center);
|
||||
}
|
||||
if (frame->is_editing)
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
X(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \
|
||||
X(zoom_out, Zoom Out, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelDown ), ) \
|
||||
X(toggle_editor, Toggle Editor, V_CmdDescFlag_None, V_HOTKEY( Button_F1 ), ) \
|
||||
X(save_level, Save level, V_CmdDescFlag_None, V_HOTKEY( Button_S, .ctrl = 1 ), ) \
|
||||
X(toggle_ui_debug, Toggle UI Debug, V_CmdDescFlag_None, V_HOTKEY( Button_F5 ), ) \
|
||||
X(toggle_console, Toggle Developer Console, V_CmdDescFlag_None, V_HOTKEY( Button_GraveAccent ), ) \
|
||||
X(toggle_fullscreen, Toggle Fullscreen Mode, V_CmdDescFlag_None, V_HOTKEY( Button_Enter, .alt = 1 ) ) \
|
||||
@ -15,7 +16,7 @@
|
||||
X(spawn, Spawn/Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_Q ), ) \
|
||||
X(spawn_dummy, Spawn Dummy, V_CmdDescFlag_None, V_HOTKEY( Button_T ), ) \
|
||||
X(delete, Delete entity at cursor, V_CmdDescFlag_None, V_HOTKEY( Button_M2 ), ) \
|
||||
X(reset_world, Reset world, V_CmdDescFlag_None, V_HOTKEY( Button_R ), ) \
|
||||
X(reset_world, Reset world, V_CmdDescFlag_None, V_HOTKEY( Button_R, .ctrl = 1, .alt = 1 ), ) \
|
||||
X(clear_particles, Clear particles, V_CmdDescFlag_None, V_HOTKEY( Button_C ), ) \
|
||||
/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user