diff --git a/Game/Data/World.cpp b/Game/Data/World.cpp index 689a333..0c57179 100644 --- a/Game/Data/World.cpp +++ b/Game/Data/World.cpp @@ -233,7 +233,7 @@ void RenderWorldEditorUI(World& world) if (ImGui::Begin("World Editor")) { TempArena temp = scratch_begin(nullptr, 0); - static char worldFilePath[256] = "../world.bin"; + static char worldFilePath[256] = "/world.bin"; ImGui::InputText("World File", worldFilePath, sizeof(worldFilePath)); String path = GetAssetPath(temp.Arena, AssetType::JAsset, ConstString(worldFilePath)); diff --git a/Juliet/include/Core/HAL/Filesystem/Filesystem.h b/Juliet/include/Core/HAL/Filesystem/Filesystem.h index c71f33b..445c38c 100644 --- a/Juliet/include/Core/HAL/Filesystem/Filesystem.h +++ b/Juliet/include/Core/HAL/Filesystem/Filesystem.h @@ -5,16 +5,19 @@ enum class AssetType { JAsset, - Shader + Shader, + Config, }; // Returns the path to the application directory -extern JULIET_API String GetBasePath(); +JULIET_API String GetBasePath(); // Path to the /Assets/ folder -extern JULIET_API String GetAssetBasePath(); +JULIET_API String GetAssetBasePath(); // Builds a full path to an asset file given its filename (e.g. "Triangle.vert.dxil"). -extern JULIET_API String GetAssetPath(NonNullPtr arena, AssetType type, String filename); +JULIET_API String GetAssetPath(NonNullPtr arena, AssetType type, String filename); -extern JULIET_API bool IsAbsolutePath(String path); +JULIET_API bool IsAbsolutePath(String path); + +JULIET_API String CleanPath(NonNullPtr arena, String path); diff --git a/Juliet/include/Core/HAL/OS/OS.h b/Juliet/include/Core/HAL/OS/OS.h index 6bc53a2..b0da8f8 100644 --- a/Juliet/include/Core/HAL/OS/OS.h +++ b/Juliet/include/Core/HAL/OS/OS.h @@ -1,5 +1,9 @@ #pragma once +#include +#include +#include + namespace Memory { Byte* OS_Reserve(size_t size); @@ -39,5 +43,10 @@ namespace Debug JULIET_API bool IsDebuggerPresent(); } // namespace Debug +String os_get_env_var(NonNullPtr arena, const String& name); +void os_set_env_var(const String& name, const String& value); + +String os_get_username(NonNullPtr arena); + using EntryPointFunc = int (*)(int, wchar_t**); JULIET_API int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv); diff --git a/Juliet/include/Engine/user.h b/Juliet/include/Engine/user.h new file mode 100644 index 0000000..e0944b6 --- /dev/null +++ b/Juliet/include/Engine/user.h @@ -0,0 +1,8 @@ +#pragma once + +using UserID = uint8; + +void initialize_user_system(); +void shutdown_user_system(); + +uint8 get_local_user_id(); diff --git a/Juliet/src/Core/HAL/Filesystem/Filesystem.cpp b/Juliet/src/Core/HAL/Filesystem/Filesystem.cpp index c84f216..dc1af03 100644 --- a/Juliet/src/Core/HAL/Filesystem/Filesystem.cpp +++ b/Juliet/src/Core/HAL/Filesystem/Filesystem.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace { @@ -36,13 +37,14 @@ String GetAssetBasePath() String GetAssetPath(NonNullPtr arena, AssetType type, String filename) { + Assert(IsValid(filename)); + String asset_path = {}; switch (type) { case AssetType::Shader: { Assert(IsValid(CachedShaderBasePath)); - Assert(IsValid(filename)); size_t totalSize = CachedShaderBasePath.Size + filename.Size + 1; char* buffer = ArenaPushArray(arena, totalSize); @@ -52,9 +54,31 @@ String GetAssetPath(NonNullPtr arena, AssetType type, String filename) asset_path = { buffer, totalSize - 1 }; } break; + case AssetType::Config: + { + Assert(IsValid(CachedAssetBasePath)); + + constexpr const char* kConfig_str = "config/"; + constexpr size_t kConfig_size = sizeof(kConfig_str) - 1; + + size_t totalSize = CachedAssetBasePath.Size + kConfig_size + filename.Size + 1; + char* buffer = ArenaPushArray(arena, totalSize); + Assert(buffer); + + juliet_snprintf(buffer, totalSize, "%s%s%s", CStr(CachedAssetBasePath), kConfig_str, CStr(filename)); + asset_path = { buffer, totalSize - 1 }; + } + break; default: { - asset_path = GetAssetBasePath(); + Assert(IsValid(CachedAssetBasePath)); + + size_t totalSize = CachedAssetBasePath.Size + filename.Size + 1; + char* buffer = ArenaPushArray(arena, totalSize); + Assert(buffer); + + juliet_snprintf(buffer, totalSize, "%s%s", CStr(CachedAssetBasePath), CStr(filename)); + asset_path = { buffer, totalSize - 1 }; } break; } @@ -71,6 +95,11 @@ bool IsAbsolutePath(String path) return Platform::IsAbsolutePath(path); } +String CleanPath(NonNullPtr arena, String path) +{ + return Platform::CleanPath(arena, path); +} + void InitFilesystem(NonNullPtr arena) { CachedBasePath = Platform::GetBasePath(arena); @@ -90,13 +119,10 @@ void InitFilesystem(NonNullPtr arena) if (DirectoryExists(probePath)) { - size_t len = strlen(probePath); - if (char* buffer = ArenaPushArray(arena, len + 1 JULIET_DEBUG_PARAM("CachedAssetBasePath"))) - { - juliet_snprintf(buffer, len + 1, "%s", probePath); - CachedAssetBasePath = { buffer, len }; - Log(LogLevel::Message, LogCategory::Core, "Asset base path: %s", buffer); - } + // Clean the path first to remove any relative parts + String abs_path = CleanPath(arena, WrapString(probePath)); + CachedAssetBasePath = abs_path; + Log(LogLevel::Message, LogCategory::Core, "Asset base path: %s", CStr(abs_path)); break; } } @@ -113,18 +139,13 @@ void InitFilesystem(NonNullPtr arena) if (DirectoryExists(probePath)) { - size_t len = strlen(probePath); - if (char* buffer = ArenaPushArray(arena, len + 1 JULIET_DEBUG_PARAM("CachedShaderBasePath"))) - { - juliet_snprintf(buffer, len + 1, "%s", probePath); - CachedShaderBasePath = { buffer, len }; - Log(LogLevel::Message, LogCategory::Core, "Shader base path: %s", buffer); - } - return; + // Clean the path first to remove any relative parts + String abs_path = CleanPath(arena, WrapString(probePath)); + CachedShaderBasePath = abs_path; + Log(LogLevel::Message, LogCategory::Core, "Asset base path: %s", CStr(abs_path)); + break; } } - - Log(LogLevel::Error, LogCategory::Core, "Filesystem: Could not find Assets/compiled/ directory!"); } void ShutdownFilesystem() diff --git a/Juliet/src/Core/HAL/Filesystem/Filesystem_Platform.h b/Juliet/src/Core/HAL/Filesystem/Filesystem_Platform.h index a5ccb47..1af6ada 100644 --- a/Juliet/src/Core/HAL/Filesystem/Filesystem_Platform.h +++ b/Juliet/src/Core/HAL/Filesystem/Filesystem_Platform.h @@ -2,6 +2,7 @@ namespace Platform { - extern String GetBasePath(NonNullPtr arena); - extern bool IsAbsolutePath(String path); + String GetBasePath(NonNullPtr arena); + bool IsAbsolutePath(String path); + String CleanPath(NonNullPtr arena, String path); } // namespace Platform diff --git a/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp b/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp index 8416103..72ec360 100644 --- a/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp +++ b/Juliet/src/Core/HAL/Filesystem/Win32/Win32Filesystem.cpp @@ -91,4 +91,17 @@ namespace Platform return false; } + + String CleanPath(NonNullPtr arena, String path) + { + char clean_path_buffer[MAX_PATH]; + LPSTR file_part = nullptr; + DWORD result = GetFullPathNameA(CStr(path), MAX_PATH, clean_path_buffer, &file_part); + if (result == 0) + { + LogError(LogCategory::Core, "Failed to resolve path. Error: %lu\n", GetLastError()); + } + + return StringCopy(arena, WrapString(clean_path_buffer)); + } } // namespace Platform diff --git a/Juliet/src/Core/HAL/OS/OS.cpp b/Juliet/src/Core/HAL/OS/OS.cpp index cbf2c42..f7c1573 100644 --- a/Juliet/src/Core/HAL/OS/OS.cpp +++ b/Juliet/src/Core/HAL/OS/OS.cpp @@ -1,6 +1,8 @@ #include #include +#include #include +#include namespace Memory { @@ -58,9 +60,24 @@ namespace Debug } } // namespace Debug +String os_get_env_var(NonNullPtr arena, const String& name) +{ + String result = Internal::os_get_env_var(arena, name); + return result; +} + +void os_set_env_var(const String& name, const String& value) +{ + Internal::os_set_env_var(name, value); +} + +String os_get_username(NonNullPtr arena) +{ + return Internal::os_get_username(arena); +} + int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv) { - int result = Internal::OS_Main(argc, argv); if (result == 0) { @@ -73,4 +90,3 @@ int Bootstrap(EntryPointFunc entryPointFunc, int argc, wchar_t** argv) return result; } - diff --git a/Juliet/src/Core/HAL/OS/OS_Private.h b/Juliet/src/Core/HAL/OS/OS_Private.h index a4f0586..37e785e 100644 --- a/Juliet/src/Core/HAL/OS/OS_Private.h +++ b/Juliet/src/Core/HAL/OS/OS_Private.h @@ -20,6 +20,11 @@ namespace Time::Internal namespace Internal { + String os_get_env_var(NonNullPtr arena, const String& name); + void os_set_env_var(const String& name, const String& value); + + String os_get_username(NonNullPtr arena); + int OS_Main(int argc, wchar_t** argv); void OS_Main_Exit(); } // namespace Internal diff --git a/Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp b/Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp index ac2f916..655324e 100644 --- a/Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp +++ b/Juliet/src/Core/HAL/OS/Win32/Win32OS.cpp @@ -100,6 +100,36 @@ namespace Internal { thread_local thread_context* mainThread = nullptr; + String os_get_env_var(NonNullPtr arena, const String& name) + { + char buffer[256]; + String result = {}; + + if (GetEnvironmentVariableA(CStr(name), buffer, sizeof(buffer)) != 0) + { + result = StringCopy(arena, WrapString(buffer)); + } + + return result; + } + + void os_set_env_var(const String& name, const String& value) + { + SetEnvironmentVariableA(CStr(name), CStr(value)); + } + + String os_get_username(NonNullPtr arena) + { + char username[256]; + DWORD usernameLength = sizeof(username); + String result = {}; + if (GetUserNameA(username, &usernameLength) && usernameLength > 1) + { + result = StringCopy(arena, { username, usernameLength }); + } + return result; + } + int OS_Main([[maybe_unused]] int argc, [[maybe_unused]] wchar_t** argv) { SetUnhandledExceptionFilter(&ExceptionFilter); diff --git a/Juliet/src/Engine/Engine.cpp b/Juliet/src/Engine/Engine.cpp index 4ef7756..de997df 100644 --- a/Juliet/src/Engine/Engine.cpp +++ b/Juliet/src/Engine/Engine.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -159,6 +160,8 @@ void InitializeEngine(JulietInit_Flags flags) InitFilesystem(EngineInstance.PlatformArena); + initialize_user_system(); + JulietInit(flags); } diff --git a/Juliet/src/Engine/user.cpp b/Juliet/src/Engine/user.cpp new file mode 100644 index 0000000..ebace17 --- /dev/null +++ b/Juliet/src/Engine/user.cpp @@ -0,0 +1,48 @@ +#include + +#include +#include +#include +#include +#include +#include +#include + +void initialize_user_system() +{ + // Project needs a user.ini file with all users + // When starting if none exists -> create it + // User name is basically found in a env variable, if not, the local windows user will be used. + TempArena temp = scratch_begin(nullptr, 0); + + String user_system_path = GetAssetPath(temp.Arena, AssetType::Config, ConstString("users.ini")); + ByteBuffer user_file = LoadFile(temp.Arena, user_system_path); + + String username = os_get_username(temp.Arena); + + if (user_file.Size == 0) + { + IOStream* stream = IOFromFile(temp.Arena, user_system_path, ConstString("w+")); + Archive ar = { .arena = temp.Arena, .loading = false, .stream = stream }; + + uint8 id = 1; + serialize(ar, username, crc32(username), id); + + IOClose(stream); + } + else + { + ParsedArchive parsed_archive = tokenize_archive(temp.Arena, user_file); + + Archive ar = { .arena = temp.Arena, .loading = true, .base = parsed_archive }; + } + + scratch_end(temp); +} + +void shutdown_user_system() {} + +uint8 get_local_user_id() +{ + return 0u; +} diff --git a/Juliet/src/UnitTest/RunUnitTests.cpp b/Juliet/src/UnitTest/RunUnitTests.cpp index 2eee895..1d501c1 100644 --- a/Juliet/src/UnitTest/RunUnitTests.cpp +++ b/Juliet/src/UnitTest/RunUnitTests.cpp @@ -11,11 +11,13 @@ namespace UnitTest void VectorUnitTest(); void TestMemoryArena(); void SerializationUnitTest(); + void os_unit_test(); void RunUnitTests() { LogMessage(LogCategory::Core, "Starting Unit Tests..."); + os_unit_test(); TestMemoryArena(); VectorUnitTest(); SerializationUnitTest(); diff --git a/Juliet/src/UnitTest/os_test.cpp b/Juliet/src/UnitTest/os_test.cpp new file mode 100644 index 0000000..09654c8 --- /dev/null +++ b/Juliet/src/UnitTest/os_test.cpp @@ -0,0 +1,51 @@ +#if JULIET_DEBUG + +#include +#include +#include +#include + +namespace UnitTest +{ + void os_unit_test() + { + LogMessage(LogCategory::Core, "=== Running OS Unit Tests (Juliet) ==="); + + TempArena scratch = scratch_begin(nullptr, 0); + String username = os_get_username(scratch.Arena); + + Assert(IsValid(username)); + + String env = os_get_env_var(scratch.Arena, ConstString("JULIET_UNIT_TEST")); + + os_set_env_var(ConstString("JULIET_UNIT_TEST"), username); + + String env2 = os_get_env_var(scratch.Arena, ConstString("JULIET_UNIT_TEST")); + + os_set_env_var(ConstString("JULIET_UNIT_TEST"), env); + + Assert(StringCompare(env, env2) != 0); + + // String os_get_env_var(NonNullPtr arena, const String& name) + // { + // String result = Internal::os_get_env_var(arena, name); + // return result; + // } + // + // void os_set_env_var(const String& name, const String& value) + // { + // Internal::os_set_env_var(name, value); + // } + // + // String os_get_username(NonNullPtr arena) + // { + // Internal::os_get_username(arena); + // } + // + + scratch_end(scratch); + LogMessage(LogCategory::Core, "=== All OS Unit Tests Passed Successfully ==="); + } +} // namespace UnitTest + +#endif diff --git a/misc/build.bat b/misc/build.bat index 4cf4ac4..71ffe50 100644 --- a/misc/build.bat +++ b/misc/build.bat @@ -175,7 +175,7 @@ if /i "!CFG!"=="Debug" ( set IMGUI_UNITY_SRCS= ) -set COMMON_LIBS=kernel32.lib user32.lib gdi32.lib dxguid.lib Ws2_32.lib dxgi.lib imm32.lib dwmapi.lib d3dcompiler.lib dxcompiler.lib shell32.lib winhttp.lib delayimp.lib +set COMMON_LIBS=kernel32.lib user32.lib Advapi32.lib gdi32.lib dxguid.lib Ws2_32.lib dxgi.lib imm32.lib dwmapi.lib d3dcompiler.lib dxcompiler.lib shell32.lib winhttp.lib delayimp.lib if defined IMGUI_UNITY_SRCS ( echo STEP Compiling ImGui Shared Objs [!CFG!]>>"!PLAN_FILE!"