From 51a25d3cc7e52b5e1566bb21f1180e51c6440292 Mon Sep 17 00:00:00 2001 From: Eddoursul Date: Fri, 5 Jul 2024 23:09:49 +0200 Subject: [PATCH] Proof of concept --- .clang-format | 101 +++++++ .gitignore | 539 +++++++++++++++++++++++++++++++++++ CMakeLists.txt | 108 +++++++ CMakePresets.json | 252 ++++++++++++++++ cmake/version.rc.in | 34 +++ cmake/x64-windows-skse.cmake | 8 + src/EventListener.cpp | 62 ++++ src/EventListener.h | 37 +++ src/Main.cpp | 62 ++++ src/PCH.h | 19 ++ src/Util.h | 29 ++ vcpkg-configuration.json | 7 + vcpkg.json | 22 ++ 13 files changed, 1280 insertions(+) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 CMakePresets.json create mode 100644 cmake/version.rc.in create mode 100644 cmake/x64-windows-skse.cmake create mode 100644 src/EventListener.cpp create mode 100644 src/EventListener.h create mode 100644 src/Main.cpp create mode 100644 src/PCH.h create mode 100644 src/Util.h create mode 100644 vcpkg-configuration.json create mode 100644 vcpkg.json diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..934e87e --- /dev/null +++ b/.clang-format @@ -0,0 +1,101 @@ +--- +AccessModifierOffset: -4 +AlignAfterOpenBracket: DontAlign +AlignConsecutiveAssignments: 'false' +AlignConsecutiveBitFields: 'false' +AlignConsecutiveDeclarations: 'false' +AlignConsecutiveMacros: 'false' +AlignEscapedNewlines: Left +AlignOperands: Align +AlignTrailingComments: 'true' +AllowAllArgumentsOnNextLine: 'false' +AllowAllConstructorInitializersOnNextLine: 'false' +AllowAllParametersOfDeclarationOnNextLine: 'false' +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: 'false' +AllowShortEnumsOnASingleLine: 'true' +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: 'true' +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: 'true' +AlwaysBreakTemplateDeclarations: 'Yes' +BinPackArguments: 'true' +BinPackParameters: 'true' +BitFieldColonSpacing: After +BraceWrapping: + AfterCaseLabel: 'true' + AfterClass: 'true' + AfterControlStatement: 'false' + AfterEnum: 'true' + AfterFunction: 'true' + AfterNamespace: 'true' + AfterStruct: 'true' + AfterUnion: 'true' + AfterExternBlock: 'true' + BeforeCatch: 'false' + BeforeElse: 'false' + BeforeLambdaBody: 'false' + BeforeWhile: 'false' + IndentBraces: 'false' + SplitEmptyFunction: 'false' + SplitEmptyRecord: 'false' + SplitEmptyNamespace: 'false' +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeTernaryOperators: 'true' +BreakConstructorInitializers: AfterColon +BreakInheritanceList: AfterColon +BreakStringLiterals: 'true' +ColumnLimit: 0 +CompactNamespaces: 'false' +ConstructorInitializerAllOnOneLineOrOnePerLine: 'false' +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: 'false' +DeriveLineEnding: 'true' +DerivePointerAlignment: 'false' +DisableFormat: 'false' +FixNamespaceComments: 'false' +IncludeBlocks: Preserve +IndentCaseBlocks: 'true' +IndentCaseLabels: 'true' +IndentExternBlock: Indent +IndentGotoLabels: 'false' +IndentPPDirectives: AfterHash +IndentWidth: 4 +IndentWrappedFunctionNames: 'true' +KeepEmptyLinesAtTheStartOfBlocks: 'false' +Language: Cpp +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +PointerAlignment: Left +ReflowComments : 'false' +SortIncludes: 'true' +SortUsingDeclarations: 'true' +SpaceAfterCStyleCast: 'false' +SpaceAfterLogicalNot: 'false' +SpaceAfterTemplateKeyword: 'true' +SpaceBeforeAssignmentOperators: 'true' +SpaceBeforeCpp11BracedList: 'false' +SpaceBeforeCtorInitializerColon: 'true' +SpaceBeforeInheritanceColon: 'true' +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: 'true' +SpaceBeforeSquareBrackets: 'false' +SpaceInEmptyBlock: 'false' +SpaceInEmptyParentheses: 'false' +SpacesBeforeTrailingComments: 1 +SpacesInAngles: 'false' +SpacesInCStyleCastParentheses: 'false' +SpacesInConditionalStatement: 'false' +SpacesInContainerLiterals: 'true' +SpacesInParentheses: 'false' +SpacesInSquareBrackets: 'false' +Standard: Latest +TabWidth: 4 +UseCRLF: 'true' +UseTab: AlignWithSpaces + +... diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fddaf08 --- /dev/null +++ b/.gitignore @@ -0,0 +1,539 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/clion,visualstudio,visualstudiocode,cmake +# Edit at https://www.toptal.com/developers/gitignore?templates=clion,visualstudio,visualstudiocode,cmake + +### CLion ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf +.vscode/ + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### CLion Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +### CMake ### +CMakeLists.txt.user +CMakeCache.txt +CMakeFiles +CMakeScripts +Testing +Makefile +cmake_install.cmake +install_manifest.txt +compile_commands.json +CTestTestfile.cmake +_deps + +### CMake Patch ### +# External projects +*-prefix/ + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json + +# Local History for Visual Studio Code +.history/ + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# Support for Project snippet scope +!.vscode/*.code-snippets + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Nuget personal access tokens and Credentials +# nuget.config + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools + +# Local History for Visual Studio Code + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +.idea/ +*.sln.iml + +### VisualStudio Patch ### +# Additional files built by Visual Studio + +# End of https://www.toptal.com/developers/gitignore/api/clion,visualstudio,visualstudiocode,cmake + +build/ + +contrib/Distribution/**/*.dll +contrib/Distribution/**/*.pdb +contrib/Distribution/**/*.pex diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..fc9955b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,108 @@ +cmake_minimum_required(VERSION 3.21) +message("Using toolchain file ${CMAKE_TOOLCHAIN_FILE}.") + +######################################################################################################################## +## Define project +######################################################################################################################## +project( + UnreadBooksGlow + VERSION 1.0.0 + DESCRIPTION "Unread Books Glow NG" + LANGUAGES CXX) +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.rc.in + ${CMAKE_CURRENT_BINARY_DIR}/version.rc + @ONLY) + +#include(GNUInstallDirs) +find_path(SIMPLEINI_INCLUDE_DIRS "ConvertUTF.c") + +file( + GLOB_RECURSE + sources + ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp + ${CMAKE_CURRENT_BINARY_DIR}/version.rc +) + +source_group( + TREE ${CMAKE_CURRENT_SOURCE_DIR} + FILES + ${headers} + ${sources}) + +######################################################################################################################## +## Configure target DLL +######################################################################################################################## + +include(FetchContent) +FetchContent_Declare( + CommonLibNG + GIT_REPOSITORY https://github.com/alandtse/CommonLibVR.git + GIT_TAG 735fa6dae8ec72966ee02673dd689c6516d49f71 +) + +set(ENABLE_SKYRIM_SE ON CACHE BOOL " " FORCE) +set(ENABLE_SKYRIM_AE ON CACHE BOOL " " FORCE) +set(ENABLE_SKYRIM_VR ON CACHE BOOL " " FORCE) +set(BUILD_TESTS OFF CACHE BOOL " " FORCE) + +FetchContent_MakeAvailable(CommonLibNG) + +# Use a local copy instead +#add_subdirectory("d:/Git/CommonLibVR/" ${CMAKE_BINARY_DIR}/_deps/clib-build) + +#find_package(CommonLibSSE CONFIG REQUIRED) + +get_target_property(COMMONLIB_SRC_DIR CommonLibSSE SOURCE_DIR) + +include(${COMMONLIB_SRC_DIR}/cmake/CommonLibSSE.cmake) + +add_commonlibsse_plugin(${PROJECT_NAME} SOURCES ${headers} ${sources}) + +add_library("${PROJECT_NAME}::${PROJECT_NAME}" ALIAS "${PROJECT_NAME}") +target_link_libraries(${PROJECT_NAME} PUBLIC CommonLibSSE::CommonLibSSE) + + +target_include_directories(${PROJECT_NAME} + PRIVATE + $ + $ + $ + ${SIMPLEINI_INCLUDE_DIRS} +) + +target_include_directories(${PROJECT_NAME} + PUBLIC + $) + + +find_package(spdlog CONFIG REQUIRED) + +target_link_libraries( + "${PROJECT_NAME}" + PUBLIC + spdlog::spdlog + Version.lib +) + +target_precompile_headers(${PROJECT_NAME} + PRIVATE + src/PCH.h) + +install(TARGETS ${PROJECT_NAME} + DESTINATION "${CMAKE_INSTALL_LIBDIR}") + + + +######################################################################################################################## +## Automatic plugin deployment +######################################################################################################################## + +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory "e:/Modding/Skyrim/Mods/overwrite/SKSE/Plugins/") +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy $ "e:/Modding/Skyrim/Mods/overwrite/SKSE/Plugins/") diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000..566eb6b --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,252 @@ +{ + "version": 2, + "cmakeMinimumRequired": { + "major": 3, + "minor": 21, + "patch": 0 + }, + "configurePresets": [ + { + "name": "base", + "hidden": true, + "cacheVariables": { + "CMAKE_CXX_FLAGS": "$env{COMMONLIBSSE_COMPILER} $env{COMMONLIBSSE_PLATFORM} $env{COMMONLIBSSE_TEXT}" + } + }, + { + "name": "vcpkg", + "hidden": true, + "cacheVariables": { + "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", + "VCPKG_TARGET_TRIPLET": "x64-windows-skse", + "VCPKG_HOST_TRIPLET": "x64-windows-skse", + "VCPKG_OVERLAY_TRIPLETS": "${sourceDir}/cmake", + "CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded$<$:Debug>DLL" + } + }, + { + "name": "win32", + "hidden": true, + "environment": { + "COMMONLIBSSE_PLATFORM": "-DWIN32_LEAN_AND_MEAN -DNOMINMAX" + } + }, + { + "name": "win32-unicode", + "hidden": true, + "inherits": "win32", + "environment": { + "COMMONLIBSSE_TEXT": "-DUNICODE -D_UNICODE" + } + }, + { + "name": "x64", + "hidden": true, + "architecture": { + "value": "x64", + "strategy": "external" + } + }, + { + "name": "msvc", + "hidden": true, + "environment": { + "COMMONLIBSSE_COMPILER": "/permissive- /Zc:preprocessor /EHsc $penv{CXXFLAGS}" + }, + "vendor": { + "microsoft.com/VisualStudioSettings/CMake/1.0": { + "intelliSenseMode": "windows-msvc-x64", + "enableMicrosoftCodeAnalysis": true, + "enableClangTidyCodeAnalysis": true + } + } + }, + { + "name": "clang-cl", + "hidden": true, + "cacheVariables": { + "CMAKE_C_COMPILER": "clang-cl", + "CMAKE_CXX_COMPILER": "clang-cl" + }, + "environment": { + "COMMONLIBSSE_COMPILER": "/permissive- /EHsc -Wno-overloaded-virtual -Wno-delete-non-abstract-non-virtual-dtor -D__cpp_lib_char8_t -D__cpp_consteval -D__cpp_lib_format $penv{CXXFLAGS}" + }, + "vendor": { + "microsoft.com/VisualStudioSettings/CMake/1.0": { + "intelliSenseMode": "windows-clang-x64", + "enableMicrosoftCodeAnalysis": true, + "enableClangTidyCodeAnalysis": true + } + } + }, + { + "name": "build-tests", + "displayName": "Build Tests", + "hidden": true, + "description": "Include test suites in the build.", + "cacheVariables": { + "BUILD_TESTS": { + "type": "STRING", + "value": "ON" + } + } + }, + { + "name": "build-release-msvc", + "inherits": [ + "base", + "vcpkg", + "win32-unicode", + "x64", + "build-tests", + "msvc" + ], + "displayName": "Release", + "description": "Optimized release build.", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/release-msvc", + "cacheVariables": { + "CMAKE_BUILD_TYPE": { + "type": "STRING", + "value": "Release" + } + } + }, + { + "name": "build-debug-msvc", + "inherits": [ + "base", + "vcpkg", + "win32-unicode", + "x64", + "build-tests", + "msvc" + ], + "displayName": "Debug", + "description": "Debug build for testing.", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/debug-msvc", + "cacheVariables": { + "CMAKE_BUILD_TYPE": { + "type": "STRING", + "value": "Debug" + } + } + }, + { + "name": "build-debug-clang-cl", + "inherits": [ + "base", + "vcpkg", + "win32-unicode", + "x64", + "build-tests", + "clang-cl" + ], + "displayName": "Debug", + "description": "Debug build for testing.", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/debug-clang", + "cacheVariables": { + "CMAKE_BUILD_TYPE": { + "type": "STRING", + "value": "Debug" + } + } + }, + { + "name": "build-release-clang-cl", + "inherits": [ + "base", + "vcpkg", + "win32-unicode", + "x64", + "build-tests", + "clang-cl" + ], + "displayName": "Release", + "description": "Optimized release build.", + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/release-clang", + "cacheVariables": { + "CMAKE_BUILD_TYPE": { + "type": "STRING", + "value": "Release" + } + } + } + ], + "buildPresets": [ + { + "name": "release-msvc", + "displayName": "Release (MSVC)", + "configurePreset": "build-release-msvc", + "description": "Optimized release build." + }, + { + "name": "debug-msvc", + "displayName": "Debug (MSVC)", + "configurePreset": "build-debug-msvc", + "description": "Debug build for testing." + }, + { + "name": "release-clang-cl", + "displayName": "Release (Clang)", + "configurePreset": "build-release-clang-cl", + "description": "Optimized release build." + }, + { + "name": "debug-clang-cl", + "displayName": "Debug (Clang)", + "configurePreset": "build-debug-clang-cl", + "description": "Debug build for testing." + } + ], + "testPresets": [ + { + "name": "tests-all", + "displayName": "All Tests", + "configurePreset": "build-debug-msvc", + "output": { + "outputOnFailure": true + }, + "execution": { + "noTestsAction": "error", + "stopOnFailure": false + } + }, + { + "name": "tests-unit", + "displayName": "Unit Tests", + "description": "Runs tests that do not require any Skyrim module loaded into the process.", + "inherits": "tests-all", + "filter": { + "exclude": { + "label": "[integration],[e2e]" + } + } + }, + { + "name": "tests-integration", + "displayName": "Integration Tests", + "description": "Runs tests that interact with a Skyrim module at rest (do not require the Skyrim module to have run any main function).", + "inherits": "tests-all", + "filter": { + "include": { + "label": "[integration]" + } + } + }, + { + "name": "tests-e2e", + "displayName": "End-to-End Tests", + "description": "Runs test that depend on a fully running Skyrim engine in the process.", + "inherits": "tests-all", + "filter": { + "include": { + "label": "[e2e]" + } + } + } + ] +} diff --git a/cmake/version.rc.in b/cmake/version.rc.in new file mode 100644 index 0000000..60fc025 --- /dev/null +++ b/cmake/version.rc.in @@ -0,0 +1,34 @@ +#include + +1 VERSIONINFO + FILEVERSION @PROJECT_VERSION_MAJOR@, @PROJECT_VERSION_MINOR@, @PROJECT_VERSION_PATCH@, 0 + PRODUCTVERSION @PROJECT_VERSION_MAJOR@, @PROJECT_VERSION_MINOR@, @PROJECT_VERSION_PATCH@, 0 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Eddoursul (www.eddoursul.win)" + VALUE "FileDescription", "@PROJECT_DESCRIPTION@" + VALUE "FileVersion", "@PROJECT_VERSION@" + VALUE "InternalName", "@PROJECT_NAME@" + VALUE "LegalCopyright", "GNU Lesser General Public License 3.0" + VALUE "ProductName", "@PROJECT_FRIENDLY_NAME@" + VALUE "ProductVersion", "@PROJECT_VERSION@" + VALUE "OriginalFilename", "@PROJECT_NAME@.dll" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/cmake/x64-windows-skse.cmake b/cmake/x64-windows-skse.cmake new file mode 100644 index 0000000..2925afa --- /dev/null +++ b/cmake/x64-windows-skse.cmake @@ -0,0 +1,8 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +set(VCPKG_CRT_LINKAGE dynamic) + +if (${PORT} MATCHES "fully-dynamic-game-engine|skse|qt*") + set(VCPKG_LIBRARY_LINKAGE dynamic) +else () + set(VCPKG_LIBRARY_LINKAGE static) +endif () diff --git a/src/EventListener.cpp b/src/EventListener.cpp new file mode 100644 index 0000000..d7f64f6 --- /dev/null +++ b/src/EventListener.cpp @@ -0,0 +1,62 @@ +#include "EventListener.h" + +auto EventListener::GetSingleton() -> EventListener* +{ + static EventListener singleton{}; + return std::addressof(singleton); +} + +void EventListener::Install() +{ + RE::ScriptEventSourceHolder::GetSingleton()->GetEventSource()->AddEventSink(EventListener::GetSingleton()); + RE::UI::GetSingleton()->AddEventSink(EventListener::GetSingleton()); + + // BGSActorCellEvent is registered on MessagingInterface::kDataLoaded +} + +auto EventListener::ProcessEvent( + const RE::BGSActorCellEvent* a_event, + RE::BSTEventSource* a_eventSource) + -> RE::BSEventNotifyControl +{ + if (a_event->flags == RE::BGSActorCellEvent::CellFlag::kEnter) { + SKSE::GetTaskInterface()->AddTask(ClearOldShaders); + } + + return RE::BSEventNotifyControl::kContinue; +} + +auto EventListener::ProcessEvent( + const RE::TESCellAttachDetachEvent* a_event, + RE::BSTEventSource* a_eventSource) + -> RE::BSEventNotifyControl +{ + if (a_event && a_event->attached && a_event->reference) { + if (const auto baseObj = a_event->reference->GetBaseObject(); baseObj->IsBook()) { + if (const auto bookObj = baseObj->As()) { + if (!bookObj->IsRead()) { + RE::TESObjectREFR* ref = a_event->reference.get(); + SKSE::GetTaskInterface()->AddTask([ref]() { + if (ref) { + ref->ApplyEffectShader(GetShader()); + } + }); + } + } + } + } + + return RE::BSEventNotifyControl::kContinue; +} + +auto EventListener::ProcessEvent( + const RE::MenuOpenCloseEvent* a_event, + RE::BSTEventSource* a_eventSource) + -> RE::BSEventNotifyControl +{ + if (a_event && !a_event->opening && a_event->menuName == RE::BookMenu::MENU_NAME) { + SKSE::GetTaskInterface()->AddTask(ClearOldShaders); + } + + return RE::BSEventNotifyControl::kContinue; +} diff --git a/src/EventListener.h b/src/EventListener.h new file mode 100644 index 0000000..d1d8f27 --- /dev/null +++ b/src/EventListener.h @@ -0,0 +1,37 @@ +#pragma once + +#include "Util.h" + +class EventListener : + public RE::BSTEventSink, + public RE::BSTEventSink, + public RE::BSTEventSink +{ +public: + ~EventListener() = default; + EventListener(const EventListener&) = delete; + EventListener& operator=(const EventListener&) = delete; + EventListener& operator=(EventListener&&) = delete; + + static auto GetSingleton() -> EventListener*; + + static void Install(); + + auto ProcessEvent( + const RE::BGSActorCellEvent* a_event, + RE::BSTEventSource* a_eventSource) + -> RE::BSEventNotifyControl override; + + auto ProcessEvent( + const RE::TESCellAttachDetachEvent* a_event, + RE::BSTEventSource* a_eventSource) + -> RE::BSEventNotifyControl override; + + auto ProcessEvent( + const RE::MenuOpenCloseEvent* a_event, + RE::BSTEventSource* a_eventSource) + -> RE::BSEventNotifyControl override; + +private: + EventListener() = default; +}; diff --git a/src/Main.cpp b/src/Main.cpp new file mode 100644 index 0000000..99e7840 --- /dev/null +++ b/src/Main.cpp @@ -0,0 +1,62 @@ +#include "Util.h" +#include "EventListener.h" + +using namespace SKSE; + +namespace +{ + void InitializeLogging() { + wchar_t* buffer{ nullptr }; + const auto result = ::SHGetKnownFolderPath(::FOLDERID_Documents, ::KNOWN_FOLDER_FLAG::KF_FLAG_DEFAULT, nullptr, std::addressof(buffer)); + std::unique_ptr knownPath(buffer, ::CoTaskMemFree); + + if (!knownPath || result != S_OK) { + logger::error("failed to get known folder path"sv); + return; + } + + std::filesystem::path path = knownPath.get(); + path /= "My Games"sv; + if (GetModuleHandle(L"Galaxy64.dll") != NULL) { + path /= "Skyrim Special Edition GOG"sv; + } else { + path /= "Skyrim Special Edition"sv; + } + path /= "SKSE"sv; + path /= std::format("{}.log", PluginDeclaration::GetSingleton()->GetName()); + + auto sink = std::make_shared(path.string(), true); + auto log = std::make_shared("global log"s, std::move(sink)); + + log->set_level(spdlog::level::info); + log->flush_on(spdlog::level::info); + + spdlog::set_default_logger(std::move(log)); + spdlog::set_pattern("[%l] %v"s); + } + + void InitializeMessaging() + { + GetMessagingInterface()->RegisterListener([](MessagingInterface::Message* message) { + if (message->type == MessagingInterface::kDataLoaded) { + RE::PlayerCharacter::GetSingleton()->AsBGSActorCellEventSource()->AddEventSink(EventListener::GetSingleton()); + } + }); + } +} + +SKSEPluginLoad(const LoadInterface* skse) +{ + InitializeLogging(); + + auto* plugin = PluginDeclaration::GetSingleton(); + logger::info("{} {} is loading...", plugin->GetName(), plugin->GetVersion()); + + Init(skse); + InitializeMessaging(); + + EventListener::Install(); + + logger::info("{} has finished loading.", plugin->GetName()); + return true; +} diff --git a/src/PCH.h b/src/PCH.h new file mode 100644 index 0000000..7fd9de7 --- /dev/null +++ b/src/PCH.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include + +#include +#undef cdecl // Workaround for Clang 14 CMake configure error. + +#include +#include + +// Compatible declarations with other sample projects. +#define DLLEXPORT __declspec(dllexport) + +using namespace std::literals; +using namespace REL::literals; + +namespace logger = SKSE::log; diff --git a/src/Util.h b/src/Util.h new file mode 100644 index 0000000..095e110 --- /dev/null +++ b/src/Util.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +inline RE::TESEffectShader* GetShader() +{ + return RE::TESForm::LookupByID(0xC5EF7); +} + +inline void ClearOldShaders() +{ + if (const auto processLists = RE::ProcessLists::GetSingleton()) { + const auto shader = GetShader(); + + processLists->ForEachShaderEffect([&](RE::ShaderReferenceEffect* a_shaderEffect) -> RE::BSContainer::ForEachResult { + if (a_shaderEffect && a_shaderEffect->effectData == shader && a_shaderEffect->target) { + if (const auto targetRef = a_shaderEffect->target.get()) { + if (const auto baseObj = targetRef->GetBaseObject(); baseObj->IsBook()) { + if (baseObj->As()->IsRead()) { + a_shaderEffect->finished = true; + } + } + } + } + + return RE::BSContainer::ForEachResult::kContinue; + }); + } +} diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json new file mode 100644 index 0000000..bff8343 --- /dev/null +++ b/vcpkg-configuration.json @@ -0,0 +1,7 @@ +{ + "default-registry": { + "kind": "git", + "repository": "https://github.com/microsoft/vcpkg.git", + "baseline": "f61a294e765b257926ae9e9d85f96468a0af74e7" + } +} diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 0000000..6f572e1 --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json", + "name": "unread-books-glow", + "version-string": "1.0.0", + "port-version": 0, + "description": "Unread Books Glow NG", + "license": "LGPL-3.0", + "features": { + "plugin": { + "description": "Unread Books Glow NG", + "dependencies": [ + "simpleini", + "spdlog", + "directxtk", + "rapidcsv" + ] + } + }, + "default-features": [ + "plugin" + ] +}