├── .clang-format
├── .editorconfig
├── .gitignore
├── .gitmodules
├── LICENSE
├── README.md
├── THIRD_PARTY_LICENSES
├── bundle
├── ArchiveXL.cpmodproj
├── scripts
│ ├── AXL_GenerateCustomizationFixes.wscript
│ └── AXL_GenerateCustomizationResources.wscript
└── source
│ ├── raw
│ └── archive_xl
│ │ ├── characters
│ │ ├── common
│ │ │ ├── eyes
│ │ │ │ ├── heb__01.mi.json
│ │ │ │ ├── hel_pma.mi.json
│ │ │ │ └── hel_pwa.mi.json
│ │ │ └── hair
│ │ │ │ ├── h1_base_color_patch.mesh.json
│ │ │ │ └── textures
│ │ │ │ └── hair_profiles
│ │ │ │ └── base_material.mi.json
│ │ └── head
│ │ │ └── player_base_heads
│ │ │ ├── appearances
│ │ │ └── head
│ │ │ │ ├── eyebrows
│ │ │ │ ├── heb_000_pma__basehead_01.app.json
│ │ │ │ └── heb_000_pwa__basehead_01.app.json
│ │ │ │ ├── he_000_pma__basehead.app.json
│ │ │ │ ├── he_000_pwa__basehead.app.json
│ │ │ │ ├── hel_000_pma__basehead.app.json
│ │ │ │ └── hel_000_pwa__basehead.app.json
│ │ │ ├── player_female_average
│ │ │ ├── h0_000_pwa_c__basehead
│ │ │ │ ├── he_000_pwa_c__basehead_patch.mesh.json
│ │ │ │ ├── heb_000_pwa__basehead_01.mesh.json
│ │ │ │ └── hel_000_pwa_c__basehead_patch.mesh.json
│ │ │ └── heb_000_pwa__basehead_01.morphtarget.json
│ │ │ └── player_man_average
│ │ │ ├── h0_000_pma_c__basehead
│ │ │ ├── he_000_pma_c__basehead_patch.mesh.json
│ │ │ ├── heb_000_pma__basehead_01.mesh.json
│ │ │ └── hel_000_pma_c__basehead_patch.mesh.json
│ │ │ └── heb_000_pma__basehead_01.morphtarget.json
│ │ └── common
│ │ └── null.morphtarget.json
│ └── resources
│ ├── Migration.xl
│ ├── PhotoModeScope.xl
│ ├── PlayerBaseScope.xl
│ ├── PlayerCustomizationBeardFix.xl
│ ├── PlayerCustomizationBeardScope.xl
│ ├── PlayerCustomizationBrowsFix.xl
│ ├── PlayerCustomizationBrowsPatch.xl
│ ├── PlayerCustomizationBrowsScope.xl
│ ├── PlayerCustomizationEyesFix.xl
│ ├── PlayerCustomizationEyesPatch.xl
│ ├── PlayerCustomizationEyesScope.xl
│ ├── PlayerCustomizationHairFix.xl
│ ├── PlayerCustomizationHairPatch.xl
│ ├── PlayerCustomizationHairScope.xl
│ ├── PlayerCustomizationLashesFix.xl
│ ├── PlayerCustomizationLashesPatch.xl
│ ├── PlayerCustomizationLashesScope.xl
│ ├── PlayerCustomizationScope.xl
│ └── QuestBaseScope.xl
├── config
├── Project.hpp.in
└── Version.rc.in
├── lib
├── Core
│ ├── Container
│ │ ├── Container.hpp
│ │ └── Registry.hpp
│ ├── Facades
│ │ ├── Container.hpp
│ │ ├── Hook.hpp
│ │ ├── Log.hpp
│ │ ├── Runtime.cpp
│ │ └── Runtime.hpp
│ ├── Foundation
│ │ ├── Application.cpp
│ │ ├── Application.hpp
│ │ ├── Feature.hpp
│ │ ├── LocaleProvider.hpp
│ │ ├── RuntimeProvider.cpp
│ │ └── RuntimeProvider.hpp
│ ├── Hooking
│ │ ├── Detail.hpp
│ │ ├── HookingAgent.cpp
│ │ ├── HookingAgent.hpp
│ │ ├── HookingDriver.cpp
│ │ └── HookingDriver.hpp
│ ├── Logging
│ │ ├── LoggingAgent.cpp
│ │ ├── LoggingAgent.hpp
│ │ ├── LoggingDriver.cpp
│ │ └── LoggingDriver.hpp
│ ├── Memory
│ │ ├── AddressResolver.cpp
│ │ └── AddressResolver.hpp
│ ├── Raw.hpp
│ ├── Runtime
│ │ ├── HostImage.cpp
│ │ ├── HostImage.hpp
│ │ ├── ModuleImage.cpp
│ │ ├── ModuleImage.hpp
│ │ ├── OwnerMutex.cpp
│ │ └── OwnerMutex.hpp
│ ├── Stl.hpp
│ └── Win.hpp
├── Red
│ ├── Alias.hpp
│ ├── Engine.hpp
│ ├── Engine
│ │ ├── Framework.hpp
│ │ ├── LogChannel.hpp
│ │ ├── Macros
│ │ │ └── Framework.hpp
│ │ └── Mappings.hpp
│ ├── Specializations.hpp
│ ├── TypeInfo.hpp
│ ├── TypeInfo
│ │ ├── Common.hpp
│ │ ├── Construction.hpp
│ │ ├── Definition.hpp
│ │ ├── Invocation.hpp
│ │ ├── Macros
│ │ │ ├── Definition.hpp
│ │ │ └── Resolving.hpp
│ │ ├── Mappings.hpp
│ │ ├── Parameters.hpp
│ │ ├── Properties.hpp
│ │ ├── Registrar.hpp
│ │ └── Resolving.hpp
│ ├── Utils.hpp
│ └── Utils
│ │ ├── Handles.hpp
│ │ ├── JobQueues.hpp
│ │ └── Resources.hpp
└── Support
│ ├── MinHook
│ ├── MinHookProvider.cpp
│ └── MinHookProvider.hpp
│ ├── RED4ext
│ ├── RED4extProvider.cpp
│ └── RED4extProvider.hpp
│ ├── RedLib
│ ├── RedLibProvider.cpp
│ └── RedLibProvider.hpp
│ └── Spdlog
│ ├── SpdlogProvider.cpp
│ └── SpdlogProvider.hpp
├── scripts
├── DynamicAppearance.reds
├── Facade.reds
└── Module.reds
├── src
├── App
│ ├── Application.cpp
│ ├── Application.hpp
│ ├── Archives
│ │ ├── ArchiveService.cpp
│ │ └── ArchiveService.hpp
│ ├── Environment.hpp
│ ├── Extensions
│ │ ├── Animation
│ │ │ ├── Config.cpp
│ │ │ ├── Config.hpp
│ │ │ ├── Extension.cpp
│ │ │ └── Extension.hpp
│ │ ├── Attachment
│ │ │ ├── Extension.cpp
│ │ │ └── Extension.hpp
│ │ ├── Customization
│ │ │ ├── Config.cpp
│ │ │ ├── Config.hpp
│ │ │ ├── Extension.cpp
│ │ │ └── Extension.hpp
│ │ ├── ExtensionBase.hpp
│ │ ├── ExtensionLoader.cpp
│ │ ├── ExtensionLoader.hpp
│ │ ├── ExtensionService.cpp
│ │ ├── ExtensionService.hpp
│ │ ├── FactoryIndex
│ │ │ ├── Config.cpp
│ │ │ ├── Config.hpp
│ │ │ ├── Extension.cpp
│ │ │ └── Extension.hpp
│ │ ├── Garment
│ │ │ ├── ChunkMask.hpp
│ │ │ ├── Config.cpp
│ │ │ ├── Config.hpp
│ │ │ ├── Dynamic.cpp
│ │ │ ├── Dynamic.hpp
│ │ │ ├── Extension.cpp
│ │ │ ├── Extension.hpp
│ │ │ ├── Prefix.cpp
│ │ │ ├── Prefix.hpp
│ │ │ ├── States.cpp
│ │ │ ├── States.hpp
│ │ │ ├── Tags.cpp
│ │ │ ├── Tags.hpp
│ │ │ ├── Wrapper.cpp
│ │ │ └── Wrapper.hpp
│ │ ├── InkSpawner
│ │ │ ├── Extension.cpp
│ │ │ └── Extension.hpp
│ │ ├── Journal
│ │ │ ├── Config.cpp
│ │ │ ├── Config.hpp
│ │ │ ├── Extension.cpp
│ │ │ └── Extension.hpp
│ │ ├── Localization
│ │ │ ├── Config.cpp
│ │ │ ├── Config.hpp
│ │ │ ├── Extension.cpp
│ │ │ ├── Extension.hpp
│ │ │ ├── Language.cpp
│ │ │ └── Language.hpp
│ │ ├── Mesh
│ │ │ ├── Extension.cpp
│ │ │ └── Extension.hpp
│ │ ├── PhotoMode
│ │ │ ├── Extension.cpp
│ │ │ └── Extension.hpp
│ │ ├── PuppetState
│ │ │ ├── Config.cpp
│ │ │ ├── Config.hpp
│ │ │ ├── Extension.cpp
│ │ │ ├── Extension.hpp
│ │ │ ├── Handler.cpp
│ │ │ ├── Handler.hpp
│ │ │ ├── System.cpp
│ │ │ └── System.hpp
│ │ ├── QuestPhase
│ │ │ ├── Config.cpp
│ │ │ ├── Config.hpp
│ │ │ ├── Extension.cpp
│ │ │ └── Extension.hpp
│ │ ├── ResourceLink
│ │ │ ├── Config.cpp
│ │ │ ├── Config.hpp
│ │ │ ├── Extension.cpp
│ │ │ └── Extension.hpp
│ │ ├── ResourceMeta
│ │ │ ├── Config.cpp
│ │ │ ├── Config.hpp
│ │ │ ├── Extension.cpp
│ │ │ └── Extension.hpp
│ │ ├── ResourcePatch
│ │ │ ├── Config.cpp
│ │ │ ├── Config.hpp
│ │ │ ├── Extension.cpp
│ │ │ └── Extension.hpp
│ │ ├── Transmog
│ │ │ ├── Extension.cpp
│ │ │ └── Extension.hpp
│ │ └── WorldStreaming
│ │ │ ├── Config.cpp
│ │ │ ├── Config.hpp
│ │ │ ├── Extension.cpp
│ │ │ └── Extension.hpp
│ ├── Facade.cpp
│ ├── Facade.hpp
│ ├── Migration.hpp
│ ├── Patches
│ │ ├── EntitySpawnerPatch.cpp
│ │ ├── EntitySpawnerPatch.hpp
│ │ ├── WorldWidgetLimitPatch.cpp
│ │ └── WorldWidgetLimitPatch.hpp
│ ├── Shared
│ │ ├── ResourcePathRegistry.cpp
│ │ └── ResourcePathRegistry.hpp
│ └── Utils
│ │ ├── Num.hpp
│ │ ├── Registers.asm
│ │ ├── Registers.hpp
│ │ └── Str.hpp
├── Red
│ ├── Addresses
│ │ └── Library.hpp
│ ├── AnimatedComponent.hpp
│ ├── AppearanceChanger.hpp
│ ├── AppearanceResource.hpp
│ ├── AttachmentSlots.hpp
│ ├── Buffer.hpp
│ ├── CharacterCustomization.hpp
│ ├── Common.hpp
│ ├── CommunitySystem.hpp
│ ├── Entity.hpp
│ ├── EntityBuilder.hpp
│ ├── EntitySpawner.hpp
│ ├── EntityTemplate.hpp
│ ├── FactoryIndex.hpp
│ ├── GameApplication.hpp
│ ├── GameEngine.hpp
│ ├── GarmentAssembler.hpp
│ ├── ImpostorComponent.hpp
│ ├── InkSpawner.hpp
│ ├── ItemObject.hpp
│ ├── JobHandle.hpp
│ ├── JournalManager.hpp
│ ├── JournalTree.hpp
│ ├── Localization.hpp
│ ├── MappinSystem.hpp
│ ├── Mesh.hpp
│ ├── MorphTarget.hpp
│ ├── PersistencySystem.hpp
│ ├── PhotoMode.hpp
│ ├── QuestLoader.hpp
│ ├── QuestPhase.hpp
│ ├── QuestsSystem.hpp
│ ├── ResourceDepot.hpp
│ ├── ResourceLoader.hpp
│ ├── ResourcePath.hpp
│ ├── Serialization.hpp
│ ├── SharedStorage.hpp
│ ├── StreamingSector.hpp
│ ├── StreamingWorld.hpp
│ ├── TPPRepresentationComponent.hpp
│ ├── TagList.hpp
│ ├── Threads.hpp
│ ├── TransactionSystem.hpp
│ ├── TweakDB.hpp
│ └── VisualTagsPreset.hpp
├── main.cpp
├── pch.cpp
├── pch.hpp
└── rtti.cpp
├── support
├── hints
│ └── ArchiveXL.toml
├── red4ext
│ └── ArchiveXL.hpp
└── templates
│ ├── factory.csv.json
│ ├── localization.json
│ └── mod.archive.xl
├── tools
└── dist
│ ├── package-mod.ps1
│ └── steps
│ ├── compose-bundle.ps1
│ ├── compose-hints.ps1
│ ├── compose-licenses.ps1
│ ├── compose-red4ext.ps1
│ ├── compose-redscripts.ps1
│ ├── create-zip-from-stage.ps1
│ ├── get-version.ps1
│ └── install-from-stage.ps1
└── xmake.lua
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | BasedOnStyle: Microsoft
3 | ---
4 | Language: Cpp
5 |
6 | AccessModifierOffset: -4
7 | AlwaysBreakTemplateDeclarations: Yes
8 | BreakConstructorInitializers: BeforeComma
9 | BreakInheritanceList: BeforeComma
10 | KeepEmptyLinesAtTheStartOfBlocks: false
11 | NamespaceIndentation: Inner
12 | PointerAlignment: Left
13 | SpaceAfterTemplateKeyword: false
14 | IndentCaseLabels: false
15 | BreakBeforeBraces: Custom
16 | BraceWrapping:
17 | AfterCaseLabel: true
18 | AfterClass: true
19 | AfterControlStatement: Always
20 | AfterEnum: true
21 | AfterFunction: true
22 | AfterNamespace: true
23 | AfterStruct: true
24 | AfterUnion: true
25 | AfterExternBlock: true
26 | BeforeCatch: true
27 | BeforeElse: true
28 | IndentBraces: false
29 | SplitEmptyFunction: true
30 | SplitEmptyRecord: true
31 | SplitEmptyNamespace: true
32 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | insert_final_newline = true
6 | trim_trailing_whitespace = true
7 |
8 | [*.{h,c,cpp,hpp}]
9 | indent_style = space
10 | indent_size = 4
11 |
12 | [*.{yml,yaml,xl}]
13 | indent_style = space
14 | indent_size = 2
15 |
16 | [*.json]
17 | indent_style = space
18 | indent_size = 2
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea
2 | /.vs
3 | /.vscode
4 | /.xmake
5 | /bundle/packed
6 | /bundle/source/archive
7 | /bundle/*.xml
8 | /bundle/*.zip
9 | /bundle/custom_refs.txt
10 | /bundle/fileTreeState.json
11 | /build
12 | /dev
13 | /src/App/Project.hpp
14 | /src/App/Version.rc
15 | /tools/wkit/layout.xml
16 | __pycache__
17 | CMakeLists.txt
18 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "vendor/RED4ext.SDK"]
2 | path = vendor/RED4ext.SDK
3 | url = https://github.com/psiberx/RED4ext.SDK.git
4 | [submodule "vendor/wil"]
5 | path = vendor/wil
6 | url = https://github.com/microsoft/wil.git
7 | [submodule "vendor/semver"]
8 | path = vendor/semver
9 | url = https://github.com/Neargye/semver.git
10 | [submodule "vendor/nameof"]
11 | path = vendor/nameof
12 | url = https://github.com/Neargye/nameof.git
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Pavel Siberx
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ArchiveXL
2 |
3 | ArchiveXL is a modding tool that allows you to load custom resources without touching original game files,
4 | thus allowing multiple mods to expand same resources without conflicts.
5 |
6 | With the mod you can:
7 |
8 | - Load custom entity factories (necessary for item additions)
9 | - Add localization texts that can be used in scripts, resources and TweakDB
10 | - Edit existing localization texts without overwriting original resources
11 | - Override submeshes visibility of entity parts
12 | - Add visual tags to a clothing item
13 | - Spawn widgets from any library without registering dependencies
14 |
15 | ## Getting Started
16 |
17 | ### Compatibility
18 |
19 | - Cyberpunk 2077 2.21
20 | - [redscript](https://github.com/jac3km4/redscript) 0.5.27+
21 |
22 | ### Installation
23 |
24 | 1. Install requirements:
25 | - [RED4ext](https://docs.red4ext.com/getting-started/installing-red4ext) 1.27.0+
26 | 2. Extract the release archive `ArchiveXL-x.x.x.zip` into the Cyberpunk 2077 directory.
27 |
28 | ## Documentation
29 |
30 | - [Dynamic appearances](https://github.com/psiberx/cp2077-archive-xl/wiki#dynamic-appearances)
31 | - [Body types](https://github.com/psiberx/cp2077-archive-xl/wiki#body-types)
32 | - [Appearance suffixes](https://github.com/psiberx/cp2077-archive-xl/wiki#appearance-suffixes)
33 | - [Components overrides](https://github.com/psiberx/cp2077-archive-xl/wiki#components-overrides)
34 | - [Visual tags](https://github.com/psiberx/cp2077-archive-xl/wiki#visual-tags)
35 | - [Extending resources](https://github.com/psiberx/cp2077-archive-xl/wiki#extending-resources)
36 |
--------------------------------------------------------------------------------
/bundle/ArchiveXL.cpmodproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | ArchiveXL
4 | ArchiveXL
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/bundle/source/raw/archive_xl/characters/common/eyes/heb__01.mi.json:
--------------------------------------------------------------------------------
1 | {
2 | "Header": {
3 | "WolvenKitVersion": "8.15.1-nightly.2024-12-22",
4 | "WKitJsonVersion": "0.0.9",
5 | "GameVersion": 2200,
6 | "ExportedDateTime": "2025-01-05T02:46:11.0092071Z",
7 | "DataType": "CR2W"
8 | },
9 | "Data": {
10 | "Version": 195,
11 | "BuildVersion": 0,
12 | "RootChunk": {
13 | "$type": "CMaterialInstance",
14 | "audioTag": {
15 | "$type": "CName",
16 | "$storage": "string",
17 | "$value": "None"
18 | },
19 | "baseMaterial": {
20 | "DepotPath": {
21 | "$type": "ResourcePath",
22 | "$storage": "string",
23 | "$value": "base\\materials\\mesh_decal_double_diffuse.mt"
24 | },
25 | "Flags": "Default"
26 | },
27 | "cookingPlatform": "PLATFORM_PC",
28 | "enableMask": 0,
29 | "metadata": null,
30 | "resourceVersion": 4,
31 | "values": [
32 | {
33 | "$type": "rRef:ITexture",
34 | "SecondaryDiffuseAlpha": {
35 | "DepotPath": {
36 | "$type": "ResourcePath",
37 | "$storage": "string",
38 | "$value": "base\\characters\\common\\character_customisation_items\\eyebrows\\textures\\heb_wa__base_ds01.xbm"
39 | },
40 | "Flags": "Default"
41 | }
42 | },
43 | {
44 | "$type": "rRef:ITexture",
45 | "DiffuseTexture": {
46 | "DepotPath": {
47 | "$type": "ResourcePath",
48 | "$storage": "string",
49 | "$value": "base\\characters\\common\\character_customisation_items\\eyebrows\\textures\\heb__base_d01.xbm"
50 | },
51 | "Flags": "Default"
52 | }
53 | },
54 | {
55 | "$type": "rRef:ITexture",
56 | "NormalTexture": {
57 | "DepotPath": {
58 | "$type": "ResourcePath",
59 | "$storage": "string",
60 | "$value": "base\\characters\\common\\character_customisation_items\\eyebrows\\textures\\heb__base_n01.xbm"
61 | },
62 | "Flags": "Default"
63 | }
64 | }
65 | ]
66 | },
67 | "EmbeddedFiles": []
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/bundle/source/raw/archive_xl/characters/common/eyes/hel_pma.mi.json:
--------------------------------------------------------------------------------
1 | {
2 | "Header": {
3 | "WolvenKitVersion": "8.15.1-nightly.2024-12-22",
4 | "WKitJsonVersion": "0.0.9",
5 | "GameVersion": 2200,
6 | "ExportedDateTime": "2025-01-05T02:46:11.0092071Z",
7 | "DataType": "CR2W"
8 | },
9 | "Data": {
10 | "Version": 195,
11 | "BuildVersion": 0,
12 | "RootChunk": {
13 | "$type": "CMaterialInstance",
14 | "audioTag": {
15 | "$type": "CName",
16 | "$storage": "string",
17 | "$value": "None"
18 | },
19 | "baseMaterial": {
20 | "DepotPath": {
21 | "$type": "ResourcePath",
22 | "$storage": "string",
23 | "$value": "base\\characters\\common\\character_customisation_items\\eyelashes\\source\\eyelashes__default.mi"
24 | },
25 | "Flags": "Default"
26 | },
27 | "cookingPlatform": "PLATFORM_PC",
28 | "enableMask": 0,
29 | "metadata": null,
30 | "resourceVersion": 4,
31 | "values": [
32 | {
33 | "$type": "rRef:ITexture",
34 | "Strand_Alpha": {
35 | "DepotPath": {
36 | "$type": "ResourcePath",
37 | "$storage": "string",
38 | "$value": "base\\characters\\common\\eyes\\textures\\eyelashes_ma_01_lod1.xbm"
39 | },
40 | "Flags": "Default"
41 | }
42 | }
43 | ]
44 | },
45 | "EmbeddedFiles": []
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/bundle/source/raw/archive_xl/characters/common/eyes/hel_pwa.mi.json:
--------------------------------------------------------------------------------
1 | {
2 | "Header": {
3 | "WolvenKitVersion": "8.15.1-nightly.2024-12-22",
4 | "WKitJsonVersion": "0.0.9",
5 | "GameVersion": 2200,
6 | "ExportedDateTime": "2025-01-05T02:46:11.0092071Z",
7 | "DataType": "CR2W"
8 | },
9 | "Data": {
10 | "Version": 195,
11 | "BuildVersion": 0,
12 | "RootChunk": {
13 | "$type": "CMaterialInstance",
14 | "audioTag": {
15 | "$type": "CName",
16 | "$storage": "string",
17 | "$value": "None"
18 | },
19 | "baseMaterial": {
20 | "DepotPath": {
21 | "$type": "ResourcePath",
22 | "$storage": "string",
23 | "$value": "base\\characters\\common\\character_customisation_items\\eyelashes\\source\\eyelashes__default.mi"
24 | },
25 | "Flags": "Default"
26 | },
27 | "cookingPlatform": "PLATFORM_PC",
28 | "enableMask": 0,
29 | "metadata": null,
30 | "resourceVersion": 4,
31 | "values": [
32 | {
33 | "$type": "rRef:ITexture",
34 | "Strand_Alpha": {
35 | "DepotPath": {
36 | "$type": "ResourcePath",
37 | "$storage": "string",
38 | "$value": "base\\characters\\common\\hair\\textures\\hb1_brow_beard_lashes\\hb1_01__lash_single_d.xbm"
39 | },
40 | "Flags": "Default"
41 | }
42 | }
43 | ]
44 | },
45 | "EmbeddedFiles": []
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/bundle/source/raw/archive_xl/characters/common/hair/textures/hair_profiles/base_material.mi.json:
--------------------------------------------------------------------------------
1 | {
2 | "Header": {
3 | "WolvenKitVersion": "8.15.1-nightly.2024-12-22",
4 | "WKitJsonVersion": "0.0.9",
5 | "GameVersion": 2200,
6 | "ExportedDateTime": "2025-01-05T02:46:11.0092071Z",
7 | "DataType": "CR2W"
8 | },
9 | "Data": {
10 | "Version": 195,
11 | "BuildVersion": 0,
12 | "RootChunk": {
13 | "$type": "CMaterialInstance",
14 | "audioTag": {
15 | "$type": "CName",
16 | "$storage": "string",
17 | "$value": "None"
18 | },
19 | "baseMaterial": {
20 | "DepotPath": {
21 | "$type": "ResourcePath",
22 | "$storage": "string",
23 | "$value": ""
24 | },
25 | "Flags": "Default"
26 | },
27 | "cookingPlatform": "PLATFORM_PC",
28 | "enableMask": 0,
29 | "metadata": null,
30 | "resourceVersion": 4,
31 | "values": []
32 | },
33 | "EmbeddedFiles": []
34 | }
35 | }
--------------------------------------------------------------------------------
/bundle/source/raw/archive_xl/characters/head/player_base_heads/player_female_average/heb_000_pwa__basehead_01.morphtarget.json:
--------------------------------------------------------------------------------
1 | {
2 | "Header": {
3 | "WolvenKitVersion": "8.15.1-nightly.2024-12-22",
4 | "WKitJsonVersion": "0.0.9",
5 | "GameVersion": 2200,
6 | "ExportedDateTime": "2025-01-02T10:21:38.3952972Z",
7 | "DataType": "CR2W"
8 | },
9 | "Data": {
10 | "Version": 195,
11 | "BuildVersion": 0,
12 | "RootChunk": {
13 | "$type": "MorphTargetMesh",
14 | "baseMesh": {
15 | "DepotPath": {
16 | "$type": "ResourcePath",
17 | "$storage": "string",
18 | "$value": "archive_xl\\characters\\head\\player_base_heads\\player_female_average\\h0_000_pwa_c__basehead\\heb_000_pwa__basehead_01.mesh"
19 | },
20 | "Flags": "Default"
21 | },
22 | "baseMeshAppearance": {
23 | "$type": "CName",
24 | "$storage": "string",
25 | "$value": "default"
26 | },
27 | "baseTexture": {
28 | "DepotPath": {
29 | "$type": "ResourcePath",
30 | "$storage": "string",
31 | "$value": "engine\\textures\\editor\\normal.xbm"
32 | },
33 | "Flags": "Default"
34 | },
35 | "baseTextureParamName": {
36 | "$type": "CName",
37 | "$storage": "string",
38 | "$value": "Normal"
39 | },
40 | "blob": null,
41 | "boundingBox": {
42 | "$type": "Box",
43 | "Max": {
44 | "$type": "Vector4",
45 | "W": 0,
46 | "X": 0,
47 | "Y": 0,
48 | "Z": 0
49 | },
50 | "Min": {
51 | "$type": "Vector4",
52 | "W": 0,
53 | "X": 0,
54 | "Y": 0,
55 | "Z": 0
56 | }
57 | },
58 | "cookingPlatform": "PLATFORM_PC",
59 | "resourceVersion": 2,
60 | "targets": []
61 | },
62 | "EmbeddedFiles": []
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/bundle/source/raw/archive_xl/characters/head/player_base_heads/player_man_average/heb_000_pma__basehead_01.morphtarget.json:
--------------------------------------------------------------------------------
1 | {
2 | "Header": {
3 | "WolvenKitVersion": "8.15.1-nightly.2024-12-22",
4 | "WKitJsonVersion": "0.0.9",
5 | "GameVersion": 2200,
6 | "ExportedDateTime": "2025-01-04T09:05:47.8167670Z",
7 | "DataType": "CR2W"
8 | },
9 | "Data": {
10 | "Version": 195,
11 | "BuildVersion": 0,
12 | "RootChunk": {
13 | "$type": "MorphTargetMesh",
14 | "baseMesh": {
15 | "DepotPath": {
16 | "$type": "ResourcePath",
17 | "$storage": "string",
18 | "$value": "archive_xl\\characters\\head\\player_base_heads\\player_man_average\\h0_000_pma_c__basehead\\heb_000_pma__basehead_01.mesh"
19 | },
20 | "Flags": "Default"
21 | },
22 | "baseMeshAppearance": {
23 | "$type": "CName",
24 | "$storage": "string",
25 | "$value": "default"
26 | },
27 | "baseTexture": {
28 | "DepotPath": {
29 | "$type": "ResourcePath",
30 | "$storage": "string",
31 | "$value": "engine\\textures\\editor\\white.xbm"
32 | },
33 | "Flags": "Default"
34 | },
35 | "baseTextureParamName": {
36 | "$type": "CName",
37 | "$storage": "string",
38 | "$value": "NormalsBlendingModeAlpha"
39 | },
40 | "blob": null,
41 | "boundingBox": {
42 | "$type": "Box",
43 | "Max": {
44 | "$type": "Vector4",
45 | "W": 0,
46 | "X": 0,
47 | "Y": 0,
48 | "Z": 0
49 | },
50 | "Min": {
51 | "$type": "Vector4",
52 | "W": 0,
53 | "X": 0,
54 | "Y": 0,
55 | "Z": 0
56 | }
57 | },
58 | "cookingPlatform": "PLATFORM_PC",
59 | "resourceVersion": 2,
60 | "targets": []
61 | },
62 | "EmbeddedFiles": []
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/bundle/source/raw/archive_xl/common/null.morphtarget.json:
--------------------------------------------------------------------------------
1 | {
2 | "Header": {
3 | "WolvenKitVersion": "8.15.1-nightly.2024-12-22",
4 | "WKitJsonVersion": "0.0.9",
5 | "GameVersion": 2200,
6 | "ExportedDateTime": "2025-05-15T19:43:25.2967155Z",
7 | "DataType": "CR2W"
8 | },
9 | "Data": {
10 | "Version": 195,
11 | "BuildVersion": 0,
12 | "RootChunk": {
13 | "$type": "MorphTargetMesh",
14 | "baseMesh": {
15 | "DepotPath": {
16 | "$type": "ResourcePath",
17 | "$storage": "uint64",
18 | "$value": "0"
19 | },
20 | "Flags": "Default"
21 | },
22 | "baseMeshAppearance": {
23 | "$type": "CName",
24 | "$storage": "string",
25 | "$value": "None"
26 | },
27 | "baseTexture": {
28 | "DepotPath": {
29 | "$type": "ResourcePath",
30 | "$storage": "uint64",
31 | "$value": "0"
32 | },
33 | "Flags": "Default"
34 | },
35 | "baseTextureParamName": {
36 | "$type": "CName",
37 | "$storage": "string",
38 | "$value": "None"
39 | },
40 | "blob": null,
41 | "boundingBox": {
42 | "$type": "Box",
43 | "Max": {
44 | "$type": "Vector4",
45 | "W": 0,
46 | "X": 0,
47 | "Y": 0,
48 | "Z": 0
49 | },
50 | "Min": {
51 | "$type": "Vector4",
52 | "W": 0,
53 | "X": 0,
54 | "Y": 0,
55 | "Z": 0
56 | }
57 | },
58 | "cookingPlatform": "PLATFORM_None",
59 | "resourceVersion": 0,
60 | "targets": []
61 | },
62 | "EmbeddedFiles": []
63 | }
64 | }
--------------------------------------------------------------------------------
/bundle/source/resources/PhotoModeScope.xl:
--------------------------------------------------------------------------------
1 | resource:
2 | scope:
3 | photomode_wa.ent:
4 | - base\characters\entities\player\photo_mode\player_wa_photomode.ent
5 | - base\characters\entities\player\photo_mode\alt_cunningham\alt_photomode.ent
6 | - base\characters\entities\player\photo_mode\blue_moon\bmuc_photomode.ent
7 | - base\characters\entities\player\photo_mode\evelyn_parker\evelyn_photomode.ent
8 | - base\characters\entities\player\photo_mode\hanako_arasaka\hanako_photomode.ent
9 | - base\characters\entities\player\photo_mode\judy_alvarez\judy_photomode.ent
10 | - base\characters\entities\player\photo_mode\lizzy_wizzy\lizzy_photomode.ent
11 | - base\characters\entities\player\photo_mode\meredith_stout\meredith_photomode.ent
12 | - base\characters\entities\player\photo_mode\panam_palmer\panam_photomode.ent
13 | - base\characters\entities\player\photo_mode\purple_force\pfuc_photomode.ent
14 | - base\characters\entities\player\photo_mode\red_menace\rmuc_photomode.ent
15 | - base\characters\entities\player\photo_mode\rogue_amendiares\old_rogue_photomode.ent
16 | - base\characters\entities\player\photo_mode\rogue_amendiares\young_rogue_photomode.ent
17 | - ep1\characters\entities\player\photo_mode\myers\myers_photomode.ent
18 | - ep1\characters\entities\player\photo_mode\player_wa_photomode_ep1.ent
19 | - ep1\characters\entities\player\photo_mode\songbird\songbird_photomode.ent
20 | photomode_ma.ent:
21 | - base\characters\entities\player\photo_mode\player_ma_photomode.ent
22 | - base\characters\entities\player\photo_mode\johnny_photomode.ent
23 | - base\characters\entities\player\photo_mode\altjohnny_silverhand\altjohnny_photomode.ent
24 | - base\characters\entities\player\photo_mode\goro_takemura\goro_photomode.ent
25 | - base\characters\entities\player\photo_mode\johnny_silverhand\johnny_photomode_entity.ent
26 | - base\characters\entities\player\photo_mode\kerry_eurodyne\kerry_photomode.ent
27 | - base\characters\entities\player\photo_mode\viktor_vektor\viktor_photomode.ent
28 | - ep1\characters\entities\player\photo_mode\player_ma_photomode_ep1.ent
29 | photomode_mb.ent:
30 | - base\characters\entities\player\photo_mode\jackie_welles\jackie_photomode.ent
31 | - base\characters\entities\player\photo_mode\river_ward\river_photomode.ent
32 | - ep1\characters\entities\player\photo_mode\kurt\kurt_photomode.ent
33 | - ep1\characters\entities\player\photo_mode\solomon_reed\reed_photomode.ent
34 | photomode_mm.ent:
35 | - base\characters\entities\player\photo_mode\adam_smasher\adam_smasher.ent
36 | photomode_cat.ent:
37 | - base\quest\minor_quests\mq000\characters\nibbles.ent
38 |
--------------------------------------------------------------------------------
/bundle/source/resources/PlayerBaseScope.xl:
--------------------------------------------------------------------------------
1 | resource:
2 | scope:
3 | player.ent:
4 | - player_ma.ent
5 | - player_wa.ent
6 | player_ma.ent:
7 | - base\characters\entities\player\photo_mode\player_ma_photomode.ent
8 | - base\characters\entities\player\player_ma_fpp.ent
9 | - base\characters\entities\player\player_ma_tpp.ent
10 | - base\characters\entities\player\player_ma_tpp_cutscene.ent
11 | - base\characters\entities\player\player_ma_tpp_cutscene_no_impostor.ent
12 | - base\characters\entities\player\player_ma_tpp_reflexion.ent
13 | - ep1\characters\entities\player\photo_mode\player_ma_photomode_ep1.ent
14 | - ep1\characters\entities\player\player_ma_fpp_ep1.ent
15 | - ep1\characters\entities\player\player_ma_tpp_ep1.ent
16 | player_wa.ent:
17 | - base\characters\entities\player\photo_mode\player_wa_photomode.ent
18 | - base\characters\entities\player\player_wa_fpp.ent
19 | - base\characters\entities\player\player_wa_tpp.ent
20 | - base\characters\entities\player\player_wa_tpp_cutscene.ent
21 | - base\characters\entities\player\player_wa_tpp_cutscene_no_impostor.ent
22 | - base\characters\entities\player\player_wa_tpp_reflexion.ent
23 | - ep1\characters\entities\player\photo_mode\player_wa_photomode_ep1.ent
24 | - ep1\characters\entities\player\player_wa_fpp_ep1.ent
25 | - ep1\characters\entities\player\player_wa_tpp_ep1.ent
26 |
--------------------------------------------------------------------------------
/bundle/source/resources/PlayerCustomizationBrowsPatch.xl:
--------------------------------------------------------------------------------
1 | resource:
2 | copy:
3 | base\characters\head\player_base_heads\player_female_average\heb_000_pwa__morphs.morphtarget:
4 | - archive_xl\characters\head\player_base_heads\player_female_average\heb_000_pwa__morphs.morphtarget
5 | base\characters\head\player_base_heads\player_female_average\h0_000_pwa_c__basehead\heb_000_pwa_c__basehead.mesh:
6 | - archive_xl\characters\head\player_base_heads\player_female_average\h0_000_pwa_c__basehead\heb_000_pwa_c__basehead.mesh
7 | base\characters\head\player_base_heads\player_man_average\heb_000_pma__morphs.morphtarget:
8 | - archive_xl\characters\head\player_base_heads\player_man_average\heb_000_pma__morphs.morphtarget
9 | base\characters\head\player_base_heads\player_man_average\h0_000_pma_c__basehead\heb_000_pma_c__basehead.mesh:
10 | - archive_xl\characters\head\player_base_heads\player_man_average\h0_000_pma_c__basehead\heb_000_pma_c__basehead.mesh
11 | patch:
12 | archive_xl\characters\head\player_base_heads\player_female_average\heb_000_pwa__morphs.morphtarget:
13 | props: [ blob, boundingBox, targets ]
14 | targets: [ player_wa_base_brows.morphtarget ]
15 | archive_xl\characters\head\player_base_heads\player_female_average\h0_000_pwa_c__basehead\heb_000_pwa_c__basehead.mesh:
16 | props: [ renderResourceBlob ]
17 | targets: [ player_wa_base_brows.mesh ]
18 | archive_xl\characters\head\player_base_heads\player_man_average\heb_000_pma__morphs.morphtarget:
19 | props: [ blob, boundingBox, targets ]
20 | targets: [ player_ma_base_brows.morphtarget ]
21 | archive_xl\characters\head\player_base_heads\player_man_average\h0_000_pma_c__basehead\heb_000_pma_c__basehead.mesh:
22 | props: [ renderResourceBlob ]
23 | targets: [ player_ma_base_brows.mesh ]
24 |
--------------------------------------------------------------------------------
/bundle/source/resources/PlayerCustomizationEyesPatch.xl:
--------------------------------------------------------------------------------
1 | resource:
2 | copy:
3 | base\characters\head\player_base_heads\player_female_average\he_000_pwa__morphs.morphtarget:
4 | - archive_xl\characters\head\player_base_heads\player_female_average\he_000_pwa__morphs_normal_fix.morphtarget
5 | base\characters\head\player_base_heads\player_man_average\he_000_pma__morphs.morphtarget:
6 | - archive_xl\characters\head\player_base_heads\player_man_average\he_000_pma__morphs_normal_fix.morphtarget
7 | patch:
8 | archive_xl\characters\head\player_base_heads\player_female_average\h0_000_pwa_c__basehead\he_000_pwa_c__basehead_patch.mesh:
9 | props: [ appearances ]
10 | targets: [ player_wa_base_eyes.mesh ]
11 | archive_xl\characters\head\player_base_heads\player_man_average\h0_000_pma_c__basehead\he_000_pma_c__basehead_patch.mesh:
12 | props: [ appearances ]
13 | targets: [ player_ma_base_eyes.mesh ]
14 | archive_xl\common\null.morphtarget:
15 | props: [ baseTexture, baseTextureParamName ]
16 | targets:
17 | - archive_xl\characters\head\player_base_heads\player_female_average\he_000_pwa__morphs_normal_fix.morphtarget
18 | - archive_xl\characters\head\player_base_heads\player_man_average\he_000_pma__morphs_normal_fix.morphtarget
19 |
--------------------------------------------------------------------------------
/bundle/source/resources/PlayerCustomizationEyesScope.xl:
--------------------------------------------------------------------------------
1 | resource:
2 | scope:
3 | player_customization.app:
4 | - player_ma_eyes.app
5 | - player_wa_eyes.app
6 | player_ma_eyes.app:
7 | - archive_xl\characters\head\player_base_heads\appearances\head\he_000_pma__basehead.app
8 | player_ma_eyes.morphtarget:
9 | - player_ma_base_eyes.morphtarget
10 | - archive_xl\characters\head\player_base_heads\player_man_average\he_000_pma__morphs_normal_fix.morphtarget
11 | player_ma_base_eyes.morphtarget:
12 | - base\characters\head\player_base_heads\player_man_average\he_000_pma__morphs.morphtarget
13 | player_ma_eyes.mesh:
14 | - player_ma_base_eyes.mesh
15 | player_ma_base_eyes.mesh:
16 | - base\characters\head\player_base_heads\player_man_average\h0_000_pma_c__basehead\he_000_pma_c__basehead.mesh
17 | player_wa_eyes.app:
18 | - archive_xl\characters\head\player_base_heads\appearances\head\he_000_pwa__basehead.app
19 | player_wa_eyes.morphtarget:
20 | - player_wa_base_eyes.morphtarget
21 | - archive_xl\characters\head\player_base_heads\player_female_average\he_000_pwa__morphs_normal_fix.morphtarget
22 | player_wa_base_eyes.morphtarget:
23 | - base\characters\head\player_base_heads\player_female_average\he_000_pwa__morphs.morphtarget
24 | player_wa_eyes.mesh:
25 | - player_wa_base_eyes.mesh
26 | player_wa_base_eyes.mesh:
27 | - base\characters\head\player_base_heads\player_female_average\h0_000_pwa_c__basehead\he_000_pwa_c__basehead.mesh
28 |
--------------------------------------------------------------------------------
/bundle/source/resources/PlayerCustomizationHairPatch.xl:
--------------------------------------------------------------------------------
1 | resource:
2 | patch:
3 | archive_xl\characters\common\hair\h1_base_color_patch.mesh:
4 | props: [ appearances ]
5 | targets: [ player_ma_hair.mesh, player_wa_hair.mesh ]
6 |
--------------------------------------------------------------------------------
/bundle/source/resources/PlayerCustomizationLashesPatch.xl:
--------------------------------------------------------------------------------
1 | resource:
2 | patch:
3 | archive_xl\characters\head\player_base_heads\player_female_average\h0_000_pwa_c__basehead\hel_000_pwa_c__basehead_patch.mesh:
4 | props: [ appearances ]
5 | targets: [ player_wa_base_lashes.mesh ]
6 | archive_xl\characters\head\player_base_heads\player_man_average\h0_000_pma_c__basehead\hel_000_pma_c__basehead_patch.mesh:
7 | props: [ appearances ]
8 | targets: [ player_ma_base_lashes.mesh ]
9 |
--------------------------------------------------------------------------------
/bundle/source/resources/PlayerCustomizationLashesScope.xl:
--------------------------------------------------------------------------------
1 | resource:
2 | scope:
3 | player_customization.app:
4 | - player_ma_lashes.app
5 | - player_wa_lashes.app
6 | player_ma_lashes.app:
7 | - archive_xl\characters\head\player_base_heads\appearances\head\hel_000_pma__basehead.app
8 | player_ma_lashes.morphtarget:
9 | - player_ma_base_lashes.morphtarget
10 | player_ma_base_lashes.morphtarget:
11 | - base\characters\head\player_base_heads\player_man_average\he_000_pma__morphs.morphtarget
12 | player_ma_lashes.mesh:
13 | - player_ma_base_lashes.mesh
14 | player_ma_base_lashes.mesh:
15 | - base\characters\head\player_base_heads\player_man_average\h0_000_pma_c__basehead\he_000_pma_c__basehead.mesh
16 | player_wa_lashes.app:
17 | - archive_xl\characters\head\player_base_heads\appearances\head\hel_000_pwa__basehead.app
18 | player_wa_lashes.morphtarget:
19 | - player_wa_base_lashes.morphtarget
20 | player_wa_base_lashes.morphtarget:
21 | - base\characters\head\player_base_heads\player_female_average\he_000_pwa__morphs.morphtarget
22 | player_wa_lashes.mesh:
23 | - player_wa_base_lashes.mesh
24 | player_wa_base_lashes.mesh:
25 | - base\characters\head\player_base_heads\player_female_average\h0_000_pwa_c__basehead\he_000_pwa_c__basehead.mesh
26 |
--------------------------------------------------------------------------------
/bundle/source/resources/PlayerCustomizationScope.xl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/psiberx/cp2077-archive-xl/30d36f116cb1b6d246b56cbb002696e56f9d8f3d/bundle/source/resources/PlayerCustomizationScope.xl
--------------------------------------------------------------------------------
/bundle/source/resources/QuestBaseScope.xl:
--------------------------------------------------------------------------------
1 | resource:
2 | scope:
3 | cyberpunk2077.quest:
4 | - cyberpunk2077_main.quest
5 | - cyberpunk2077_ep1.quest
6 | cyberpunk2077_main.quest:
7 | - base\quest\cyberpunk2077.quest
8 | cyberpunk2077_ep1.quest:
9 | - ep1\quest\ep1_standalone.quest
10 |
--------------------------------------------------------------------------------
/config/Project.hpp.in:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | // Generated by xmake from config/Project.hpp.in
4 |
5 | #define BUILD_SUFFIX ".${MODE}"
6 | #define DEBUG_SUFFIX ".${DEBUG}"
7 |
8 | #include
9 |
10 | namespace App::Project
11 | {
12 | constexpr auto Name = "${NAME}";
13 | constexpr auto Author = "${AUTHOR}";
14 |
15 | constexpr auto NameW = L"${NAME}";
16 | constexpr auto AuthorW = L"${AUTHOR}";
17 |
18 | constexpr auto Version = semver::from_string_noexcept("${VERSION}").value();
19 | }
20 |
--------------------------------------------------------------------------------
/config/Version.rc.in:
--------------------------------------------------------------------------------
1 | #define VER_PRODUCTVERSION ${VERSION_MAJOR},${VERSION_MINOR},${VERSION_ALTER},0
2 | #define VER_FILEVERSION ${VERSION_MAJOR},${VERSION_MINOR},${VERSION_ALTER},${VERSION_BUILD}
3 |
4 | #define VER_PRODUCTNAME_STR "${NAME}\0"
5 | #define VER_PRODUCTVERSION_STR "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_ALTER}\0"
6 | #define VER_FILEVERSION_STR "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_ALTER}.${VERSION_BUILD}\0"
7 |
8 | 1 VERSIONINFO
9 | FILEVERSION VER_FILEVERSION
10 | PRODUCTVERSION VER_PRODUCTVERSION
11 | FILEFLAGSMASK 0x17L
12 | FILEFLAGS 0x0L
13 | FILEOS 0x4L
14 | FILETYPE 0x2L
15 | FILESUBTYPE 0x0L
16 | BEGIN
17 | BLOCK "StringFileInfo"
18 | BEGIN
19 | BLOCK "040904b0"
20 | BEGIN
21 | VALUE "CompanyName", "\0"
22 | VALUE "FileDescription", "\0"
23 | VALUE "FileVersion", VER_FILEVERSION_STR
24 | VALUE "InternalName", "\0"
25 | VALUE "LegalCopyright", "\0"
26 | VALUE "LegalTrademarks1", "\0"
27 | VALUE "LegalTrademarks2", "\0"
28 | VALUE "OriginalFilename", "\0"
29 | VALUE "ProductName", VER_PRODUCTNAME_STR
30 | VALUE "ProductVersion", VER_PRODUCTVERSION_STR
31 | END
32 | END
33 | BLOCK "VarFileInfo"
34 | BEGIN
35 | VALUE "Translation", 0x409, 1200
36 | END
37 | END
38 |
--------------------------------------------------------------------------------
/lib/Core/Container/Container.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Core/Stl.hpp"
4 |
5 | namespace Core
6 | {
7 | class Container
8 | {
9 | public:
10 | template
11 | inline static void Set(const Core::SharedPtr& aInstance)
12 | {
13 | Resolver::Assign(aInstance);
14 | }
15 |
16 | template
17 | inline static Core::SharedPtr Get()
18 | {
19 | return Resolver::Retrieve().lock();
20 | }
21 |
22 | template
23 | inline static bool Has()
24 | {
25 | return !Resolver::Retrieve().expired();
26 | }
27 |
28 | private:
29 | template
30 | struct Resolver
31 | {
32 | inline static void Assign(const Core::SharedPtr& aInstance)
33 | {
34 | s_instance = aInstance;
35 | }
36 |
37 | inline static Core::WeakPtr& Retrieve()
38 | {
39 | return s_instance;
40 | }
41 |
42 | inline static Core::WeakPtr s_instance;
43 | };
44 | };
45 | }
--------------------------------------------------------------------------------
/lib/Core/Container/Registry.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Core/Container/Container.hpp"
4 | #include "Core/Stl.hpp"
5 |
6 | namespace Core
7 | {
8 | template
9 | class RegistryProxy;
10 |
11 | template
12 | class Registry
13 | {
14 | public:
15 | template
16 | requires std::is_base_of_v
17 | T& Register(Args&&... aArgs)
18 | {
19 | auto registrable = Core::MakeShared(std::forward(aArgs)...);
20 | m_registered.push_back(registrable);
21 | Container::Set(registrable);
22 |
23 | if constexpr (std::is_base_of_v, T>)
24 | {
25 | registrable->SetParent(*this);
26 | }
27 |
28 | OnRegistered(registrable);
29 |
30 | return *registrable.get();
31 | }
32 |
33 | protected:
34 | using TraverseFunc = void (*)(const Core::SharedPtr&);
35 |
36 | void ForEach(TraverseFunc aTraverse) const
37 | {
38 | std::for_each(m_registered.begin(), m_registered.end(), aTraverse);
39 | }
40 |
41 | const Core::Vector>& GetRegistered() const
42 | {
43 | return m_registered;
44 | }
45 |
46 | template
47 | inline static Core::SharedPtr Resolve()
48 | {
49 | return Container::Get();
50 | }
51 |
52 | template
53 | inline static bool Resolvable()
54 | {
55 | return Container::Get();
56 | }
57 |
58 | virtual void OnRegistered(const Core::SharedPtr& aRegistred) {}
59 |
60 | private:
61 | Core::Vector> m_registered;
62 | };
63 |
64 | template
65 | class RegistryProxy
66 | {
67 | protected:
68 | template
69 | requires std::is_base_of_v
70 | T& Register(Args&&... aArgs)
71 | {
72 | assert(m_parent);
73 | return m_parent->template Register(std::forward(aArgs)...);
74 | }
75 |
76 | template
77 | requires std::is_base_of_v
78 | T& Register(Core::SharedPtr aFeature)
79 | {
80 | assert(m_parent);
81 | return m_parent->Register(std::forward(aFeature));
82 | }
83 |
84 | private:
85 | friend class Registry;
86 |
87 | void SetParent(Registry& aParent)
88 | {
89 | m_parent = &aParent;
90 | }
91 |
92 | Registry* m_parent{ nullptr };
93 | };
94 | }
95 |
--------------------------------------------------------------------------------
/lib/Core/Facades/Container.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Core/Container/Container.hpp"
4 |
5 | namespace Core
6 | {
7 | template
8 | inline Core::SharedPtr Resolve()
9 | {
10 | return Container::Get();
11 | }
12 |
13 | template
14 | inline bool Resolvable()
15 | {
16 | return Container::Get();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/lib/Core/Facades/Log.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Core/Logging/LoggingDriver.hpp"
4 |
5 | namespace Core::Log
6 | {
7 | inline void Info(const std::string_view& aMessage)
8 | {
9 | LoggingDriver::GetDefault().LogInfo(aMessage);
10 | }
11 |
12 | inline void Warning(const std::string_view& aMessage)
13 | {
14 | LoggingDriver::GetDefault().LogWarning(aMessage);
15 | }
16 |
17 | inline void Error(const std::string_view& aMessage)
18 | {
19 | LoggingDriver::GetDefault().LogError(aMessage);
20 | }
21 |
22 | inline void Debug(const std::string_view& aMessage)
23 | {
24 | LoggingDriver::GetDefault().LogDebug(aMessage);
25 | }
26 |
27 | template
28 | constexpr void Info(std::format_string aFormat, Args&&... aArgs)
29 | {
30 | LoggingDriver::GetDefault().LogInfo(std::format(aFormat, std::forward(aArgs)...));
31 | }
32 |
33 | template
34 | constexpr void Warning(std::format_string aFormat, Args&&... aArgs)
35 | {
36 | LoggingDriver::GetDefault().LogWarning(std::format(aFormat, std::forward(aArgs)...));
37 | }
38 |
39 | template
40 | constexpr void Error(std::format_string aFormat, Args&&... aArgs)
41 | {
42 | LoggingDriver::GetDefault().LogError(std::format(aFormat, std::forward(aArgs)...));
43 | }
44 |
45 | template
46 | constexpr void Debug(std::format_string aFormat, Args&&... aArgs)
47 | {
48 | LoggingDriver::GetDefault().LogDebug(std::format(aFormat, std::forward(aArgs)...));
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/lib/Core/Facades/Runtime.cpp:
--------------------------------------------------------------------------------
1 | #include "Runtime.hpp"
2 | #include "Core/Stl.hpp"
3 |
4 | namespace
5 | {
6 | Core::UniquePtr s_host;
7 | Core::UniquePtr s_module;
8 | }
9 |
10 | void Core::Runtime::Initialize(const Core::HostImage& aHost, const Core::ModuleImage& aModule)
11 | {
12 | s_host = Core::MakeUnique(aHost);
13 | s_module = Core::MakeUnique(aModule);
14 | }
15 |
16 | Core::HostImage* Core::Runtime::GetHost()
17 | {
18 | return s_host.get();
19 | }
20 |
21 | Core::ModuleImage* Core::Runtime::GetModule()
22 | {
23 | return s_module.get();
24 | }
25 |
26 | uintptr_t Core::Runtime::GetImageBase()
27 | {
28 | assert(s_host);
29 | return s_host->GetBase();
30 | }
31 |
32 | std::filesystem::path Core::Runtime::GetImagePath()
33 | {
34 | assert(s_host);
35 | return s_host->GetPath();
36 | }
37 |
38 | std::filesystem::path Core::Runtime::GetRootDir()
39 | {
40 | assert(s_host);
41 | return s_host->GetRootDir();
42 | }
43 |
44 | std::filesystem::path Core::Runtime::GetModulePath()
45 | {
46 | assert(s_module);
47 | return s_module->GetPath();
48 | }
49 |
50 | std::filesystem::path Core::Runtime::GetModuleDir()
51 | {
52 | assert(s_module);
53 | return s_module->GetDir();
54 | }
55 |
56 | std::string Core::Runtime::GetModuleName()
57 | {
58 | assert(s_module);
59 | return s_module->GetName();
60 | }
61 |
62 | bool Core::Runtime::IsASI()
63 | {
64 | assert(s_module);
65 | return s_module->IsASI();
66 | }
67 |
68 | bool Core::Runtime::IsASI(HMODULE aHandle)
69 | {
70 | return Core::ModuleImage(aHandle).IsASI();
71 | }
72 |
73 | bool Core::Runtime::IsEXE(std::wstring_view aName)
74 | {
75 | if (s_host)
76 | return s_host->GetPath().filename() == aName;
77 |
78 | return Core::HostImage().GetPath().filename() == aName;
79 | }
80 |
--------------------------------------------------------------------------------
/lib/Core/Facades/Runtime.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Core/Runtime/HostImage.hpp"
4 | #include "Core/Runtime/ModuleImage.hpp"
5 |
6 | namespace Core::Runtime
7 | {
8 | void Initialize(const Core::HostImage& aHost, const Core::ModuleImage& aModule);
9 |
10 | HostImage* GetHost();
11 | ModuleImage* GetModule();
12 |
13 | [[nodiscard]] uintptr_t GetImageBase();
14 | [[nodiscard]] std::filesystem::path GetImagePath();
15 | [[nodiscard]] std::filesystem::path GetRootDir();
16 | [[nodiscard]] std::filesystem::path GetModulePath();
17 | [[nodiscard]] std::filesystem::path GetModuleDir();
18 | [[nodiscard]] std::string GetModuleName();
19 | [[nodiscard]] bool IsASI();
20 | [[nodiscard]] bool IsASI(HMODULE aHandle);
21 | [[nodiscard]] bool IsEXE(std::wstring_view aName);
22 | }
23 |
--------------------------------------------------------------------------------
/lib/Core/Foundation/Application.cpp:
--------------------------------------------------------------------------------
1 | #include "Application.hpp"
2 |
3 | void Core::Application::Bootstrap()
4 | {
5 | if (m_booted)
6 | return;
7 |
8 | if (!s_discoveryCallbacks.empty())
9 | {
10 | for (const auto& callback : s_discoveryCallbacks)
11 | {
12 | callback(*this);
13 | }
14 | s_discoveryCallbacks.clear();
15 | }
16 |
17 | m_booted = true;
18 |
19 | OnStarting();
20 |
21 | for (const auto& feature : GetRegistered())
22 | {
23 | feature->OnBootstrap();
24 | }
25 |
26 | OnStarted();
27 | }
28 |
29 | void Core::Application::Shutdown()
30 | {
31 | if (!m_booted)
32 | return;
33 |
34 | OnStopping();
35 |
36 | for (const auto& feature : GetRegistered())
37 | {
38 | feature->OnShutdown();
39 | }
40 |
41 | OnStopped();
42 |
43 | m_booted = false;
44 | }
45 |
46 | void Core::Application::OnRegistered(const SharedPtr& aFeature)
47 | {
48 | aFeature->OnRegister();
49 |
50 | if (m_booted)
51 | {
52 | aFeature->OnBootstrap();
53 | }
54 | }
55 |
56 | bool Core::Application::Discover(AutoDiscoveryCallback aCallback)
57 | {
58 | s_discoveryCallbacks.push_back(aCallback);
59 | return true;
60 | }
61 |
--------------------------------------------------------------------------------
/lib/Core/Foundation/Application.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Core/Container/Registry.hpp"
4 | #include "Core/Foundation/Feature.hpp"
5 | #include "Core/Stl.hpp"
6 |
7 | namespace Core
8 | {
9 | using AutoDiscoveryCallback = void(*)(Application&);
10 |
11 | class Application : public Registry
12 | {
13 | public:
14 | template
15 | Feature::Defer Register(Args&&... aArgs)
16 | {
17 | return Registry::Register(std::forward(aArgs)...);
18 | }
19 |
20 | void Bootstrap();
21 | void Shutdown();
22 |
23 | static bool Discover(AutoDiscoveryCallback aCallback);
24 |
25 | protected:
26 | void OnRegistered(const SharedPtr& aFeature) override;
27 |
28 | virtual void OnStarting() {};
29 | virtual void OnStarted() {};
30 | virtual void OnStopping() {};
31 | virtual void OnStopped() {};
32 |
33 | private:
34 | bool m_booted = false;
35 |
36 | inline static Vector s_discoveryCallbacks;
37 | };
38 | }
39 |
--------------------------------------------------------------------------------
/lib/Core/Foundation/Feature.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Core/Container/Registry.hpp"
4 |
5 | namespace Core
6 | {
7 | class Application;
8 |
9 | class Feature : public RegistryProxy
10 | {
11 | public:
12 | Feature() = default;
13 | virtual ~Feature() = default;
14 |
15 | Feature(Feature&& aOther) = delete;
16 | Feature(const Feature& aOther) = delete;
17 |
18 | protected:
19 | friend class Application;
20 | friend class Registry;
21 |
22 | virtual void OnRegister() {};
23 | virtual void OnInitialize() {};
24 | virtual void OnBootstrap() {};
25 | virtual void OnShutdown() {};
26 |
27 | template
28 | requires std::is_base_of_v
29 | class Defer
30 | {
31 | public:
32 | inline Defer(T& aTarget)
33 | : m_instance(aTarget)
34 | {
35 | ++m_instance.m_deferChain;
36 | }
37 |
38 | inline Defer(T* aTarget)
39 | : m_instance(*aTarget)
40 | {
41 | ++m_instance.m_deferChain;
42 | }
43 |
44 | inline ~Defer()
45 | {
46 | if (--m_instance.m_deferChain == 0)
47 | {
48 | static_cast(m_instance).OnInitialize();
49 | }
50 | }
51 |
52 | [[nodiscard]] inline T* operator->() const
53 | {
54 | return &m_instance;
55 | }
56 |
57 | private:
58 | T& m_instance;
59 | };
60 |
61 | private:
62 | uint8_t m_deferChain = 0;
63 | };
64 | }
65 |
--------------------------------------------------------------------------------
/lib/Core/Foundation/LocaleProvider.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Core/Foundation/Feature.hpp"
4 |
5 | namespace Core
6 | {
7 | class LocaleProvider : public Feature
8 | {
9 | public:
10 | LocaleProvider(const char* aLocale = "en_US.UTF-8")
11 | {
12 | std::setlocale(LC_ALL, aLocale);
13 | }
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/lib/Core/Foundation/RuntimeProvider.cpp:
--------------------------------------------------------------------------------
1 | #include "RuntimeProvider.hpp"
2 | #include "Core/Facades/Runtime.hpp"
3 |
4 | Core::RuntimeProvider::RuntimeProvider(HMODULE aHandle) noexcept
5 | : m_handle(aHandle)
6 | , m_basePathDepth(0)
7 | {
8 | }
9 |
10 | void Core::RuntimeProvider::OnInitialize()
11 | {
12 | Runtime::Initialize(HostImage(m_basePathDepth), ModuleImage(m_handle));
13 | }
14 |
--------------------------------------------------------------------------------
/lib/Core/Foundation/RuntimeProvider.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Core/Foundation/Feature.hpp"
4 | #include "Core/Win.hpp"
5 |
6 | namespace Core
7 | {
8 | class RuntimeProvider : public Feature
9 | {
10 | public:
11 | explicit RuntimeProvider(HMODULE aHandle) noexcept;
12 |
13 | auto SetBaseImagePathDepth(int aDepth) noexcept
14 | {
15 | m_basePathDepth = aDepth;
16 | return Defer(this);
17 | }
18 |
19 | protected:
20 | void OnInitialize() override;
21 |
22 | HMODULE m_handle;
23 | int m_basePathDepth;
24 | };
25 | }
26 |
--------------------------------------------------------------------------------
/lib/Core/Hooking/HookingAgent.cpp:
--------------------------------------------------------------------------------
1 | #include "HookingAgent.hpp"
2 |
3 | #include
4 |
5 | namespace
6 | {
7 | Core::HookingDriver* s_driver;
8 | }
9 |
10 | void Core::HookingAgent::SetHookingDriver(Core::HookingDriver& aDriver)
11 | {
12 | s_driver = &aDriver;
13 | }
14 |
15 | Core::HookingDriver& Core::HookingAgent::GetHookingDriver()
16 | {
17 | assert(s_driver);
18 | return *s_driver;
19 | }
20 |
--------------------------------------------------------------------------------
/lib/Core/Hooking/HookingDriver.cpp:
--------------------------------------------------------------------------------
1 | #include "HookingDriver.hpp"
2 | #include "HookingAgent.hpp"
3 |
4 | #include
5 |
6 | namespace
7 | {
8 | Core::HookingDriver* s_default;
9 | }
10 |
11 | void Core::HookingDriver::SetDefault(Core::HookingDriver& aDriver)
12 | {
13 | s_default = &aDriver;
14 |
15 | HookingAgent::SetHookingDriver(aDriver);
16 | }
17 |
18 | Core::HookingDriver& Core::HookingDriver::GetDefault()
19 | {
20 | assert(s_default);
21 | return *s_default;
22 | }
23 |
--------------------------------------------------------------------------------
/lib/Core/Hooking/HookingDriver.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace Core
4 | {
5 | class HookingDriver
6 | {
7 | public:
8 | virtual bool HookAttach(uintptr_t aAddress, void* aCallback) = 0;
9 | virtual bool HookAttach(uintptr_t aAddress, void* aCallback, void** aOriginal) = 0;
10 | virtual bool HookDetach(uintptr_t aAddress) = 0;
11 |
12 | static void SetDefault(HookingDriver& aDriver);
13 | static HookingDriver& GetDefault();
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/lib/Core/Logging/LoggingAgent.cpp:
--------------------------------------------------------------------------------
1 | #include "LoggingAgent.hpp"
2 |
3 | #include
4 |
5 | namespace
6 | {
7 | Core::LoggingDriver* s_driver;
8 | }
9 |
10 | void Core::LoggingAgent::SetDriver(Core::LoggingDriver& aDriver)
11 | {
12 | s_driver = &aDriver;
13 | }
14 |
15 | Core::LoggingDriver& Core::LoggingAgent::GetLoggingDriver()
16 | {
17 | assert(s_driver);
18 | return *s_driver;
19 | }
20 |
21 | void Core::LoggingAgent::LogFlush()
22 | {
23 | s_driver->LogFlush();
24 | }
25 |
--------------------------------------------------------------------------------
/lib/Core/Logging/LoggingAgent.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "LoggingDriver.hpp"
4 |
5 | namespace Core
6 | {
7 | class LoggingAgent
8 | {
9 | protected:
10 | inline static void LogInfo(const char* aMessage)
11 | {
12 | GetLoggingDriver().LogInfo(aMessage);
13 | }
14 |
15 | inline static void LogWarning(const char* aMessage)
16 | {
17 | GetLoggingDriver().LogWarning(aMessage);
18 | }
19 |
20 | inline static void LogError(const char* aMessage)
21 | {
22 | GetLoggingDriver().LogError(aMessage);
23 | }
24 |
25 | inline static void LogDebug(const char* aMessage)
26 | {
27 | GetLoggingDriver().LogDebug(aMessage);
28 | }
29 |
30 | template
31 | inline static constexpr void LogInfo(std::format_string aFormat, Args&&... aArgs)
32 | {
33 | GetLoggingDriver().LogInfo(aFormat, std::forward(aArgs)...);
34 | }
35 |
36 | template
37 | inline static constexpr void LogWarning(std::format_string aFormat, Args&&... aArgs)
38 | {
39 | GetLoggingDriver().LogWarning(std::format(aFormat, std::forward(aArgs)...));
40 | }
41 |
42 | template
43 | inline static constexpr void LogError(std::format_string aFormat, Args&&... aArgs)
44 | {
45 | GetLoggingDriver().LogError(std::format(aFormat, std::forward(aArgs)...));
46 | }
47 |
48 | template
49 | inline static constexpr void LogDebug(std::format_string aFormat, Args&&... aArgs)
50 | {
51 | GetLoggingDriver().LogDebug(std::format(aFormat, std::forward(aArgs)...));
52 | }
53 |
54 | static void LogFlush();
55 |
56 | static LoggingDriver& GetLoggingDriver();
57 |
58 | private:
59 | friend LoggingDriver;
60 |
61 | static void SetDriver(LoggingDriver& aDriver);
62 | };
63 | }
64 |
--------------------------------------------------------------------------------
/lib/Core/Logging/LoggingDriver.cpp:
--------------------------------------------------------------------------------
1 | #include "LoggingDriver.hpp"
2 | #include "LoggingAgent.hpp"
3 |
4 | #include
5 |
6 | namespace
7 | {
8 | Core::LoggingDriver* s_default;
9 | }
10 |
11 | void Core::LoggingDriver::SetDefault(LoggingDriver& aDriver)
12 | {
13 | s_default = &aDriver;
14 |
15 | LoggingAgent::SetDriver(aDriver);
16 | }
17 |
18 | Core::LoggingDriver& Core::LoggingDriver::GetDefault()
19 | {
20 | assert(s_default);
21 | return *s_default;
22 | }
23 |
--------------------------------------------------------------------------------
/lib/Core/Logging/LoggingDriver.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace Core
4 | {
5 | class LoggingDriver
6 | {
7 | public:
8 | virtual void LogInfo(const std::string_view& aMessage) = 0;
9 | virtual void LogWarning(const std::string_view& aMessage) = 0;
10 | virtual void LogError(const std::string_view& aMessage) = 0;
11 | virtual void LogDebug(const std::string_view& aMessage) = 0;
12 | virtual void LogFlush() = 0;
13 |
14 | template
15 | constexpr void LogInfo(std::format_string aFormat, Args&&... aArgs)
16 | {
17 | LogInfo(std::format(aFormat, std::forward(aArgs)...));
18 | }
19 |
20 | template
21 | constexpr void LogWarning(std::format_string aFormat, Args&&... aArgs)
22 | {
23 | LogWarning(std::format(aFormat, std::forward(aArgs)...));
24 | }
25 |
26 | template
27 | constexpr void LogError(std::format_string aFormat, Args&&... aArgs)
28 | {
29 | LogError(std::format(aFormat, std::forward(aArgs)...));
30 | }
31 |
32 | template
33 | constexpr void LogDebug(std::format_string aFormat, Args&&... aArgs)
34 | {
35 | LogDebug(std::format(aFormat, std::forward(aArgs)...));
36 | }
37 |
38 | static void SetDefault(LoggingDriver& aDriver);
39 | static LoggingDriver& GetDefault();
40 | };
41 | }
42 |
--------------------------------------------------------------------------------
/lib/Core/Memory/AddressResolver.cpp:
--------------------------------------------------------------------------------
1 | #include "AddressResolver.hpp"
2 |
3 | #include
4 |
5 | namespace
6 | {
7 | Core::AddressResolver* s_default;
8 | }
9 |
10 | void Core::AddressResolver::SetDefault(Core::AddressResolver& aResolver)
11 | {
12 | s_default = &aResolver;
13 | }
14 |
15 | Core::AddressResolver& Core::AddressResolver::GetDefault()
16 | {
17 | assert(s_default);
18 | return *s_default;
19 | }
20 |
--------------------------------------------------------------------------------
/lib/Core/Memory/AddressResolver.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace Core
4 | {
5 | class AddressResolver
6 | {
7 | public:
8 | virtual uintptr_t ResolveAddress(uint32_t aAddressID) = 0;
9 |
10 | static void SetDefault(AddressResolver& aResolver);
11 | static AddressResolver& GetDefault();
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/lib/Core/Runtime/HostImage.cpp:
--------------------------------------------------------------------------------
1 | #include "HostImage.hpp"
2 | #include "Core/Win.hpp"
3 |
4 | Core::HostImage::HostImage(int aExePathDepth)
5 | {
6 | const auto handle = GetModuleHandleW(nullptr);
7 |
8 | m_base = reinterpret_cast(handle);
9 |
10 | std::wstring filePath;
11 | wil::GetModuleFileNameW(handle, filePath);
12 |
13 | m_exe = filePath;
14 | m_root = m_exe.parent_path();
15 |
16 | while (--aExePathDepth >= 0)
17 | m_root = m_root.parent_path();
18 |
19 | TryResolveVersion(filePath);
20 | }
21 |
22 | uintptr_t Core::HostImage::GetBase() const
23 | {
24 | return m_base;
25 | }
26 |
27 | std::filesystem::path Core::HostImage::GetPath() const
28 | {
29 | return m_exe;
30 | }
31 |
32 | std::string Core::HostImage::GetName() const
33 | {
34 | return m_exe.stem().string();
35 | }
36 |
37 | std::filesystem::path Core::HostImage::GetRootDir() const
38 | {
39 | return m_root;
40 | }
41 |
42 | const Core::FileVer& Core::HostImage::GetFileVer() const
43 | {
44 | return m_fileVer;
45 | }
46 |
47 | const Core::SemvVer& Core::HostImage::GetProductVer() const
48 | {
49 | return m_productVer;
50 | }
51 |
52 | bool Core::HostImage::TryResolveVersion(const std::wstring& filePath)
53 | {
54 | auto size = GetFileVersionInfoSizeW(filePath.c_str(), nullptr);
55 | if (!size)
56 | return false;
57 |
58 | std::unique_ptr data(new (std::nothrow) uint8_t[size]());
59 | if (!data)
60 | return false;
61 |
62 | if (!GetFileVersionInfoW(filePath.c_str(), 0, size, data.get()))
63 | return false;
64 |
65 | VS_FIXEDFILEINFO* fileInfo = nullptr;
66 | UINT fileInfoBytes;
67 |
68 | if (!VerQueryValueW(data.get(), L"\\", reinterpret_cast(&fileInfo), &fileInfoBytes))
69 | return false;
70 |
71 | constexpr auto signature = 0xFEEF04BD;
72 | if (fileInfo->dwSignature != signature)
73 | return false;
74 |
75 | m_fileVer.major = (fileInfo->dwFileVersionMS >> 16) & 0xFF;
76 | m_fileVer.minor = fileInfo->dwFileVersionMS & 0xFFFF;
77 | m_fileVer.build = (fileInfo->dwFileVersionLS >> 16) & 0xFFFF;
78 | m_fileVer.revision = fileInfo->dwFileVersionLS & 0xFFFF;
79 |
80 | m_productVer.major = (fileInfo->dwProductVersionMS >> 16) & 0xFF;
81 | m_productVer.minor = fileInfo->dwProductVersionMS & 0xFFFF;
82 | m_productVer.patch = (fileInfo->dwProductVersionLS >> 16) & 0xFFFF;
83 |
84 | return true;
85 | }
86 |
--------------------------------------------------------------------------------
/lib/Core/Runtime/HostImage.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace Core
4 | {
5 | struct FileVer
6 | {
7 | uint16_t major;
8 | uint16_t minor;
9 | uint16_t build;
10 | uint16_t revision;
11 | };
12 |
13 | struct SemvVer
14 | {
15 | uint16_t major;
16 | uint16_t minor;
17 | uint32_t patch;
18 | };
19 |
20 | class HostImage
21 | {
22 | public:
23 | explicit HostImage(int32_t aExePathDepth = 0);
24 | ~HostImage() = default;
25 |
26 | [[nodiscard]] uintptr_t GetBase() const;
27 | [[nodiscard]] std::filesystem::path GetPath() const;
28 | [[nodiscard]] std::string GetName() const;
29 | [[nodiscard]] std::filesystem::path GetRootDir() const;
30 |
31 | [[nodiscard]] const FileVer& GetFileVer() const;
32 | [[nodiscard]] const SemvVer& GetProductVer() const;
33 |
34 | private:
35 | bool TryResolveVersion(const std::wstring& aFilePath);
36 |
37 | uintptr_t m_base;
38 | std::filesystem::path m_exe;
39 | std::filesystem::path m_root;
40 | FileVer m_fileVer{};
41 | SemvVer m_productVer{};
42 | };
43 | }
44 |
--------------------------------------------------------------------------------
/lib/Core/Runtime/ModuleImage.cpp:
--------------------------------------------------------------------------------
1 | #include "ModuleImage.hpp"
2 |
3 | Core::ModuleImage::ModuleImage(HMODULE aHandle)
4 | {
5 | std::wstring filePath;
6 | wil::GetModuleFileNameW(aHandle, filePath);
7 |
8 | m_path = filePath;
9 | }
10 |
11 | std::filesystem::path Core::ModuleImage::GetPath() const
12 | {
13 | return m_path;
14 | }
15 |
16 | std::filesystem::path Core::ModuleImage::GetDir() const
17 | {
18 | return m_path.parent_path();
19 | }
20 |
21 | std::string Core::ModuleImage::GetName() const
22 | {
23 | return m_path.stem().string();
24 | }
25 |
26 | bool Core::ModuleImage::IsASI() const
27 | {
28 | return m_path.extension() == L".asi";
29 | }
30 |
--------------------------------------------------------------------------------
/lib/Core/Runtime/ModuleImage.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Core/Win.hpp"
4 |
5 | namespace Core
6 | {
7 | class ModuleImage
8 | {
9 | public:
10 | explicit ModuleImage(HMODULE aHandle);
11 | ~ModuleImage() = default;
12 |
13 | [[nodiscard]] std::filesystem::path GetPath() const;
14 | [[nodiscard]] std::filesystem::path GetDir() const;
15 | [[nodiscard]] std::string GetName() const;
16 | [[nodiscard]] bool IsASI() const;
17 |
18 | private:
19 | std::filesystem::path m_path;
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/lib/Core/Runtime/OwnerMutex.cpp:
--------------------------------------------------------------------------------
1 | #include "OwnerMutex.hpp"
2 |
3 | Core::OwnerMutex::OwnerMutex(std::string_view aName)
4 | : m_aname(aName)
5 | , m_mutex(nullptr)
6 | {
7 | }
8 |
9 | Core::OwnerMutex::OwnerMutex(std::wstring_view aName)
10 | : m_wname(aName)
11 | , m_mutex(nullptr)
12 | {
13 | }
14 |
15 | Core::OwnerMutex::~OwnerMutex()
16 | {
17 | Release();
18 | }
19 |
20 | bool Core::OwnerMutex::Obtain()
21 | {
22 | const auto mutex = !m_wname.empty()
23 | ? CreateMutexW(NULL, TRUE, m_wname.data())
24 | : CreateMutexA(NULL, TRUE, m_aname.data());
25 |
26 | if (!mutex)
27 | return false;
28 |
29 | if (GetLastError() == ERROR_ALREADY_EXISTS)
30 | {
31 | ReleaseMutex(mutex);
32 | return false;
33 | }
34 |
35 | m_mutex = mutex;
36 |
37 | return true;
38 | }
39 |
40 | bool Core::OwnerMutex::Release()
41 | {
42 | if (!m_mutex)
43 | return false;
44 |
45 | ReleaseMutex(m_mutex);
46 | m_mutex = nullptr;
47 |
48 | return true;
49 | }
50 |
51 | bool Core::OwnerMutex::IsOwner()
52 | {
53 | return m_mutex;
54 | }
55 |
--------------------------------------------------------------------------------
/lib/Core/Runtime/OwnerMutex.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Core/Win.hpp"
4 |
5 | namespace Core
6 | {
7 | class OwnerMutex
8 | {
9 | public:
10 | explicit OwnerMutex(std::string_view aName);
11 | explicit OwnerMutex(std::wstring_view aName);
12 | ~OwnerMutex();
13 |
14 | bool Obtain();
15 | bool Release();
16 | bool IsOwner();
17 |
18 | private:
19 | std::string_view m_aname;
20 | std::wstring_view m_wname;
21 | HANDLE m_mutex;
22 | };
23 | }
24 |
--------------------------------------------------------------------------------
/lib/Core/Stl.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | namespace Core
8 | {
9 | // Pretty much the same as TiltedCore with StlAllocator,
10 | // but unique ptr allows implicit casting to the base.
11 |
12 | namespace Detail
13 | {
14 | template
15 | struct UniqueDeleter
16 | {
17 | constexpr UniqueDeleter() noexcept = default;
18 |
19 | template
20 | requires std::is_base_of_v
21 | UniqueDeleter(const UniqueDeleter& d) noexcept {}
22 |
23 | void operator()(std::conditional_t, T, T*> aData)
24 | {
25 | TiltedPhoques::Delete(aData);
26 | }
27 | };
28 | }
29 |
30 | template
31 | using Vector = std::vector>;
32 |
33 | template
34 | using Set = tsl::hopscotch_set, std::equal_to, TiltedPhoques::StlAllocator>;
35 |
36 | template
37 | using Map = tsl::hopscotch_map, std::equal_to, TiltedPhoques::StlAllocator>>;
38 |
39 | template
40 | using SortedMap = std::map, TiltedPhoques::StlAllocator>>;
41 |
42 | // TODO: OrderedMap
43 |
44 | template
45 | using SharedPtr = std::shared_ptr;
46 |
47 | template
48 | using WeakPtr = std::weak_ptr;
49 |
50 | template
51 | using UniquePtr = std::unique_ptr>;
52 |
53 | template
54 | struct ShareFromThis : public std::enable_shared_from_this
55 | {
56 | SharedPtr ToShared()
57 | {
58 | return std::enable_shared_from_this::shared_from_this();
59 | }
60 |
61 | WeakPtr ToWeak()
62 | {
63 | return std::enable_shared_from_this::weak_from_this();
64 | }
65 | };
66 |
67 | template
68 | auto MakeShared(Args&&... aArgs)
69 | {
70 | return std::allocate_shared(TiltedPhoques::StlAllocator(), std::forward(aArgs)...);
71 | }
72 |
73 | template
74 | auto MakeUnique(Args&&... aArgs)
75 | {
76 | return UniquePtr(TiltedPhoques::New(std::forward(aArgs)...));
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/lib/Core/Win.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #ifndef WIN32_LEAN_AND_MEAN
4 | #define WIN32_LEAN_AND_MEAN
5 | #endif
6 | #ifndef NOMINMAX
7 | #define NOMINMAX
8 | #endif
9 |
10 | #include
11 | #include
12 |
--------------------------------------------------------------------------------
/lib/Red/Alias.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace Red
4 | {
5 | using namespace RED4ext;
6 | }
7 |
8 | namespace Red::Detail
9 | {
10 | using namespace RED4ext::Detail;
11 | }
12 |
--------------------------------------------------------------------------------
/lib/Red/Engine.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "TypeInfo/Resolving.hpp"
4 | #include "TypeInfo/Parameters.hpp"
5 |
6 | #include "Engine/Framework.hpp"
7 | #include "Engine/LogChannel.hpp"
8 |
9 | #include "Engine/Mappings.hpp"
10 |
--------------------------------------------------------------------------------
/lib/Red/Engine/Framework.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Macros/Framework.hpp"
4 |
5 | namespace Red
6 | {
7 | template
8 | struct RuntimeSystemMapping : public std::false_type {};
9 |
10 | namespace Detail
11 | {
12 | template
13 | concept HasRuntimeSystemMapping = RuntimeSystemMapping::value
14 | && RuntimeSystemMapping::offset >= 0
15 | && RuntimeSystemMapping::offset <= 64;
16 | }
17 |
18 | template
19 | requires std::is_base_of_v && std::is_base_of_v
20 | U* GetGameSystem()
21 | {
22 | static const auto s_type = GetType();
23 | auto& gameInstance = CGameEngine::Get()->framework->gameInstance;
24 | return reinterpret_cast(gameInstance->GetSystem(s_type));
25 | }
26 |
27 | template
28 | requires std::is_base_of_v && std::is_base_of_v && Detail::HasRuntimeSystemMapping
29 | U* GetRuntimeSystem()
30 | {
31 | constexpr auto systemOffset = RuntimeSystemMapping::offset * sizeof(Handle);
32 | const auto& runtimeSceneAddr = CGameEngine::Get()->framework->unk18;
33 | return reinterpret_cast*>(runtimeSceneAddr + systemOffset)->instance;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/Red/Engine/LogChannel.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace Red::Log
4 | {
5 | inline void Channel(CName aChannel, const CString& aMessage)
6 | {
7 | static auto* s_rtti = CRTTISystem::Get();
8 | static auto* s_logFunc = s_rtti->GetFunction("LogChannel");
9 | static auto* s_stringType = s_rtti->GetType("String");
10 | static auto* s_stringRefType = s_rtti->GetType("script_ref:String");
11 | static auto* s_nameType = s_rtti->GetType("CName");
12 |
13 | ScriptRef messageRef;
14 | messageRef.type = s_stringType;
15 | messageRef.name = s_stringType->GetName();
16 | messageRef.ref = const_cast(&aMessage);
17 |
18 | StackArgs_t args;
19 | args.emplace_back(s_nameType, &aChannel);
20 | args.emplace_back(s_stringRefType, &messageRef);
21 |
22 | CStack stack(nullptr, args.data(), static_cast(args.size()), nullptr);
23 |
24 | s_logFunc->Execute(&stack);
25 | }
26 |
27 | inline void Channel(Red::CName aChannel, const std::string& aMessage)
28 | {
29 | Channel(aChannel, Red::CString(aMessage.c_str()));
30 | }
31 |
32 | template
33 | constexpr void Channel(CName aChannel, std::format_string aFormat, Args&&... aArgs)
34 | {
35 | Channel(aChannel, std::format(aFormat, std::forward(aArgs)...));
36 | }
37 |
38 | template
39 | constexpr void Debug(std::format_string aFormat, Args&&... aArgs)
40 | {
41 | Channel("DEBUG", std::format(aFormat, std::forward(aArgs)...));
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/Red/Engine/Macros/Framework.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define RTTI_MAP_RUNTIME_SYSTEM(_type, _offset) \
4 | template<> \
5 | struct Red::RuntimeSystemMapping<_type> : public std::true_type \
6 | { \
7 | static constexpr auto offset = _offset; \
8 | };
9 |
--------------------------------------------------------------------------------
/lib/Red/Specializations.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "TypeInfo/Resolving.hpp"
4 |
5 | template<>
6 | struct std::hash
7 | {
8 | std::size_t operator()(RED4ext::CName aKey) const
9 | {
10 | return aKey.hash;
11 | }
12 | };
13 |
14 | template<>
15 | struct std::hash
16 | {
17 | std::size_t operator()(RED4ext::TweakDBID aKey) const
18 | {
19 | return aKey.value;
20 | }
21 | };
22 |
23 | template<>
24 | struct std::hash
25 | {
26 | std::size_t operator()(RED4ext::ResourcePath aKey) const
27 | {
28 | return aKey.hash;
29 | }
30 | };
31 |
32 | template<>
33 | struct std::hash
34 | {
35 | std::size_t operator()(RED4ext::NodeRef aKey) const
36 | {
37 | return aKey.hash;
38 | }
39 | };
40 |
41 | template
42 | requires std::is_class_v && std::is_convertible_v && Red::Detail::HasGeneratedTypeName
43 | struct std::hash
44 | {
45 | std::size_t operator()(T aKey) const
46 | {
47 | return static_cast(aKey);
48 | }
49 | };
50 |
--------------------------------------------------------------------------------
/lib/Red/TypeInfo.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "TypeInfo/Construction.hpp"
4 | #include "TypeInfo/Definition.hpp"
5 | #include "TypeInfo/Properties.hpp"
6 | #include "TypeInfo/Parameters.hpp"
7 | #include "TypeInfo/Invocation.hpp"
8 | #include "TypeInfo/Registrar.hpp"
9 | #include "TypeInfo/Resolving.hpp"
10 |
11 | #include "TypeInfo/Mappings.hpp"
12 |
--------------------------------------------------------------------------------
/lib/Red/TypeInfo/Construction.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Resolving.hpp"
4 |
5 | namespace Red
6 | {
7 | template
8 | inline T* Construct()
9 | {
10 | auto type = GetType();
11 | auto instance = reinterpret_cast(type->GetAllocator()->AllocAligned(type->GetSize(),
12 | type->GetAlignment()).memory);
13 | type->Construct(instance);
14 | return instance;
15 | }
16 |
17 | template
18 | inline void Destruct(T* aInstance)
19 | {
20 | auto type = GetType();
21 | type->Destruct(aInstance);
22 | type->GetAllocator()->Free(aInstance);
23 | }
24 | }
25 |
26 | template
27 | requires (std::is_abstract_v || !RED4ext::Detail::HasStaticAllocator) && Red::Detail::HasGeneratedTypeName
28 | struct RED4ext::Detail::AllocatorHook : std::true_type
29 | {
30 | inline static Memory::IAllocator* Get()
31 | {
32 | return Red::GetClass()->GetAllocator();
33 | }
34 | };
35 |
36 | template
37 | requires (std::is_abstract_v || !RED4ext::Detail::HasStaticAllocator) && Red::Detail::HasGeneratedTypeName
38 | struct RED4ext::Detail::ConstructorHook : std::true_type
39 | {
40 | inline static void Apply(T* aInstance)
41 | {
42 | Red::GetClass()->ConstructCls(aInstance);
43 | }
44 | };
45 |
--------------------------------------------------------------------------------
/lib/Red/TypeInfo/Macros/Resolving.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define RTTI_MAP_TYPE_NAME(_type, _name) \
4 | template<> \
5 | struct Red::TypeNameMapping<_type> : public std::true_type \
6 | { \
7 | static constexpr auto name = _name; \
8 | };
9 |
10 | #define RTTI_MAP_TYPE_PREFIX(_type, _prefix) \
11 | template \
12 | struct Red::TypePrefixMapping<_type> : public std::true_type \
13 | { \
14 | static constexpr auto prefix = _prefix; \
15 | };
16 |
17 | #define RTTI_MAP_TYPE_PROXY(_type) \
18 | template \
19 | struct Red::TypeProxyMapping<_type> : public std::true_type \
20 | { \
21 | using type = A; \
22 | };
23 |
24 | #define RTTI_TYPE_NAME_STR(_type) Red::GetTypeNameStr<_type>()
25 |
26 | #define RTTI_FUNC_NAME_STR(...) []() constexpr noexcept { \
27 | constexpr auto _name = ::nameof::detail::pretty_name(#__VA_ARGS__); \
28 | return ::Red::Detail::MakeConstStr<_name.size()>(_name.data()); }()
29 |
30 | #define RTTI_PROP_NAME_STR(...) []() constexpr noexcept { \
31 | constexpr auto _name = ::nameof::detail::pretty_name(#__VA_ARGS__); \
32 | constexpr auto _clean = ::Red::Detail::RemoveMemberPrefix(_name); \
33 | return ::Red::Detail::MakeConstStr<_clean.size()>(_clean.data()); }()
34 |
35 | #define RTTI_ENUM_NAME_STR(...) ::nameof::nameof_enum<__VA_ARGS__>()
36 |
37 | #define RTTI_TYPE_NAME(_type) ::Red::GetTypeName<_type>()
38 | #define RTTI_FUNC_NAME(_func) ::Red::CName(RTTI_FUNC_NAME_STR(&_func).data())
39 | #define RTTI_PROP_NAME(_prop) ::Red::CName(RTTI_PROP_NAME_STR(&_prop).data())
40 | #define RTTI_ENUM_NAME(_enum) ::Red::CName(RTTI_ENUM_NAME_STR(_enum).data())
41 |
--------------------------------------------------------------------------------
/lib/Red/TypeInfo/Mappings.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Resolving.hpp"
4 |
5 | namespace Red
6 | {
7 | RTTI_MAP_TYPE_NAME(int8_t, "Int8");
8 | RTTI_MAP_TYPE_NAME(uint8_t, "Uint8");
9 | RTTI_MAP_TYPE_NAME(int16_t, "Int16");
10 | RTTI_MAP_TYPE_NAME(uint16_t, "Uint16");
11 | RTTI_MAP_TYPE_NAME(int32_t, "Int32");
12 | RTTI_MAP_TYPE_NAME(uint32_t, "Uint32");
13 | RTTI_MAP_TYPE_NAME(int64_t, "Int64");
14 | RTTI_MAP_TYPE_NAME(uint64_t, "Uint64");
15 | RTTI_MAP_TYPE_NAME(float, "Float");
16 | RTTI_MAP_TYPE_NAME(double, "Double");
17 | RTTI_MAP_TYPE_NAME(bool, "Bool");
18 | RTTI_MAP_TYPE_NAME(CString, "String");
19 | RTTI_MAP_TYPE_NAME(CName, "CName");
20 | RTTI_MAP_TYPE_NAME(TweakDBID, "TweakDBID");
21 | RTTI_MAP_TYPE_NAME(ItemID, "gameItemID");
22 | RTTI_MAP_TYPE_NAME(NodeRef, "NodeRef");
23 | RTTI_MAP_TYPE_NAME(GlobalNodeRef, "worldGlobalNodeRef");
24 | RTTI_MAP_TYPE_NAME(Variant, "Variant");
25 |
26 | RTTI_MAP_TYPE_PREFIX(DynArray, "array:");
27 | RTTI_MAP_TYPE_PREFIX(Handle, "handle:");
28 | RTTI_MAP_TYPE_PREFIX(WeakHandle, "whandle:");
29 | RTTI_MAP_TYPE_PREFIX(ResourceReference, "rRef:");
30 | RTTI_MAP_TYPE_PREFIX(ResourceAsyncReference, "raRef:");
31 | RTTI_MAP_TYPE_PREFIX(CurveData, "curveData:");
32 |
33 | RTTI_MAP_TYPE_NAME(char, "Uint8");
34 | RTTI_MAP_TYPE_NAME(ResourcePath, "redResourceReferenceScriptToken");
35 | }
36 |
--------------------------------------------------------------------------------
/lib/Red/TypeInfo/Properties.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Common.hpp"
4 | #include "Resolving.hpp"
5 |
6 | namespace Red
7 | {
8 | template
9 | requires (!std::is_base_of_v)
10 | inline T& GetPropertyPtr(C* aContext, CName aProp)
11 | {
12 | return GetPropertyPtr(aContext, GetClass(), aProp);
13 | }
14 |
15 | template
16 | inline T* GetPropertyPtr(ISerializable* aContext, CName aProp)
17 | {
18 | if (!aContext)
19 | return nullptr;
20 |
21 | auto prop = aContext->GetType()->GetProperty(aProp);
22 | if (!prop)
23 | return nullptr;
24 |
25 | return prop->GetValuePtr(aContext);
26 | }
27 |
28 | template
29 | inline T* GetPropertyPtr(void* aContext, CClass* aType, CName aProp)
30 | {
31 | if (!aContext || !aType)
32 | return nullptr;
33 |
34 | auto prop = aType->GetProperty(aProp);
35 | if (!prop)
36 | return nullptr;
37 |
38 | return prop->GetValuePtr(aContext);
39 | }
40 |
41 | template
42 | inline T* GetPropertyPtr(void* aContext, CName aType, CName aProp)
43 | {
44 | return GetPropertyPtr(aContext, GetClass(aType), aProp);
45 | }
46 |
47 | template
48 | requires (!std::is_base_of_v)
49 | inline T& GetProperty(C* aContext, CName aProp)
50 | {
51 | return *GetPropertyPtr(aContext, GetClass(), aProp);
52 | }
53 |
54 | template
55 | inline T& GetProperty(ISerializable* aContext, CName aProp)
56 | {
57 | return *GetPropertyPtr(aContext, aProp);
58 | }
59 |
60 | template
61 | inline T& GetProperty(void* aContext, CClass* aType, CName aProp)
62 | {
63 | return *GetPropertyPtr(aContext, aType, aProp);
64 | }
65 |
66 | template
67 | inline T& GetProperty(void* aContext, CName aType, CName aProp)
68 | {
69 | return *GetPropertyPtr(aContext, aType, aProp);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/lib/Red/TypeInfo/Registrar.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace Red
4 | {
5 | class TypeInfoRegistrar
6 | {
7 | public:
8 | using Callback = void(*)();
9 |
10 | TypeInfoRegistrar(Callback aRegister, Callback aDescribe)
11 | {
12 | AddRegisterCallback(aRegister);
13 | AddDescribeCallback(aDescribe);
14 | }
15 |
16 | static inline void RegisterDiscovered()
17 | {
18 | QueuePendingRegisterCallbacks();
19 | QueuePendingDescribeCallbacks();
20 | }
21 |
22 | static inline void AddRegisterCallback(Callback aRegister)
23 | {
24 | if (aRegister)
25 | {
26 | s_registerCallbacks.push_back(aRegister);
27 | }
28 | }
29 |
30 | static inline void AddDescribeCallback(Callback aDescribe)
31 | {
32 | if (aDescribe)
33 | {
34 | s_describeCallbacks.push_back(aDescribe);
35 | }
36 | }
37 |
38 | private:
39 | static inline void QueuePendingRegisterCallbacks()
40 | {
41 | if (!s_registerCallbacks.empty())
42 | {
43 | CRTTISystem::Get()->AddRegisterCallback(&OnRegister);
44 | }
45 | }
46 |
47 | static inline void QueuePendingDescribeCallbacks()
48 | {
49 | if (!s_describeCallbacks.empty())
50 | {
51 | CRTTISystem::Get()->AddPostRegisterCallback(&OnDescribe);
52 | }
53 | }
54 |
55 | static inline void ProcessPendingRegisterCallbacks()
56 | {
57 | auto callbacks = std::move(s_registerCallbacks);
58 | for (const auto& callback :callbacks)
59 | {
60 | callback();
61 | }
62 | }
63 |
64 | static inline void ProcessPendingDescriberCallbacks()
65 | {
66 | auto callbacks = std::move(s_describeCallbacks);
67 | for (const auto& callback :callbacks)
68 | {
69 | callback();
70 | }
71 | }
72 |
73 | static inline void OnRegister()
74 | {
75 | ProcessPendingRegisterCallbacks();
76 | QueuePendingRegisterCallbacks();
77 | }
78 |
79 | static inline void OnDescribe()
80 | {
81 | ProcessPendingDescriberCallbacks();
82 | QueuePendingDescribeCallbacks();
83 | }
84 |
85 | static inline std::vector s_registerCallbacks;
86 | static inline std::vector s_describeCallbacks;
87 | };
88 | }
89 |
--------------------------------------------------------------------------------
/lib/Red/Utils.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Utils/Handles.hpp"
4 | #include "Utils/JobQueues.hpp"
5 | #include "Utils/Resources.hpp"
6 |
--------------------------------------------------------------------------------
/lib/Red/Utils/Handles.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace Red
4 | {
5 | template
6 | inline WeakHandle& AsWeakHandle(T* aInstance)
7 | {
8 | return *reinterpret_cast*>(&aInstance->ref);
9 | }
10 |
11 | template
12 | inline Handle AsHandle(T* aInstance)
13 | {
14 | return AsWeakHandle(aInstance);
15 | }
16 |
17 | template
18 | inline WeakHandle ToWeakHandle(T* aInstance)
19 | {
20 | if (!aInstance)
21 | return {};
22 |
23 | return AsWeakHandle(aInstance);
24 | }
25 |
26 | template
27 | inline WeakHandle ToWeakHandle(const Handle& aInstance)
28 | {
29 | return aInstance;
30 | }
31 |
32 | template
33 | inline Handle ToHandle(T* aInstance)
34 | {
35 | if (!aInstance)
36 | return {};
37 |
38 | if (aInstance->ref.instance)
39 | {
40 | return reinterpret_cast*>(&aInstance->ref)->Lock();
41 | }
42 | else
43 | {
44 | return Handle(aInstance);
45 | }
46 | }
47 |
48 | template
49 | inline Handle ToHandle(U* aInstance)
50 | {
51 | if (!aInstance)
52 | return {};
53 |
54 | auto instance = reinterpret_cast(aInstance);
55 | if (instance->ref.instance)
56 | {
57 | return reinterpret_cast*>(&instance->ref)->Lock();
58 | }
59 | else
60 | {
61 | return Handle(reinterpret_cast(instance));
62 | }
63 | }
64 |
65 | template
66 | inline Handle MakeScriptedHandle(CClass* aType)
67 | {
68 | return Handle(reinterpret_cast(aType->CreateInstance(true)));
69 | }
70 |
71 | template