Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD

# Post-build: Create distribution folder structure
set(DIST_ROOT "${CMAKE_SOURCE_DIR}/dist")
set(DIST_VERSION_DIR "${DIST_ROOT}/PrismaUI_${PROJECT_VERSION}")
set(DIST_VERSION_DIR "${DIST_ROOT}/PrismaUI_${PROJECT_VERSION}$<$<CONFIG:Debug>:_Debug>")
set(DIST_PRISMAUI_DIR "${DIST_VERSION_DIR}/PrismaUI")
set(DIST_SKSE_PLUGINS_DIR "${DIST_VERSION_DIR}/SKSE/plugins")

Expand All @@ -139,6 +139,6 @@ add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
"$<$<BOOL:$<TARGET_PDB_FILE:${PROJECT_NAME}>>:$<TARGET_PDB_FILE:${PROJECT_NAME}>>"
"${DIST_SKSE_PLUGINS_DIR}/"

COMMAND "${CMAKE_COMMAND}" -E echo "Creating distribution folder: dist/PrismaUI_${PROJECT_VERSION}"
COMMAND "${CMAKE_COMMAND}" -E echo "Creating distribution folder: ${DIST_VERSION_DIR}"
)

10 changes: 2 additions & 8 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,8 @@
"VCPKG_TARGET_TRIPLET": "x64-windows-static",
"VCPKG_INSTALLED_DIR": "${sourceDir}/build/vcpkg_installed",
"VCPKG_INSTALL_OPTIONS": "--no-print-usage",
"CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded$<$<CONFIG:Debug>:Debug>",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",

"CMAKE_CXX_FLAGS": "/permissive- /Zc:preprocessor /MP /W4 /utf-8",
"CMAKE_C_FLAGS_DEBUG": "/DWIN32_LEAN_AND_MEAN /DNOMINMAX /DUNICODE /D_UNICODE",
"CMAKE_CXX_FLAGS_DEBUG": "/DWIN32_LEAN_AND_MEAN /DNOMINMAX /DUNICODE /D_UNICODE",
"CMAKE_C_FLAGS_RELEASE": "/DWIN32_LEAN_AND_MEAN /DNOMINMAX /DUNICODE /D_UNICODE",
"CMAKE_CXX_FLAGS_RELEASE": "/DWIN32_LEAN_AND_MEAN /DNOMINMAX /DUNICODE /D_UNICODE",
"CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded$<$<CONFIG:Debug>:Debug>",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",

"CMAKE_CXX_STANDARD": "23",
"CMAKE_CXX_STANDARD_REQUIRED": "ON",
Expand Down
28 changes: 19 additions & 9 deletions cmake/CompilerFlags.cmake
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
# CompilerFlags.cmake
# Configures compiler-specific flags and optimizations

# Statically link the C runtime (avoids MSVC redistributable DLLs)
if(MSVC)
# Add compilation speed optimizations
# /d2ReducedOptimizeHugeFunctions - Faster optimization for large functions
string(APPEND CMAKE_CXX_FLAGS " /d2ReducedOptimizeHugeFunctions")
# CompilerFlags.cmake
# Configures compiler-specific flags and optimizations

add_compile_definitions(
WIN32_LEAN_AND_MEAN
NOMINMAX
UNICODE
_UNICODE
)

# Statically link the C runtime (avoids MSVC redistributable DLLs)
if(MSVC)
string(REGEX REPLACE "/EH[scra-]*" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(APPEND CMAKE_CXX_FLAGS " /permissive- /Zc:preprocessor /MP /W4 /utf-8")

# Add compilation speed optimizations
# /d2ReducedOptimizeHugeFunctions - Faster optimization for large functions
string(APPEND CMAKE_CXX_FLAGS " /d2ReducedOptimizeHugeFunctions")

# Code generation optimizations
string(APPEND CMAKE_CXX_FLAGS " /Gy") # Function-level linking (enables dead code elimination)
Expand Down Expand Up @@ -58,4 +68,4 @@ if(MSVC)
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF")


endif()
endif()
14 changes: 3 additions & 11 deletions cmake/commonlibsse.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,23 @@
# CommonLibSSE-NG configuration
set(CommonLibPath "external/commonlibsse-ng")
set(CommonLibName "CommonLibSSE")
set(CommonLibBuildDir "${CMAKE_BINARY_DIR}/external_builds/${CommonLibName}")

# Extract version from CommonLibSSE's CMakeLists.txt (project() VERSION doesn't propagate to parent scope)
file(READ "${CMAKE_SOURCE_DIR}/${CommonLibPath}/CMakeLists.txt" _commonlib_cmakelists_content)
string(REGEX MATCH "VERSION[ \t]+([0-9]+\\.[0-9]+\\.[0-9]+)" _ "${_commonlib_cmakelists_content}")
set(COMMONLIBSSE_VERSION "${CMAKE_MATCH_1}" CACHE STRING "CommonLibSSE-NG version" FORCE)
message(STATUS "Configuring CommonLibSSE-NG version ${COMMONLIBSSE_VERSION}")

# Save original build type
set(_saved_build_type "${CMAKE_BUILD_TYPE}")

# Always build CommonLibSSE in Release mode to disable assertions and enable optimizations
set(CMAKE_BUILD_TYPE "Release")
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
add_definitions(-DNDEBUG)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might want to be sure no there are no commonlib asserts that can get hit

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll re-check

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should leave assertions for debug builds. They can point to potential bugs. In release mode they'll be disabled.


# Disable CommonLibSSE tests when building as subdirectory
set(BUILD_TESTS OFF CACHE BOOL "Disable CommonLibSSE tests" FORCE)

# Check if CommonLibSSE has already been built
set(COMMONLIB_STAMP_FILE "${BUILD_ROOT}/external_builds/${CommonLibName}.stamp")
set(COMMONLIB_STAMP_FILE "${CommonLibBuildDir}/${CommonLibName}.stamp")
# Add CommonLibSSE-NG as a subdirectory with EXCLUDE_FROM_ALL
add_subdirectory("${CommonLibPath}" "${BUILD_ROOT}/external_builds/${CommonLibName}" EXCLUDE_FROM_ALL)
add_subdirectory("${CommonLibPath}" "${CommonLibBuildDir}" EXCLUDE_FROM_ALL)

# Create stamp file after configuration (informational only)
if(NOT EXISTS "${COMMONLIB_STAMP_FILE}")
Expand All @@ -34,8 +29,5 @@ endif()
# Include the CommonLibSSE helper cmake functions (provides add_commonlibsse_plugin macro)
include("${CommonLibPath}/cmake/CommonLibSSE.cmake")

# Restore original build type for the main project
set(CMAKE_BUILD_TYPE "${_saved_build_type}")

# Expose CommonLibSSE version to C++ code
add_compile_definitions(COMMONLIBSSE_VERSION="${COMMONLIBSSE_VERSION}")
171 changes: 117 additions & 54 deletions src/API/API.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,53 +5,12 @@

PrismaView PluginAPI::PrismaUIInterface::CreateView(const char* htmlPath, PRISMA_UI_API::OnDomReadyCallback onDomReadyCallback) noexcept
{
if (!htmlPath) {
return 0;
}

std::function<void(PrismaUI::Core::PrismaViewId)> domReadyWrapper = nullptr;
if (onDomReadyCallback) {
domReadyWrapper = [onDomReadyCallback](PrismaUI::Core::PrismaViewId viewId) {
SKSE::GetTaskInterface()->AddTask([callback = onDomReadyCallback, id = viewId]() {
callback(id);
});
};
}

return PrismaUI::ViewManager::Create(htmlPath, domReadyWrapper);
return CreateViewInternal(htmlPath, onDomReadyCallback);
}

void PluginAPI::PrismaUIInterface::Invoke(PrismaView view, const char* script, PRISMA_UI_API::JSCallback callback) noexcept
{
if (!view || !script) {
return;
}

std::string processedScript;

if (isValidUTF8(script)) {
processedScript = script;
}
else {
processedScript = convertFromANSIToUTF8(script);
if (processedScript.empty()) {
return; // Conversion failed, cannot safely invoke
}
}

ultralight::String _script(processedScript.c_str());

std::function<void(std::string)> callbackWrapper = nullptr;

if (callback) {
callbackWrapper = [callback](const std::string& result) {
SKSE::GetTaskInterface()->AddTask([targetCallback = callback, data = result]() {
targetCallback(data.c_str());
});
};
}

return PrismaUI::Communication::Invoke(view, _script, callbackWrapper);
InvokeInternal(view, script, callback);
}

void PluginAPI::PrismaUIInterface::InteropCall(PrismaView view, const char* functionName, const char* argument) noexcept
Expand All @@ -77,17 +36,7 @@ void PluginAPI::PrismaUIInterface::InteropCall(PrismaView view, const char* func

void PluginAPI::PrismaUIInterface::RegisterJSListener(PrismaView view, const char* fnName, PRISMA_UI_API::JSListenerCallback callback) noexcept
{
if (!view || !fnName || !callback) {
return;
}

std::function<void(std::string)> callbackWrapper = [callback](const std::string& arg) {
SKSE::GetTaskInterface()->AddTask([targetCallback = callback, data = arg]() {
targetCallback(data.c_str());
});
};

return PrismaUI::Communication::RegisterJSListener(view, fnName, callbackWrapper);
RegisterJSListenerInternal(view, fnName, callback);
}

bool PluginAPI::PrismaUIInterface::HasFocus(PrismaView view) noexcept
Expand Down Expand Up @@ -240,3 +189,117 @@ void PluginAPI::PrismaUIInterface::RegisterConsoleCallback(PrismaView view, PRIS
PrismaUI::ViewManager::RegisterConsoleCallback(view, nullptr);
}
}

PrismaView PluginAPI::PrismaUIInterface::CreateViewV2(
const char* htmlPath, PRISMA_UI_API::OnDomReadyCallbackWithState onDomReadyCallback, void* callbackState) noexcept
{
auto callback = onDomReadyCallback
? std::function<void(PrismaUI::Core::PrismaViewId)>([onDomReadyCallback, callbackState](auto id) { onDomReadyCallback(id, callbackState); })
: nullptr;

return CreateViewInternal(htmlPath, callback);
}

void PluginAPI::PrismaUIInterface::InvokeV2(PrismaView view, const char* script,
PRISMA_UI_API::JSCallbackWithState callback, void* callbackState) noexcept
{
auto callbackFunc = callback
? std::function<void(const char*)>([callback, callbackState](auto id) { callback(id, callbackState); })
: nullptr;

InvokeInternal(view, script, callbackFunc);
}

void PluginAPI::PrismaUIInterface::RegisterJSListenerV2(PrismaView view, const char* functionName,
PRISMA_UI_API::JSListenerCallbackWithState callback, void* callbackState) noexcept
{
if (!callback) {
return;
}

RegisterJSListenerInternal(view, functionName, [callback, callbackState](auto argument) { callback(argument, callbackState); });
}

void PluginAPI::PrismaUIInterface::RegisterConsoleCallbackV2(
PrismaView view, PRISMA_UI_API::ConsoleMessageCallbackWithState callback, void* callbackState) noexcept
{
if (!view || !callback) {
return;
}

auto wrappedCallback = [callback, callbackState](PrismaUI::Core::PrismaViewId id, PRISMA_UI_API::ConsoleMessageLevel level, const std::string& msg) {
SKSE::GetTaskInterface()->AddTask([callback, id, level, msg, callbackState] {
callback(id, level, msg.c_str(), callbackState);
});
};
PrismaUI::ViewManager::RegisterConsoleCallback(view, wrappedCallback);
}

PrismaView PluginAPI::PrismaUIInterface::CreateViewInternal(
const char* htmlPath, std::function<void(PrismaUI::Core::PrismaViewId)> onDomReadyCallback) noexcept
{
if (!htmlPath) {
return 0;
}

std::move_only_function<void(PrismaUI::Core::PrismaViewId)> domReadyWrapper = nullptr;
if (onDomReadyCallback) {
domReadyWrapper = [callback = std::move(onDomReadyCallback)](PrismaUI::Core::PrismaViewId viewId) {
SKSE::GetTaskInterface()->AddTask([callback = std::move(callback), id = viewId] {
std::invoke(callback, id);
});
};
}

return PrismaUI::ViewManager::Create(htmlPath, std::move(domReadyWrapper));
}

void PluginAPI::PrismaUIInterface::InvokeInternal(PrismaView view, const char* script,
std::function<void(const char*)> callback) noexcept
{
if (!view || !script) {
return;
}

std::string processedScript;

if (isValidUTF8(script)) {
processedScript = script;
}
else {
processedScript = convertFromANSIToUTF8(script);
if (processedScript.empty()) {
return; // Conversion failed, cannot safely invoke
}
}

ultralight::String _script(processedScript.c_str());

std::move_only_function<void(std::string)> callbackWrapper = nullptr;

if (callback) {
callbackWrapper = [callback = std::move(callback)](const std::string& result) {
SKSE::GetTaskInterface()->AddTask([targetCallback = std::move(callback), data = result] {
targetCallback(data.c_str());
});
};
}

return PrismaUI::Communication::Invoke(view, _script, std::move(callbackWrapper));
}

void PluginAPI::PrismaUIInterface::RegisterJSListenerInternal(PrismaView view, const char* functionName,
std::function<void(const char*)> callback) noexcept
{
if (!view || !functionName || !callback) {
return;
}

PrismaUI::Core::SimpleJSCallback callbackWrapper = [callback = std::move(callback)](const std::string& arg) {
SKSE::GetTaskInterface()->AddTask([targetCallback = std::move(callback), data = arg] {
targetCallback(data.c_str());
});
};

return PrismaUI::Communication::RegisterJSListener(view, functionName, callbackWrapper);
}
Loading