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'
|
#error Missing compile time definition for 'IsHotSwappingEnabled'
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef DefaultAppName
|
||||||
|
#error Default application name not defined
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Machine context
|
//~ Machine context
|
||||||
|
|
||||||
@ -784,6 +788,7 @@ u64 MixU64s(u64 seed_a, u64 seed_b)
|
|||||||
|
|
||||||
#if IsLanguageC
|
#if IsLanguageC
|
||||||
StringList GetRawCommandline(void);
|
StringList GetRawCommandline(void);
|
||||||
|
String GetAppDirectory(void);
|
||||||
void Echo(String msg);
|
void Echo(String msg);
|
||||||
b32 Panic(String msg);
|
b32 Panic(String msg);
|
||||||
Callstack CaptureCallstack(u64 skip_frames);
|
Callstack CaptureCallstack(u64 skip_frames);
|
||||||
|
|||||||
@ -177,24 +177,31 @@ Vec4 CR_Vec4FromString(String str)
|
|||||||
|
|
||||||
b32 ok = 1;
|
b32 ok = 1;
|
||||||
|
|
||||||
if (StringBeginsWith(str, Lit("(")))
|
// if (StringBeginsWith(str, Lit("(")))
|
||||||
{
|
// {
|
||||||
str.text += 1;
|
// str.text += 1;
|
||||||
str.len -= 1;
|
// str.len -= 1;
|
||||||
}
|
// }
|
||||||
if (StringEndsWith(str, Lit(")")))
|
// if (StringEndsWith(str, Lit(")")))
|
||||||
{
|
// {
|
||||||
str.len -= 1;
|
// str.len -= 1;
|
||||||
}
|
// }
|
||||||
|
|
||||||
u64 pos = 0;
|
u64 pos = 0;
|
||||||
u64 parts_found = 0;
|
u64 parts_found = 0;
|
||||||
String part = Zi;
|
String part = Zi;
|
||||||
part.text = str.text;
|
part.text = str.text;
|
||||||
|
if (StringBeginsWith(str, Lit("(")))
|
||||||
|
{
|
||||||
|
part.text += 1;
|
||||||
|
pos += 1;
|
||||||
|
}
|
||||||
|
|
||||||
while (pos < str.len && parts_found < 4)
|
while (pos < str.len && parts_found < 4)
|
||||||
{
|
{
|
||||||
u8 c = str.text[pos];
|
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;
|
part.len = (str.text + pos) - part.text;
|
||||||
f64 part_float = CR_FloatFromString(part);
|
f64 part_float = CR_FloatFromString(part);
|
||||||
@ -347,16 +354,7 @@ CR_Item *CR_ItemFromString(Arena *arena, String str)
|
|||||||
|
|
||||||
if (text_end != -1)
|
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;
|
is_escaped = 0;
|
||||||
text_is_string = 0;
|
|
||||||
|
|
||||||
String src_text = Zi;
|
String src_text = Zi;
|
||||||
if (text_end > text_start)
|
if (text_end > text_start)
|
||||||
@ -365,8 +363,12 @@ CR_Item *CR_ItemFromString(Arena *arena, String str)
|
|||||||
src_text.text = str.text + text_start;
|
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
|
// FIXME: Arrays always have an item even if empty
|
||||||
@ -406,9 +408,8 @@ CR_Item *CR_ItemFromString(Arena *arena, String str)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
mode = Mode_None;
|
mode = Mode_None;
|
||||||
|
text_is_string = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos += 1;
|
pos += 1;
|
||||||
|
|||||||
@ -482,6 +482,21 @@ String StringFromArray(Arena *arena, StringArray a)
|
|||||||
return result;
|
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
|
//~ String list helpers
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Formatting types
|
//~ Formatting types
|
||||||
|
|
||||||
#define DefaultFmtPrecision 3
|
#define DefaultFmtPrecision 6
|
||||||
#define Base16Chars ("0123456789abcdef")
|
#define Base16Chars ("0123456789abcdef")
|
||||||
|
|
||||||
Enum(FmtArgKind)
|
Enum(FmtArgKind)
|
||||||
@ -100,6 +100,7 @@ b32 StringContains(String str, String substring);
|
|||||||
b32 StringBeginsWith(String str, String substring);
|
b32 StringBeginsWith(String str, String substring);
|
||||||
b32 StringEndsWith(String str, String substring);
|
b32 StringEndsWith(String str, String substring);
|
||||||
String StringFromArray(Arena *arena, StringArray a);
|
String StringFromArray(Arena *arena, StringArray a);
|
||||||
|
String PathFromString(Arena *arena, String str, u8 path_delimiter);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Trimming helpers
|
//~ Trimming helpers
|
||||||
|
|||||||
@ -189,6 +189,11 @@ void SleepSeconds(f64 seconds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String GetAppDirectory(void)
|
||||||
|
{
|
||||||
|
return W32.appdir_path;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookimpl Swap
|
//~ @hookimpl Swap
|
||||||
|
|
||||||
@ -206,7 +211,7 @@ String SwappedStateFromName(Arena *arena, String name)
|
|||||||
{
|
{
|
||||||
TempArena scratch = BeginScratch(arena);
|
TempArena scratch = BeginScratch(arena);
|
||||||
String result = Zi;
|
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);
|
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);
|
HANDLE handle = CreateFileW(path_wstr, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
if (handle != INVALID_HANDLE_VALUE)
|
if (handle != INVALID_HANDLE_VALUE)
|
||||||
@ -234,11 +239,11 @@ String SwappedStateFromName(Arena *arena, String name)
|
|||||||
void WriteSwappedState(String name, String data)
|
void WriteSwappedState(String name, String data)
|
||||||
{
|
{
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
// TODO: Use directory non-relative to executable
|
String dir_path = PathFromString(scratch.arena, StringF(scratch.arena, "%F/swap", FmtString(GetAppDirectory())), '\\');
|
||||||
CreateDirectoryW(L"ppswap", 0);
|
String path = PathFromString(scratch.arena, StringF(scratch.arena, "%F/%F.swp", FmtString(dir_path), FmtString(name)), '\\');
|
||||||
String result = Zi;
|
wchar_t *dir_path_wstr = WstrFromString(scratch.arena, dir_path);
|
||||||
String path = StringF(scratch.arena, "ppswap/%F.swp", FmtString(name));
|
|
||||||
wchar_t *path_wstr = WstrFromString(scratch.arena, 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);
|
HANDLE handle = CreateFileW(path_wstr, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
|
||||||
if (handle != INVALID_HANDLE_VALUE)
|
if (handle != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
@ -277,16 +282,14 @@ void ExitNow(i32 code)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Log
|
//~ Log
|
||||||
|
|
||||||
void W32_BootstrapLogs(String logfile_path)
|
void W32_BootstrapLogs(void)
|
||||||
{
|
{
|
||||||
|
Arena *perm = PermArena();
|
||||||
W32.logs_arena = AcquireArena(Gibi(64));
|
W32.logs_arena = AcquireArena(Gibi(64));
|
||||||
W32.log_msgs_arena = AcquireArena(Gibi(64));
|
W32.log_msgs_arena = AcquireArena(Gibi(64));
|
||||||
W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent);
|
W32.readable_log_events = ArenaNext(W32.logs_arena, LogEvent);
|
||||||
if (logfile_path.len > 0)
|
String logfile_path = StringF(perm, "%F/log.log", FmtString(GetAppDirectory()));
|
||||||
{
|
wchar_t *path_wstr = WstrFromString(perm, logfile_path);
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
|
||||||
{
|
|
||||||
wchar_t *path_wstr = WstrFromString(scratch.arena, logfile_path);
|
|
||||||
W32.logfile = CreateFileW(
|
W32.logfile = CreateFileW(
|
||||||
path_wstr,
|
path_wstr,
|
||||||
FILE_APPEND_DATA,
|
FILE_APPEND_DATA,
|
||||||
@ -296,10 +299,8 @@ void W32_BootstrapLogs(String logfile_path)
|
|||||||
FILE_ATTRIBUTE_NORMAL,
|
FILE_ATTRIBUTE_NORMAL,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
}
|
|
||||||
EndScratch(scratch);
|
|
||||||
}
|
|
||||||
Atomic32Set(&W32.logs_initialized, 1);
|
Atomic32Set(&W32.logs_initialized, 1);
|
||||||
|
LogInfoF("Log file path: %F", FmtString(logfile_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
void W32_Log(i32 level, String msg)
|
void W32_Log(i32 level, String msg)
|
||||||
@ -443,8 +444,8 @@ i32 W32_Main(void)
|
|||||||
W32_InitCurrentThread(Lit("Main"));
|
W32_InitCurrentThread(Lit("Main"));
|
||||||
|
|
||||||
// Get raw args from command line
|
// Get raw args from command line
|
||||||
{
|
|
||||||
Arena *perm = PermArena();
|
Arena *perm = PermArena();
|
||||||
|
{
|
||||||
StringList args_list = Zi;
|
StringList args_list = Zi;
|
||||||
{
|
{
|
||||||
LPCWSTR cmdline_wstr = GetCommandLineW();
|
LPCWSTR cmdline_wstr = GetCommandLineW();
|
||||||
@ -469,10 +470,78 @@ i32 W32_Main(void)
|
|||||||
// Bootstrap command line
|
// Bootstrap command line
|
||||||
BootstrapCmdline();
|
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
|
// Bootstrap log system
|
||||||
// FIXME: Remove hardcoded log path
|
W32_BootstrapLogs();
|
||||||
W32_BootstrapLogs(Lit("log.log"));
|
|
||||||
LogInfoF("Main thread ID: %F", FmtUint(ThreadId()));
|
LogInfoF("Main thread ID: %F", FmtUint(ThreadId()));
|
||||||
|
if (appdir_error.len > 0)
|
||||||
|
{
|
||||||
|
LogError(appdir_error);
|
||||||
|
}
|
||||||
|
|
||||||
// Bootstrap resource system
|
// Bootstrap resource system
|
||||||
{
|
{
|
||||||
|
|||||||
@ -68,6 +68,7 @@ Struct(W32_Ctx)
|
|||||||
i64 ns_per_qpc;
|
i64 ns_per_qpc;
|
||||||
|
|
||||||
StringList raw_command_line;
|
StringList raw_command_line;
|
||||||
|
String appdir_path;
|
||||||
|
|
||||||
//- Application control flow
|
//- Application control flow
|
||||||
|
|
||||||
@ -107,7 +108,7 @@ BOOL W32_FindEmbeddedRcData(HMODULE module, LPCWSTR type, LPWSTR wstr_entry_name
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Log
|
//~ Log
|
||||||
|
|
||||||
void W32_BootstrapLogs(String logfile_path);
|
void W32_BootstrapLogs();
|
||||||
void W32_Log(i32 level, String msg);
|
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("-DIsUnoptimized=1"));
|
||||||
PushStringToList(perm, &cp.defs, Lit("-DIsTestingEnabled=0"));
|
PushStringToList(perm, &cp.defs, Lit("-DIsTestingEnabled=0"));
|
||||||
PushStringToList(perm, &cp.defs, Lit("-DIsHotSwappingEnabled=1"));
|
PushStringToList(perm, &cp.defs, Lit("-DIsHotSwappingEnabled=1"));
|
||||||
|
PushStringToList(perm, &cp.defs, StringF(perm, "-DDefaultAppName=%F", FmtString(cmdline.leaf_layer_name)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Msvc
|
//- Msvc
|
||||||
@ -1015,7 +1016,7 @@ void BuildEntryPoint(WaveLaneCtx *lane)
|
|||||||
|
|
||||||
if (lane->idx == 0)
|
if (lane->idx == 0)
|
||||||
{
|
{
|
||||||
EchoLine(StringF(perm, "Runtime: %Fs", FmtFloat(SecondsFromNs(TimeNs()))));
|
EchoLine(StringF(perm, "Runtime: %Fs", FmtFloat(SecondsFromNs(TimeNs()), .p = 3)));
|
||||||
ExitNow(GetBuildStatus());
|
ExitNow(GetBuildStatus());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,10 @@
|
|||||||
#define IsHotSwappingEnabled 0
|
#define IsHotSwappingEnabled 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef DefaultAppName
|
||||||
|
#define DefaultAppName meta
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Includes
|
//~ Includes
|
||||||
|
|
||||||
|
|||||||
@ -77,10 +77,8 @@ void PLT_Bootstrap(void);
|
|||||||
// NOTE: File paths use forward slash '/' as delimiter
|
// NOTE: File paths use forward slash '/' as delimiter
|
||||||
|
|
||||||
//- File system helpers
|
//- File system helpers
|
||||||
String PLT_GetWritePath(Arena *arena);
|
|
||||||
b32 PLT_IsFile(String path);
|
b32 PLT_IsFile(String path);
|
||||||
b32 PLT_IsDir(String path);
|
b32 PLT_IsDir(String path);
|
||||||
void PLT_MkDir(String path);
|
|
||||||
|
|
||||||
//- File creation
|
//- File creation
|
||||||
PLT_File PLT_OpenFileRead(String path);
|
PLT_File PLT_OpenFileRead(String path);
|
||||||
|
|||||||
@ -212,25 +212,6 @@ void PLT_W32_SyncTimerForever(WaveLaneCtx *lane)
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ @hookimpl File system
|
//~ @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)
|
b32 PLT_IsFile(String path)
|
||||||
{
|
{
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
@ -249,47 +230,16 @@ b32 PLT_IsDir(String path)
|
|||||||
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY);
|
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PLT_MkDir(String path)
|
b32 PLT_MkDir(String path)
|
||||||
{
|
{
|
||||||
TempArena scratch = BeginScratchNoConflict();
|
TempArena scratch = BeginScratchNoConflict();
|
||||||
|
i32 err = 0;
|
||||||
|
{
|
||||||
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
wchar_t *path_wstr = WstrFromString(scratch.arena, path);
|
||||||
int err_code = SHCreateDirectory(0, path_wstr);
|
err = 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);
|
|
||||||
}
|
}
|
||||||
EndScratch(scratch);
|
EndScratch(scratch);
|
||||||
|
return err == ERROR_SUCCESS || err == ERROR_ALREADY_EXISTS || err == ERROR_FILE_EXISTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
PLT_File PLT_OpenFileRead(String path)
|
PLT_File PLT_OpenFileRead(String path)
|
||||||
|
|||||||
@ -2,7 +2,6 @@ S_Ctx S = Zi;
|
|||||||
ThreadLocal S_ThreadLocalCtx S_tl = Zi;
|
ThreadLocal S_ThreadLocalCtx S_tl = Zi;
|
||||||
|
|
||||||
Readonly S_Ent S_NilEnt = {
|
Readonly S_Ent S_NilEnt = {
|
||||||
.last_xf = CompXformIdentity,
|
|
||||||
.xf = CompXformIdentity,
|
.xf = CompXformIdentity,
|
||||||
.look = { 0, -1 },
|
.look = { 0, -1 },
|
||||||
};
|
};
|
||||||
@ -220,6 +219,30 @@ Rng2 S_BoundingBoxFromShape(S_Shape shape)
|
|||||||
return result;
|
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
|
//~ Collision
|
||||||
|
|
||||||
@ -1254,7 +1277,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
String packed = Zi;
|
String packed = Zi;
|
||||||
if (swapin)
|
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);
|
S_UnpackedWorld unpacked = S_UnpackWorld(frame_arena, packed);
|
||||||
|
|
||||||
@ -1263,6 +1286,10 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
world->seed = unpacked.seed;
|
world->seed = unpacked.seed;
|
||||||
world->tick = unpacked.tick;
|
world->tick = unpacked.tick;
|
||||||
world->time_ns = unpacked.time_ns;
|
world->time_ns = unpacked.time_ns;
|
||||||
|
if (world->seed == 0)
|
||||||
|
{
|
||||||
|
TrueRand(StringFromStruct(&world->seed));
|
||||||
|
}
|
||||||
|
|
||||||
world->ent_bins_count = Kibi(16);
|
world->ent_bins_count = Kibi(16);
|
||||||
world->ent_bins = PushStructs(world_arena, S_EntBin, world->ent_bins_count);
|
world->ent_bins = PushStructs(world_arena, S_EntBin, world->ent_bins_count);
|
||||||
@ -1279,7 +1306,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
if (swapout)
|
if (swapout)
|
||||||
{
|
{
|
||||||
String packed = S_PackWorld(frame_arena, world);
|
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
|
//- 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 = 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);
|
Vec2 pos_diff = SubVec2(desired_xf.og, xf.og);
|
||||||
f32 angle_diff = UnwindAngleF32(RotationFromXform(desired_xf) - RotationFromXform(xf));
|
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);
|
// Xform last_xf = ent->last_xf;
|
||||||
// S_TileKind tile = S_TileFromPos(tile_pos);
|
// 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
|
//- Solve constraints
|
||||||
@ -1643,8 +1682,7 @@ void S_TickForever(WaveLaneCtx *lane)
|
|||||||
i64 tick_bullets_count = bullets_per_fire;
|
i64 tick_bullets_count = bullets_per_fire;
|
||||||
if (tick_bullets_count > 0)
|
if (tick_bullets_count > 0)
|
||||||
{
|
{
|
||||||
Xform firer_xf = firer->xf;
|
S_Shape firer_world_shape = S_WorldShapeFromEnt(firer);
|
||||||
S_Shape firer_world_shape = S_MulXformShape(firer_xf, firer->local_shape);
|
|
||||||
|
|
||||||
Vec2 pos = S_EdgePointFromShape(firer_world_shape, firer->look);
|
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))
|
if (victim->is_player && !S_MatchKey(victim->key, bullet->bullet_firer))
|
||||||
{
|
{
|
||||||
Xform victim_xf = victim->xf;
|
S_Shape victim_world_shape = S_WorldShapeFromEnt(victim);
|
||||||
S_Shape victim_world_shape = S_MulXformShape(victim_xf, victim->local_shape);
|
|
||||||
|
|
||||||
S_RaycastResult entrance_raycast = S_RaycastShape(victim_world_shape, ray_start, ray_dir);
|
S_RaycastResult entrance_raycast = S_RaycastShape(victim_world_shape, ray_start, ray_dir);
|
||||||
Vec2 entrance = entrance_raycast.p;
|
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))
|
for (S_Ent *ent = S_FirstEnt(world); ent->valid; ent = S_NextEnt(ent))
|
||||||
{
|
{
|
||||||
Xform xf = ent->xf;
|
S_Shape world_shape = S_WorldShapeFromEnt(ent);
|
||||||
S_Shape world_shape = S_MulXformShape(xf, ent->local_shape);
|
|
||||||
|
|
||||||
// Draw aabb
|
// Draw aabb
|
||||||
{
|
{
|
||||||
|
|||||||
@ -62,12 +62,8 @@ Struct(S_Ent)
|
|||||||
b32 is_player;
|
b32 is_player;
|
||||||
f32 health;
|
f32 health;
|
||||||
|
|
||||||
Xform last_xf;
|
|
||||||
Xform xf;
|
Xform xf;
|
||||||
|
|
||||||
S_Shape local_shape;
|
|
||||||
|
|
||||||
f32 move_speed;
|
|
||||||
Vec2 move;
|
Vec2 move;
|
||||||
Vec2 look;
|
Vec2 look;
|
||||||
f32 fire_held;
|
f32 fire_held;
|
||||||
@ -245,6 +241,7 @@ Struct(S_SnapshotNode)
|
|||||||
Enum(S_CmdKind)
|
Enum(S_CmdKind)
|
||||||
{
|
{
|
||||||
S_CmdKind_Nop,
|
S_CmdKind_Nop,
|
||||||
|
S_CmdKind_Save,
|
||||||
S_CmdKind_Delta,
|
S_CmdKind_Delta,
|
||||||
S_CmdKind_Control,
|
S_CmdKind_Control,
|
||||||
};
|
};
|
||||||
@ -394,6 +391,9 @@ S_Shape S_ShapeFromDescEx(S_ShapeDesc desc);
|
|||||||
S_Shape S_MulXformShape(Xform xf, S_Shape shape);
|
S_Shape S_MulXformShape(Xform xf, S_Shape shape);
|
||||||
Rng2 S_BoundingBoxFromShape(S_Shape shape);
|
Rng2 S_BoundingBoxFromShape(S_Shape shape);
|
||||||
|
|
||||||
|
S_Shape S_LocalShapeFromEnt(S_Ent *ent);
|
||||||
|
S_Shape S_WorldShapeFromEnt(S_Ent *ent);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Collision
|
//~ Collision
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Tile types
|
//~ Tile types
|
||||||
|
|
||||||
#define S_WorldPitch 80.0
|
#define S_WorldPitch 60.0
|
||||||
#define S_TilesPitch (S_WorldPitch * 2)
|
#define S_TilesPitch (S_WorldPitch * 2)
|
||||||
#define S_TilesCount (S_TilesPitch * S_TilesPitch)
|
#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, "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
|
// Pack entities
|
||||||
// FIXME: Precision
|
// FIXME: Precision
|
||||||
result.len += PushString(arena, Lit("\nentities:\n")).len;
|
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 += StringF(arena, " 0x%F:\n", FmtHex(ent->key.v)).len;
|
||||||
result.len += PushString(arena, Lit(" {\n")).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, " pos: \"%F\"\n", FmtFloat2(ent->xf.og)).len;
|
||||||
result.len += StringF(arena, " rot: \"%F\"\n", FmtFloat2(RightFromXform(ent->xf))).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, " exists: \"%F\"\n", FmtFloat(ent->exists)).len;
|
||||||
result.len += StringF(arena, " look: \"%F\"\n", FmtFloat2(ent->look)).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;
|
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);
|
CR_Item *root = CR_ItemFromString(scratch.arena, packed);
|
||||||
|
|
||||||
// Get version
|
// Unpack version
|
||||||
S_Tv version = 0;
|
S_Tv version = 0;
|
||||||
for (CR_Item *root_item = root->first; root_item; root_item = root_item->next)
|
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)
|
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")))
|
if (MatchString(top_item->name, Lit("entities")))
|
||||||
{
|
{
|
||||||
for (CR_Item *ent_item = top_item->first; ent_item; ent_item = ent_item->next)
|
for (CR_Item *ent_item = top_item->first; ent_item; ent_item = ent_item->next)
|
||||||
{
|
{
|
||||||
S_Ent *ent = S_PushTempEnt(arena, &result.ents);
|
S_Ent *ent = S_PushTempEnt(arena, &result.ents);
|
||||||
ent->key = (S_Key) { .v = CR_IntFromString(ent_item->name) };
|
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);
|
for (CR_Item *prop = attr->first; prop; prop = prop->next)
|
||||||
ent->xf.og = pos;
|
|
||||||
}
|
|
||||||
if (MatchString(prop->name, Lit("rot")))
|
|
||||||
{
|
{
|
||||||
Vec2 rot = CR_Vec2FromString(prop->value);
|
if (MatchString(prop->value, Lit("player")))
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
ent->is_player = 1;
|
ent->is_player = 1;
|
||||||
ent->has_weapon = 1;
|
ent->has_weapon = 1;
|
||||||
}
|
}
|
||||||
// if (MatchString(prop->name, Lit("bullet")) && CR_BoolFromString(prop->value))
|
if (MatchString(prop->value, Lit("bullet")))
|
||||||
// {
|
{
|
||||||
// ent->is_bullet = 1;
|
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);
|
EndScratch(scratch);
|
||||||
return result;
|
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.icon_font = UI_BuiltinIconFont();
|
||||||
|
|
||||||
// theme.font_size = 14;
|
// 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.h1 = 2.00;
|
||||||
theme.h2 = 1.50;
|
theme.h2 = 1.50;
|
||||||
theme.h3 = 1.25;
|
theme.h3 = 1.25;
|
||||||
@ -558,7 +558,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
}
|
}
|
||||||
else
|
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);
|
bb = BB_BuffFromString(swap_encoded);
|
||||||
br = BB_ReaderFromBuff(&bb);
|
br = BB_ReaderFromBuff(&bb);
|
||||||
}
|
}
|
||||||
@ -586,7 +586,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
// Write swapout
|
// Write swapout
|
||||||
if (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.y = 0.25;
|
||||||
look_ratio.x = look_ratio.y / (16.0 / 9.0);
|
look_ratio.x = look_ratio.y / (16.0 / 9.0);
|
||||||
S_Ent *player = S_EntFromKey(world, V.player_key);
|
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_pos = AddVec2(target_camera_pos, MulVec2Vec2(player->look, look_ratio));
|
||||||
target_camera_zoom = 1;
|
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 });
|
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))
|
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;
|
b32 is_hovered = S_CollisionResultFromShapes(ent_shape, cursor_shape).collision_points_count > 0;
|
||||||
if (is_hovered)
|
if (is_hovered)
|
||||||
{
|
{
|
||||||
@ -2379,9 +2379,8 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
UI_Push(BackgroundColor, color);
|
UI_Push(BackgroundColor, color);
|
||||||
UI_Push(Width, UI_GROW(1, 0));
|
UI_Push(Width, UI_GROW(1, 0));
|
||||||
UI_Push(Height, UI_FNT(1.5, 1));
|
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(Rounding, UI_RPIX(0));
|
||||||
UI_Push(BorderSize, 1);
|
UI_Push(BorderSize, 0);
|
||||||
UI_Push(ChildAlignment, UI_Region_Left);
|
UI_Push(ChildAlignment, UI_Region_Left);
|
||||||
UI_PushCP(UI_BuildRow());
|
UI_PushCP(UI_BuildRow());
|
||||||
{
|
{
|
||||||
@ -2517,13 +2516,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
*ent = S_NilEnt;
|
*ent = S_NilEnt;
|
||||||
ent->key = V.player_key;
|
ent->key = V.player_key;
|
||||||
ent->xf = XformFromPos(player_pos);
|
ent->xf = XformFromPos(player_pos);
|
||||||
ent->move_speed = 0.075;
|
|
||||||
ent->is_player = 1;
|
ent->is_player = 1;
|
||||||
ent->local_shape = S_ShapeFromDesc(
|
|
||||||
.mass = 10,
|
|
||||||
.count = 1,
|
|
||||||
.radius = 0.3,
|
|
||||||
);
|
|
||||||
ent->has_weapon = 1;
|
ent->has_weapon = 1;
|
||||||
ent->exists = 1;
|
ent->exists = 1;
|
||||||
}
|
}
|
||||||
@ -2537,13 +2530,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
*ent = S_NilEnt;
|
*ent = S_NilEnt;
|
||||||
ent->key = S_RandKey();
|
ent->key = S_RandKey();
|
||||||
ent->xf = XformFromPos(frame->world_cursor);
|
ent->xf = XformFromPos(frame->world_cursor);
|
||||||
ent->move_speed = 0.075;
|
|
||||||
ent->is_player = 1;
|
ent->is_player = 1;
|
||||||
ent->local_shape = S_ShapeFromDesc(
|
|
||||||
.mass = 10,
|
|
||||||
.count = 1,
|
|
||||||
.radius = 0.3,
|
|
||||||
);
|
|
||||||
ent->has_weapon = 1;
|
ent->has_weapon = 1;
|
||||||
ent->exists = 1;
|
ent->exists = 1;
|
||||||
} break;
|
} break;
|
||||||
@ -2560,6 +2547,14 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case V_CmdKind_save_level:
|
||||||
|
{
|
||||||
|
if (frame->is_editing)
|
||||||
|
{
|
||||||
|
S_Cmd *cmd = V_PushSimCmd(S_CmdKind_Save);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
case V_CmdKind_clear_particles:
|
case V_CmdKind_clear_particles:
|
||||||
{
|
{
|
||||||
should_clear_particles = 1;
|
should_clear_particles = 1;
|
||||||
@ -2582,7 +2577,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
f32 fire_presses = fire_held && !last_frame->held_buttons[Button_M1];
|
f32 fire_presses = fire_held && !last_frame->held_buttons[Button_M1];
|
||||||
Vec2 look = Zi;
|
Vec2 look = Zi;
|
||||||
{
|
{
|
||||||
Vec2 center = MulXformV2(player->xf, player->local_shape.centroid);
|
Vec2 center = S_WorldShapeFromEnt(player).centroid;
|
||||||
look = SubVec2(frame->world_cursor, center);
|
look = SubVec2(frame->world_cursor, center);
|
||||||
}
|
}
|
||||||
if (frame->is_editing)
|
if (frame->is_editing)
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
X(zoom_in, Zoom In, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelUp ), ) \
|
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(zoom_out, Zoom Out, V_CmdDescFlag_HideFromPalette, V_HOTKEY( Button_MWheelDown ), ) \
|
||||||
X(toggle_editor, Toggle Editor, V_CmdDescFlag_None, V_HOTKEY( Button_F1 ), ) \
|
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_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_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 ) ) \
|
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, Spawn/Teleport Player, V_CmdDescFlag_None, V_HOTKEY( Button_Q ), ) \
|
||||||
X(spawn_dummy, Spawn Dummy, V_CmdDescFlag_None, V_HOTKEY( Button_T ), ) \
|
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(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 ), ) \
|
X(clear_particles, Clear particles, V_CmdDescFlag_None, V_HOTKEY( Button_C ), ) \
|
||||||
/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user