├── .github ├── FUNDING.yml └── workflows │ ├── build.yml │ ├── release.yml │ ├── unex_check.yml │ └── update_info.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── README_zh.md ├── Third_Party_LICENSES ├── build.lua ├── metadata.json ├── scripts ├── dofiles │ ├── set_time_to_noon.lua │ ├── suicide.lua │ └── to-the-moon.lua ├── init.lua ├── lang │ ├── de_de.lua │ ├── en_us.lua │ ├── example.lua │ ├── fr_fr.lua │ ├── ja_jp.lua │ ├── lang.lua │ ├── pt_br.lua │ ├── ro_ro.lua │ ├── ru_ru.lua │ ├── tr_tc.lua │ ├── zh_cn.lua │ └── zh_tw.lua └── modules │ ├── CETMM.lua │ ├── backend.lua │ ├── core │ ├── class │ │ ├── dofile.lua │ │ └── path.lua │ └── helper.lua │ ├── dofiles.lua │ ├── event.lua │ ├── gui │ ├── dpi.lua │ ├── init.lua │ ├── themeSys.lua │ ├── themes │ │ ├── baseTheme.lua │ │ ├── default.lua │ │ ├── ua_special.lua │ │ └── white.lua │ ├── widgets │ │ ├── btnToggle.lua │ │ ├── button.lua │ │ └── init.lua │ ├── window.lua │ └── windows │ │ ├── init.lua │ │ └── uninstall.lua │ ├── hotkeys.lua │ ├── i18n │ ├── README.md │ ├── init.lua │ ├── interpolate.lua │ ├── plural.lua │ ├── variants.lua │ └── version.lua │ ├── locale.lua │ ├── options.lua │ └── types.lua ├── src ├── CETMM │ ├── CETMM.cpp │ ├── CETMM.h │ ├── EXT │ │ ├── Auth.cpp │ │ ├── Auth.h │ │ ├── CETMMEXT.cpp │ │ ├── CETMMEXT.h │ │ ├── Misc.cpp │ │ ├── Misc.h │ │ ├── Mod.cpp │ │ ├── Mod.h │ │ ├── Mods.cpp │ │ ├── Mods.h │ │ ├── TypeRegister.h │ │ ├── Uninstall.cpp │ │ └── Uninstall.h │ ├── Logger.cpp │ ├── Logger.h │ ├── Utilities.cpp │ ├── Utilities.h │ ├── dllmain.cpp │ └── pch.h ├── Common │ ├── Paths.cpp │ ├── Paths.h │ └── Version.h.in └── Installer │ ├── Installer.cpp │ ├── Installer.h │ ├── Logger.cpp │ ├── Logger.h │ ├── Update.cpp │ ├── Update.h │ ├── dllmain.cpp │ └── pch.h ├── vendor └── bin2cpp │ ├── LICENSE │ ├── README.md │ └── bin2cpp.exe └── xmake.lua /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: mingm 2 | custom: buymeacoffee.com/mingm 3 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: 3 | push: 4 | branches: [ master ] 5 | paths: 6 | - 'scripts/**' 7 | - 'src/**' 8 | - 'vendor/**' 9 | - '**.lua' 10 | - '.github/workflows/build.yml' 11 | pull_request: 12 | branches: [ master ] 13 | 14 | jobs: 15 | build: 16 | runs-on: windows-latest 17 | steps: 18 | - uses: actions/checkout@v2 19 | with: 20 | fetch-depth: 0 21 | submodules: recursive 22 | 23 | - name: Setup xmake 24 | uses: xmake-io/github-action-setup-xmake@v1 25 | 26 | - name: Update xmake repository and install dependencies 27 | run: | 28 | xmake.exe repo --update 29 | xmake.exe q --yes 30 | 31 | - name: Build and Package 32 | run: | 33 | xmake.exe build cet_mod_manager 34 | xmake.exe embed 35 | xmake.exe package installer 36 | 37 | - name: Upload Artifacts 38 | uses: actions/upload-artifact@v2 39 | with: 40 | name: package 41 | path: build/package/ -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | release: 4 | types: [published] 5 | 6 | jobs: 7 | build: 8 | runs-on: windows-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | with: 12 | fetch-depth: 0 13 | submodules: recursive 14 | 15 | - name: Setup xmake 16 | uses: xmake-io/github-action-setup-xmake@v1 17 | 18 | - name: Update xmake repository and install dependencies 19 | run: | 20 | xmake.exe repo --update 21 | xmake.exe q --yes 22 | 23 | - name: Build and Package 24 | run: | 25 | xmake.exe build cet_mod_manager 26 | xmake.exe embed 27 | xmake.exe package installer 28 | 29 | - name: Upload Artifacts 30 | uses: actions/upload-artifact@v2 31 | with: 32 | name: package 33 | path: build/package/ 34 | 35 | release-github: 36 | runs-on: ubuntu-latest 37 | needs: build 38 | steps: 39 | - uses: actions/checkout@v2 40 | 41 | - name: Set environment variables 42 | uses: antifree/json-to-variables@v1.0.1 43 | with: 44 | filename: metadata.json 45 | prefix: META 46 | 47 | - name: Download Artifact 48 | uses: actions/download-artifact@v2.0.9 49 | 50 | - name: Create zip 51 | uses: ihiroky/archive-action@v1 52 | with: 53 | root_dir: "package/" 54 | file_path: "${{ env.META_MOD_FILE_NAME }}_${{ github.event.release.tag_name }}.zip" 55 | 56 | - name: Upload to Github Release 57 | uses: ncipollo/release-action@v1 58 | with: 59 | allowUpdates: true 60 | omitNameDuringUpdate: true 61 | omitBodyDuringUpdate: true 62 | artifacts: "${{ env.META_MOD_FILE_NAME }}_${{ github.event.release.tag_name }}.zip" 63 | token: ${{ secrets.GITHUB_TOKEN }} 64 | prerelease: ${{ github.event.release.prerelease }} 65 | 66 | release-nexus: 67 | runs-on: ubuntu-latest 68 | needs: build 69 | steps: 70 | - uses: actions/checkout@v2 71 | 72 | - name: Update release note 73 | uses: jossef/action-set-json-field@v1 74 | with: 75 | file: metadata.json 76 | field: UNEX_FILEDESCRIPTION 77 | value: ${{ github.event.release.body }} 78 | 79 | - name: Set environment variables 80 | uses: antifree/json-to-variables@v1.0.1 81 | with: 82 | filename: metadata.json 83 | prefix: META 84 | 85 | - name: Download Artifact 86 | uses: actions/download-artifact@v2.0.9 87 | 88 | - name: Create zip 89 | uses: ihiroky/archive-action@v1 90 | with: 91 | root_dir: "package/" 92 | file_path: "${{ env.META_MOD_FILE_NAME }}_${{ github.event.release.tag_name }}.zip" 93 | 94 | - name: Setup dotnet 95 | uses: actions/setup-dotnet@v1 96 | with: 97 | dotnet-version: '3.1.x' 98 | 99 | - name: Upload to Nexus Mods 100 | env: 101 | UNEX_APIKEY: ${{ secrets.UNEX_APIKEY }} 102 | UNEX_COOKIES: ${{ secrets.UNEX_COOKIES }} 103 | UNEX_GAME: ${{ env.META_UNEX_GAME }} 104 | UNEX_MODID: ${{ env.META_UNEX_MODID }} 105 | UNEX_PREVIOUSFILE: auto 106 | UNEX_FILENAME: ${{ env.META_UNEX_FILENAME }} 107 | UNEX_FILEDESCRIPTION: ${{ github.event.release.body }} 108 | UNEX_FILEPATH: ${{ env.META_MOD_FILE_NAME }}_${{ github.event.release.tag_name }}.zip 109 | UNEX_VERSION: ${{ github.event.release.tag_name }} 110 | run: | 111 | dotnet tool install -g NexusUploader 112 | unex upload $UNEX_MODID $UNEX_FILEPATH -v $UNEX_VERSION 113 | 114 | release-3dm: 115 | runs-on: ubuntu-latest 116 | needs: build 117 | steps: 118 | - uses: actions/checkout@v2 119 | 120 | - name: Set environment variables 121 | uses: antifree/json-to-variables@v1.0.1 122 | with: 123 | filename: metadata.json 124 | prefix: META 125 | 126 | - name: Download Artifact 127 | uses: actions/download-artifact@v2.0.9 128 | 129 | - name: Upload to 3DM Mods 130 | id: upload_3dm 131 | uses: GlossMod/ActionUpdateMod@v1 132 | with: 133 | appid: ${{ secrets.APPID_3DM }} 134 | appkey: ${{ secrets.APPKEY_3DM }} 135 | id: ${{ env.META_3DM_MOD_ID }} 136 | title: ${{ env.META_3DM_MOD_TITLE }} 137 | version: ${{ github.event.release.tag_name }} 138 | tags: ${{ env.META_3DM_MOD_TAGS }} 139 | desc: ${{ env.META_3DM_MOD_DESC }} 140 | content: ${{ env.META_3DM_MOD_CONTENT }} 141 | file: package/ 142 | 143 | - name: Check 3DM upload status 144 | run: "echo 'Code: ${{ steps.test3.outputs.code }}\tMessage: ${{ steps.test3.outputs.msg }}'" 145 | -------------------------------------------------------------------------------- /.github/workflows/unex_check.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: UNEX Check 4 | 5 | # Controls when the action will run. 6 | on: 7 | 8 | workflow_dispatch: 9 | 10 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 11 | jobs: 12 | # This workflow contains a single job called "build" 13 | check: 14 | # The type of runner that the job will run on 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - name: Setup dotnet 20 | uses: actions/setup-dotnet@v1 21 | with: 22 | dotnet-version: '3.1.x' 23 | 24 | - name: Check 25 | env: 26 | UNEX_APIKEY: ${{ secrets.UNEX_APIKEY }} 27 | UNEX_COOKIES: ${{ secrets.UNEX_COOKIES }} 28 | run: | 29 | dotnet tool install -g NexusUploader 30 | unex check 31 | -------------------------------------------------------------------------------- /.github/workflows/update_info.yml: -------------------------------------------------------------------------------- 1 | name: Update Mod info 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | update-3dm: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | 12 | - name: Set environment variables 13 | uses: antifree/json-to-variables@v1.0.1 14 | with: 15 | filename: metadata.json 16 | prefix: META 17 | 18 | - name: Update infomation on 3DM Mods 19 | id: update_3dm 20 | uses: Nats-ji/3dm-release-action@master 21 | with: 22 | appid: ${{ secrets.APPID_3DM }} 23 | appkey: ${{ secrets.APPKEY_3DM }} 24 | mod_id: ${{ env.META_3DM_MOD_ID }} 25 | mod_title: ${{ env.META_3DM_MOD_TITLE }} 26 | mod_tags: ${{ env.META_3DM_MOD_TAGS }} 27 | mod_desc: ${{ env.META_3DM_MOD_DESC }} 28 | mod_content: ${{ env.META_3DM_MOD_CONTENT }} 29 | 30 | - name: Check 3DM update status 31 | run: echo ${{ steps.update_3dm.outputs.RESPONSE }} 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # dev 2 | .vscode/ 3 | .xmake/ 4 | build/ 5 | 6 | cet_mod_manager.code-workspace 7 | 8 | src/Common/Version.h 9 | scripts/modules/version.lua 10 | src/Installer/embeds/ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/RED4ext.SDK"] 2 | path = vendor/RED4ext.SDK 3 | url = https://github.com/WopsS/RED4ext.SDK.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Buy Me a Coffee at ko-fi.com 3 | Donate me at paypal.com 4 | 5 | [![github][github-badge]][github-link] [![build][build-badge]][build-link] ![license][license-badge] [![release][release-badge]][release-link] [![nexus][nexus-badge]][nexus-link] [![3dm][3dm-badge]][3dm-link] 6 | 7 | # Cyber Engine Tweaks Mod Manager 8 | 9 | ## Features 10 | 11 | Download: https://github.com/Nats-ji/CET-Mod-Manager/releases/ 12 | 13 | Nexusmods: https://www.nexusmods.com/cyberpunk2077/mods/895 14 | 15 | - A Mod Manager for CyberEngineTweaks based mods 16 | - Enable/Disable CyberEngineTweaks based mods inside game with a single click 17 | - Open the interface by pressing the hotkey you bound in CET 18 | 19 | 20 | ![imgage](https://staticdelivery.nexusmods.com/mods/3333/images/895/895-1610480969-1242777005.png) 21 | 22 | ## Installation 23 | 24 | This mod requires: 25 | 1. the latest version of **Cyber Engine Tweaks** Mod. [[nexusmods]](https://www.nexusmods.com/cyberpunk2077/mods/107) | [[github]](https://github.com/yamashi/CyberEngineTweaks) 26 | 2. the latest version of **Red4EXT**. [[nexusmods]](https://www.nexusmods.com/cyberpunk2077/mods/2380) | [[github]](https://github.com/WopsS/RED4ext) 27 | 28 | Extract `bin` into the root directory of Cyberpunk2077's install path. 29 | 30 | Restart the game. 31 | 32 | ## Usage 33 | 34 | 1. To use it, you just simply press `hotkey` you bound to open the inertface. 35 | 36 | 2. Press the button `Scan` to scan your installed mods. 37 | 38 | 3. Tick/untick the checkbox in front of the mod name to enable/disable them. 39 | 40 | 4. Press the `Reload ALL Mods` button on the console to reload the mods. 41 | 42 | ### Change language 43 | Check this [guide](https://wiki.redmodding.org/cyber-engine-tweaks/getting-started/configuration/change-font-and-font-size#how-to-display-non-english-characters) for more information. 44 | 45 | ### API (deprecated) 46 | 47 | 1. To use the API (currently only supports CET) to query the mod list 48 | ```lua 49 | -- returns a table 50 | modlist = GetMod("cet_mod_manager").GetModList() 51 | 52 | -- print the mod list in console 53 | GetMod("cet_mod_manager").PrintModList() 54 | ``` 55 | 2. Return format by the API 56 | ```lua 57 | { 58 | archive = { "a", "list", "of", "mods"}, 59 | asi = { "a", "list", "of", "mods"}, 60 | cet = { "a", "list", "of", "mods"}, 61 | red4ext = { "a", "list", "of", "mods"}, 62 | redscript = { "a", "list", "of", "mods"} 63 | } 64 | ``` 65 | 66 | ## Uninstallation 67 | 68 | 1. Before you uninstall this mod, make sure you have **re-enabled** all the mods. 69 | 70 | 2. Remove `cet_mod_manager.asi` from `\Cyberpunk 2077\bin\x64\plugins\` 71 | 72 | ## Translations 73 | - English 74 | - Simplified Chinese (Translator: Nats-ji) 75 | - Traditional Chinese (Translator: Nats-ji) 76 | - Japanese (Translator: Nats-ji) 77 | - German (Translator: keanuWheeze) 78 | - Russian (Translator: vanja-san) 79 | - Turkish (Translator: sebepne) 80 | - Romanian (Translator: Maddmaniak) 81 | - Brazilian Portuguese (Translator: mathfelin) 82 | - French (Translator : ReActif) 83 | 84 | ## Credits 85 | 86 | - yamashi's CyberEngineTweaks https://github.com/yamashi?tab=repositories 87 | - WhySoSerious for answering every question I had about lua https://github.com/WSSDude420 88 | - Development Team behind CyberEngineTweaks and and RED4extSDK 89 | - CP77 Modding Tools Discord Community https://discord.gg/cp77modding 90 | - And people who translated for this project. 91 | 92 | [github-badge]: https://img.shields.io/badge/source-Github-red?style=social&logo=github 93 | [github-link]: https://github.com/Nats-ji/CET-Mod-Manager 94 | [build-badge]: https://img.shields.io/github/actions/workflow/status/Nats-ji/CET-Mod-Manager/build.yml?branch=master 95 | [build-link]: https://github.com/Nats-ji/CET-Mod-Manager/actions/workflows/build.yml 96 | [license-badge]: https://img.shields.io/github/license/Nats-ji/CET-Mod-Manager 97 | [release-badge]: https://img.shields.io/github/v/release/Nats-ji/CET-Mod-Manager?include_prereleases 98 | [release-link]: https://github.com/Nats-ji/CET-Mod-Manager/releases/latest 99 | [nexus-badge]: https://img.shields.io/badge/download-Nexus%20Mods-orange 100 | [nexus-link]: https://www.nexusmods.com/cyberpunk2077/mods/895 101 | [3dm-badge]: https://img.shields.io/badge/download-3DM%20Mods-blueviolet 102 | [3dm-link]: https://mod.3dmgame.com/mod/172144 103 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | [![github][github-badge]][github-link] [![build][build-badge]][build-link] ![license][license-badge] [![release][release-badge]][release-link] [![nexus][nexus-badge]][nexus-link] [![3dm][3dm-badge]][3dm-link] 2 | 3 | ### 现已支持中文,需要把控制台的默认字体改成中文字体 4 | 点按钮 ! 选择语言。 5 | 6 | ![](https://staticdelivery.nexusmods.com/mods/3333/images/895/895-1611766356-1945566139.png) 7 | 8 | # 功能 9 | - 在游戏中启用或者禁用基于Cyber Engine Tweaks的mod 10 | - 用不到的mod在游戏中一键关闭 11 | - 可以直接从mod管理器运行使用`dofile()`命令的脚本mod 12 | 13 | ![](https://mod.3dmgame.com/ueditor/php/upload/image/20210114/1610567995552748.png) ![](https://mod.3dmgame.com/ueditor/php/upload/image/20210114/1610567995298943.png) 14 | 15 | # 安装 16 | 1. 首先安装最新版 [Cyber Engine Tweaks](https://www.nexusmods.com/cyberpunk2077/mods/107) 17 | 2. 其次安装最新版 [Red4EXT](https://www.nexusmods.com/cyberpunk2077/mods/2380) 18 | 3. 解压后把 `bin` 文件夹放到游戏安装主路径 19 | 20 | - 安装后目录应该像这样 21 | 22 | Cyberpunk 2077 23 | └── bin 24 |    └── x64 25 |       └── plugins 26 |          ├── cet_mod_manager.asi 27 |          └── cyber_engine_tweaks.asi 28 | 29 | 30 | # 使用方法 31 | 1. 在游戏中按绑定的热键打开Mod管理界面 32 | 2. 点`扫描`按钮扫描安装的mod (如果你的游戏是全屏模式的话会弹到桌面,再切换回游戏就行了,把游戏改成全屏无边框窗口的话就不会弹到桌面了) 33 | 3. 把不需要的mod勾掉 34 | 4. 点控制台的`Reload All Mods`按钮以重载Cyber Engine Tweaks 35 | 5. 在游戏中按绑定的热键可以打开脚本Mod运行界面 36 | 6. 要从mod管理器运行脚本mod的话,把脚本文件直接放到 `cet_mod_manager` 文件夹里的`dofiles`文件夹(点mod管理器里的`Dofile文件夹`按钮可以直接打开)。 37 | 7. 点左上角的`Dofile Mods`按钮进入脚本mod的列表。 38 | 8. 点mod前面的`运行`按钮就可以直接运行了。 39 | 9. 自带了几个示例脚本,不需要的话自行删除即可。 40 | 41 | # 卸载 42 | 1. 先把所有mod都重新启用 43 | 2. 删除 `<赛博朋克2077的安装路径>/bin/x64/plugins/` 里的 `cet_mod_manager.asi` 44 | 45 | # 目前支持的语言 46 | - 英文 47 | - 简体中文(翻译者:Ming) 48 | - 繁体中文(翻译者:Ming) 49 | - 日语(翻译者:Ming) 50 | - 德语(翻译者:keanuWheeze) 51 | - 俄语(翻译者:vanja-san) 52 | - 土耳其语(翻译者:sebepne) 53 | - 罗马尼亚语(翻译者:Maddmaniak) 54 | - 葡萄牙语(巴西)(翻译者:mathfelin) 55 | - 法语(翻译者:ReActif) 56 | 57 | # Github 58 | https://github.com/Nats-ji/CET-Mod-Manager 59 | 60 | [github-badge]: https://img.shields.io/badge/source-Github-red?style=social&logo=github 61 | [github-link]: https://github.com/Nats-ji/CET-Mod-Manager 62 | [build-badge]: https://img.shields.io/github/workflow/status/Nats-ji/CET-Mod-Manager/Build?event=push 63 | [build-link]: https://github.com/Nats-ji/CET-Mod-Manager/actions/workflows/build.yml 64 | [license-badge]: https://img.shields.io/github/license/Nats-ji/CET-Mod-Manager 65 | [release-badge]: https://img.shields.io/github/v/release/Nats-ji/CET-Mod-Manager?include_prereleases 66 | [release-link]: https://github.com/Nats-ji/CET-Mod-Manager/releases/latest 67 | [nexus-badge]: https://img.shields.io/badge/download-Nexus%20Mods-orange 68 | [nexus-link]: https://www.nexusmods.com/cyberpunk2077/mods/895 69 | [3dm-badge]: https://img.shields.io/badge/download-3DM%20Mods-blueviolet 70 | [3dm-link]: https://mod.3dmgame.com/mod/172144 -------------------------------------------------------------------------------- /Third_Party_LICENSES: -------------------------------------------------------------------------------- 1 | i18n.lua 2 | 3 | MIT License Terms 4 | ================= 5 | 6 | Copyright (c) 2012 Enrique García Cota. 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy of 9 | this software and associated documentation files (the "Software"), to deal in 10 | the Software without restriction, including without limitation the rights to 11 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 | of the Software, and to permit persons to whom the Software is furnished to do 13 | so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | 26 | ******************************************************************************* 27 | 28 | spdlog 29 | 30 | The MIT License (MIT) 31 | 32 | Copyright (c) 2016 Gabi Melman. 33 | 34 | Permission is hereby granted, free of charge, to any person obtaining a copy 35 | of this software and associated documentation files (the "Software"), to deal 36 | in the Software without restriction, including without limitation the rights 37 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 38 | copies of the Software, and to permit persons to whom the Software is 39 | furnished to do so, subject to the following conditions: 40 | 41 | The above copyright notice and this permission notice shall be included in 42 | all copies or substantial portions of the Software. 43 | 44 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 45 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 46 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 47 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 48 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 49 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 50 | THE SOFTWARE. 51 | 52 | -- NOTE: Third party dependency used by this software -- 53 | This software depends on the fmt lib (MIT License), 54 | and users must comply to its license: 55 | https://github.com/fmtlib/fmt/blob/master/LICENSE.rst 56 | 57 | ******************************************************************************* 58 | 59 | fmt 60 | 61 | Copyright (c) 2012 - present, Victor Zverovich 62 | 63 | Permission is hereby granted, free of charge, to any person obtaining a copy of 64 | this software and associated documentation files (the "Software"), to deal in the 65 | Software without restriction, including without limitation the rights to use, 66 | copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 67 | Software, and to permit persons to whom the Software is furnished to do so, 68 | subject to the following conditions: 69 | 70 | The above copyright notice and this permission notice shall be included in all 71 | copies or substantial portions of the Software. 72 | 73 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 74 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 75 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 76 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 77 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 78 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 79 | 80 | --- Optional exception to the license --- 81 | 82 | As an exception, if, as a result of your compiling your source code, portions of 83 | this Software are embedded into a machine-executable object form of such source 84 | code, you may redistribute such embedded portions in such object form without 85 | including the above copyright and permission notices. 86 | 87 | ******************************************************************************* 88 | 89 | bin2cpp 90 | 91 | MIT License 92 | 93 | Copyright (c) 2018 Antoine Beauchamp 94 | 95 | Permission is hereby granted, free of charge, to any person obtaining a copy 96 | of this software and associated documentation files (the "Software"), to deal 97 | in the Software without restriction, including without limitation the rights 98 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 99 | copies of the Software, and to permit persons to whom the Software is 100 | furnished to do so, subject to the following conditions: 101 | 102 | The above copyright notice and this permission notice shall be included in all 103 | copies or substantial portions of the Software. 104 | 105 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 106 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 107 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 108 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 109 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 110 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 111 | SOFTWARE. 112 | 113 | ********************************************************************************* 114 | 115 | RED4ext.SDK 116 | 117 | MIT License 118 | 119 | Copyright (c) 2020 - present Octavian Dima 120 | 121 | Permission is hereby granted, free of charge, to any person obtaining a copy of 122 | this software and associated documentation files (the "Software"), to deal in 123 | the Software without restriction, including without limitation the rights to 124 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 125 | the Software, and to permit persons to whom the Software is furnished to do so, 126 | subject to the following conditions: 127 | 128 | The above copyright notice and this permission notice shall be included in all 129 | copies or substantial portions of the Software. 130 | 131 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 132 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 133 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 134 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 135 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 136 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /build.lua: -------------------------------------------------------------------------------- 1 | -- build script for xmake 2 | local package_path = vformat("$(buildir)/package") 3 | 4 | -- embed settings 5 | local embeds_path = "src/Installer/embeds" 6 | 7 | local embed_files = { 8 | "LICENSE", 9 | "Third_Party_LICENSES", 10 | "README.md", 11 | "README_zh.md", 12 | } 13 | 14 | local function check_game_installation(install_path) 15 | assert(install_path, format("Install path not set.\n\tUse the follow command to set install path:\n\txmake f --installpath=%s", [["C:\Program Files (x86)\Steam\steamapps\common\Cyberpunk 2077"]])) 16 | local exe_path = path.join(install_path, "bin", "x64", "Cyberpunk2077.exe") 17 | assert(os.exists(exe_path), format("Can't find the game installation. Make sure the install path is set to game root directory.\n\tUse the follow command to set install path:\n\txmake f --installpath=%s", [["C:\Program Files (x86)\Steam\steamapps\common\Cyberpunk 2077"]])) 18 | end 19 | 20 | local function generate_version_lua(git_tag) 21 | local file = io.open("scripts/modules/version.lua", "w") 22 | 23 | assert(file, "can't open file scripts/modules/version.lua") 24 | local content = format([[return "%s"]], git_tag) 25 | file:write(content) 26 | file:close() 27 | end 28 | 29 | -- Export functions 30 | function UpdateVersion() 31 | local git_tag = os.iorun("git describe --tags"):gsub("\n", "") 32 | generate_version_lua(git_tag) 33 | cprint("generating scripts\\modules\\version.lua ... ${bright green}ok") 34 | 35 | if os.exists("src/Common/Version.h.in") then 36 | local file = io.open("src/Common/Version.h.in", "r") 37 | local content = file:read("*a") 38 | file:close() 39 | cprint("generating src\\Common\\Version.h.in ... ${bright green}ok") 40 | content = content:gsub("${GIT_TAG}", git_tag) 41 | cprint("updating the git tag in src\\Common\\Version.h ... ${bright green}ok") 42 | file = io.open("src/Common/Version.h", "w") 43 | file:write(content) 44 | file:close() 45 | end 46 | end 47 | 48 | function GenerateEmbeds() 49 | -- clear embed directories 50 | if os.isdir(embeds_path) then 51 | os.tryrm(path.join(embeds_path, "**")) 52 | end 53 | 54 | -- create directories for embed files 55 | local embeds_lua_path = path.join(embeds_path, "lua") 56 | local embeds_red4ext_path = path.join(embeds_path, "red4ext") 57 | os.mkdir(embeds_lua_path) 58 | os.mkdir(embeds_red4ext_path) 59 | 60 | -- embed red4ext plugin 61 | import("core.project.config") 62 | config.load() 63 | import("core.project.project") 64 | local target = project.target("cet_mod_manager") 65 | print(target:targetfile()) 66 | assert(os.exists(target:targetfile()), "target file for cet_mod_manager doesn't exist, run xmake build cet_mod_manager to build the target first.") 67 | os.exec([[.\vendor\bin2cpp\bin2cpp.exe --file=%s --managerfile=EmbedFileManager_Red4ExtPlugin.h --registerfile --namespace=bin2cppRed4ExtPlugin --output=%s --noheader]], target:targetfile(), path.translate(embeds_red4ext_path)) 68 | 69 | -- embed loose files 70 | for _, file in ipairs(embed_files) do 71 | os.exec([[.\vendor\bin2cpp\bin2cpp.exe --file=%s --managerfile=EmbedFileManager_LooseFiles.h --registerfile --output=%s --namespace=bin2cppLooseFiles --noheader]], file, path.translate(embeds_lua_path)) 72 | end 73 | 74 | -- embed lua files 75 | os.exec([[.\vendor\bin2cpp\bin2cpp.exe --dir=scripts --managerfile=EmbedFileManager_Lua.h --output=%s --namespace=bin2cppLua --keepdirs --noheader]], path.translate(embeds_lua_path)) 76 | 77 | cprint("generating files for embedding to %s ... ${bright green}ok", embeds_path) 78 | end 79 | 80 | function Package(target) 81 | if os.tryrm(path.join(package_path, "**")) then 82 | cprint("cleaning old package files ... ${bright green}ok") 83 | else 84 | cprint("cleaning old package files ... ${bright red}failed") 85 | end 86 | local output_path = path.join(package_path, "bin/x64/plugins") 87 | os.mkdir(output_path) 88 | cprint("creating file structure ... ${bright green}ok") 89 | 90 | if target then 91 | os.cp(target:targetfile(), output_path) 92 | cprint("copying cet_mod_manager.asi ... ${bright green}ok") 93 | end 94 | end 95 | 96 | function Install() 97 | import("core.project.config") 98 | config.load() 99 | import("core.project.project") 100 | local target = project.target("installer") 101 | local install_path = config.get("installpath") 102 | cprint("${green bright}Installing CET Mod Manager ..") 103 | check_game_installation(install_path) 104 | assert(os.exists(target:targetfile()), "target file doesn't exist, run xmake to build the target first.") 105 | local output_dir = path.join(install_path, "bin/x64/plugins") 106 | os.cp(target:targetfile(), output_dir) 107 | cprint("CET Mod Manager installed at: ${underline}%s", output_dir) 108 | end 109 | 110 | function InstallLua() 111 | import("core.project.config") 112 | config.load() 113 | local install_path = config.get("installpath") 114 | cprint("${green bright}Installing CET Mod Manager Lua ..") 115 | check_game_installation(install_path) 116 | local from_path = path.translate("./scripts") 117 | local to_path = path.translate(path.join(install_path, "bin/x64/plugins/cyber_engine_tweaks/mods/cet_mod_manager")) 118 | os.execv("xcopy", {from_path, to_path, "/s", "/e", "/y", "/q"}) -- Don't use os.cp(), it will remove the contents from the destination directory. 119 | cprint("CET Mod Manager Lua installed at: ${underline}%s", path.translate(path.join(install_path, "bin/x64/plugins/cyber_engine_tweaks/mods/cet_mod_manager"))) 120 | end 121 | 122 | function InstallExt() 123 | import("core.project.config") 124 | config.load() 125 | import("core.project.project") 126 | local target = project.target("cet_mod_manager") 127 | local install_path = config.get("installpath") 128 | cprint("${green bright}Installing CET Mod Manager Red4ext plugin ..") 129 | check_game_installation(install_path) 130 | assert(os.exists(target:targetfile()), "target file doesn't exist, run xmake to build the target first.") 131 | local output_dir = path.join(install_path, "red4ext/plugins/cet_mod_manager") 132 | os.mkdir(output_dir) 133 | os.cp(target:targetfile(), output_dir) 134 | cprint("CET Mod Manager Lua installed at: ${underline}%s", path.translate(output_dir)) 135 | end 136 | 137 | function Clean() 138 | if os.tryrm(path.join(embeds_path, "**")) then 139 | cprint("cleaning embed files ... ${bright green}ok") 140 | else 141 | cprint("cleaning embed files ... ${bright red}failed") 142 | end 143 | 144 | if os.tryrm(path.join(package_path, "**")) then 145 | cprint("cleaning package files ... ${bright green}ok") 146 | else 147 | cprint("cleaning package files ... ${bright red}failed") 148 | end 149 | end 150 | 151 | function BuildAll() 152 | os.execv("xmake", {"b", "cet_mod_manager"}) 153 | GenerateEmbeds() 154 | os.execv("xmake", {"b", "installer"}) 155 | end -------------------------------------------------------------------------------- /metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "3DM_MOD_ID": 172144, 3 | "3DM_MOD_TITLE": "(已支持中文) Cyber Engine Tweaks 控制台 内置 MOD管理器", 4 | "3DM_MOD_TAGS": "Cyber Engine Tweaks,赛博朋克2077,Cyberpunk 2077,MOD管理器,控制台", 5 | "3DM_MOD_DESC": "在游戏中启用禁用基于Cyber Engine Tweaks的mod", 6 | "3DM_MOD_CONTENT": "README_zh.md", 7 | "UNEX_GAME": "cyberpunk2077", 8 | "UNEX_MODID": 895, 9 | "UNEX_FILENAME": "CET Mod Manager", 10 | "UNEX_FILEDESCRIPTION": "Check here for release note: https://github.com/Nats-ji/CET-Mod-Manager/releases/latest", 11 | "MOD_FILE_NAME": "cet_mod_manager" 12 | } 13 | -------------------------------------------------------------------------------- /scripts/dofiles/set_time_to_noon.lua: -------------------------------------------------------------------------------- 1 | local tms = Game.GetTimeSystem() 2 | tms:SetGameTimeByHMS(12, 0, 0) 3 | print("Good Morning, sleepy head!") -------------------------------------------------------------------------------- /scripts/dofiles/suicide.lua: -------------------------------------------------------------------------------- 1 | local player = Game.GetPlayer() 2 | player:OnDied() 3 | print("YOLO") 4 | -------------------------------------------------------------------------------- /scripts/dofiles/to-the-moon.lua: -------------------------------------------------------------------------------- 1 | local cood = {4743.650879, -1091.755127, 1310.439575} 2 | 3 | Game.TeleportPlayerToPosition(cood[1], cood[2], cood[3]) 4 | -------------------------------------------------------------------------------- /scripts/init.lua: -------------------------------------------------------------------------------- 1 | require ("modules/CETMM") 2 | 3 | CETMM.Initialize() 4 | CETMM.Event() 5 | CETMM.Update() 6 | CETMM.Render() 7 | CETMM.Shutdown() -------------------------------------------------------------------------------- /scripts/lang/de_de.lua: -------------------------------------------------------------------------------- 1 | -- Translator : keanuWheeze 2 | return { 3 | de_de = { 4 | console_msg_loaded1 = "**************************************************" , 5 | console_msg_loaded2 = " Cyber Engine Tweaks Mod Manager geladen... " , 6 | console_msg_loaded3 = " Bitte lege einen Hotkey in Cyber Engine Tweaks " , 7 | console_msg_loaded4 = " fest wenn dies der erste Start ist. " , 8 | console_msg_loaded5 = "**************************************************" , 9 | hotkey_manager = "Mod Manager Fenster" , 10 | hotkey_dofiles = "Dofile Fenster" , 11 | console_msg_scan = "[CETMM] Mod scan abgeschlossen." , 12 | console_msg_autoscan_on = "[CETMM] Auto scan aktiviert." , 13 | console_msg_autoscan_off = "[CETMM] Auto scan deaktiviert." , 14 | console_msg_autoapear_on = "[CETMM] Öffnet sich automatisch mit der Konsole." , 15 | console_msg_autoapear_off = "[CETMM] Öffnet sich nicht mehr automatisch mit der Konsole." , 16 | console_msg_dofile_run = "[CETMM] Führe %{dofilename} aus." , 17 | console_msg_dofile_done = "[CETMM] Fertig." , 18 | window_title = "Cyber Engine Tweaks Mod Manager" , 19 | button_dofiles = "Dofile Mods" , 20 | button_scan = "Scan" , 21 | button_autoscan_on = "Auto Scan an" , 22 | button_autoscan_off = "Auto Scan aus" , 23 | button_autoappear_on = "Automatisch öffnen an" , 24 | button_autoappear_off = "Automatisch öffnen aus" , 25 | text_help_manager_1 = "Drücke [Scan] um nach installierten Cyber Engine Tweaks Mods zu scannen." , 26 | text_help_manager_2 = "Nutze die Boxen um die Mods zu (de)aktivieren." , 27 | text_help_manager_3 = "Wechsele zu [Fenstermodus ohne Rand] in [Einstellungen] - [Video] um beim drücken von [Scan] nicht auf den Desktop geworfen zu werden." , 28 | text_help_manager_4 = "Nach dem (de)aktivieren von Mods, drücke den [Reload ALL Mods] Knopf in der Knosole um alle Mods neu zu laden." , 29 | text_help_manager_5 = "Drücke [Auto Scan] um den Auto Scan zu aktivieren." , 30 | text_help_dofiles_1 = "Hier kannst du deine lieblings \"dofile()\" lua mods per Knopfdruck ausführen." , 31 | text_help_dofiles_2 = "Drücke den [Dofile Ordner] Knopf um dieses Feature zu nutzen. Kopiere nun deine *.lua mods welche mit \"dofile()\" ausgeführt werden sollen hier hinein." , 32 | text_help_dofiles_3 = "Drücke [Scan] um die Mod Liste zu aktualisieren." , 33 | text_help_dofiles_4 = "Drücke den [Run] Knopf vor den Mods, nachdem die Mod Liste geladen ist, um diese per Knopfdruck auszuführen. Nie wieder dofile()!" , 34 | text_help_dofiles_5 = "Wenn du möchtest kannst du die beispiel Dofile Mods löschen." , 35 | text_no_dofiles = "Du hast keine dofile mods..." , 36 | text_please_scan = "Bitte scanne zuerst nach mods..." , 37 | button_mods_folder = "Mods Ordner" , 38 | button_dofile_folder = "Dofile Ordner" , 39 | button_dofile_run = "Run" , -- German translation would be too long for the button 40 | console_msg_mod_enable = "[CETMM] %{modname} wurde aktiviert." , 41 | console_msg_mod_enable_error = "[CETMM] Fehler beim aktivieren von %{modname}" , 42 | console_msg_mod_disable = "[CETMM] %{modname} wurde deaktiviert." , 43 | console_msg_mod_disable_error = "[CETMM] Fehler beim deaktivieren von %{modname}" , 44 | text_select_settings = "Einstellungen" , 45 | text_select_lang = "Wähle eine Sprache aus (Benötigt evtl. Schriftart)", 46 | tooltip_btn_settings = "Einstellungen" , 47 | tooltip_btn_help = "Hilfe", 48 | -- text_error_window_1 = "Error!!" , 49 | -- text_error_window_2 = "CET Mod Manager failed to load it's file module!" , 50 | -- text_error_window_3 = "Please make sure it's installed correctly." , 51 | -- text_error_window_4 = "1. Try to uninstall the old version first, and make a clean installation." , 52 | -- text_error_window_5 = "2. If you are using vortex, try to install manually." , 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/lang/en_us.lua: -------------------------------------------------------------------------------- 1 | return { 2 | en_us = { 3 | console_msg_loaded1 = "************************************************" , 4 | console_msg_loaded2 = " Cyber Engine Tweaks Mod Manager Loaded... " , 5 | console_msg_loaded3 = " Please bind a hotkey in Cyber Engine Tweaks, " , 6 | console_msg_loaded4 = " if this is your first time launch. " , 7 | console_msg_loaded5 = "************************************************" , 8 | hotkey_manager = "Mod Manager Interface" , 9 | hotkey_dofiles = "Dofile Interface" , 10 | console_msg_scan = "[CETMM] Mod scan complete." , 11 | console_msg_autoscan_on = "[CETMM] Auto scan enabled." , 12 | console_msg_autoscan_off = "[CETMM] Auto scan disabled." , 13 | console_msg_autoapear_on = "[CETMM] Now automatically opens with console." , 14 | console_msg_autoapear_off = "[CETMM] No longer automatically opens with console." , 15 | console_msg_dofile_run = "[CETMM] Executing %{dofilename}." , 16 | console_msg_dofile_done = "[CETMM] Done." , 17 | window_title = "Cyber Engine Tweaks Mod Manager" , 18 | button_dofiles = "Dofile Mods" , 19 | button_scan = "Scan" , 20 | button_autoscan_on = "Auto Scan On" , 21 | button_autoscan_off = "Auto Scan Off" , 22 | button_autoappear_on = "Auto Appear On" , 23 | button_autoappear_off = "Auto Appear Off" , 24 | text_help_manager_1 = "Press [Scan] to scan the Cyber Engine Tweaks mods you have installed." , 25 | text_help_manager_2 = "Tick/untick the checkbox to enable/disable mods." , 26 | text_help_manager_3 = "Change [Windowed Mode] in Game\'s [Settings] - [Video] to [Windows Borderless] to avoid being thrown out to desktop when pressing [Scan]." , 27 | text_help_manager_4 = "After Enabling/Disabling mods, press the [Reload ALL Mods] button on console to reload the mods." , 28 | text_help_manager_5 = "Press [Auto Scan] button to enable auto scan when the mod manager is loaded." , 29 | text_help_dofiles_1 = "You can run your favorite \"dofile()\" lua mods here with a press of button." , 30 | text_help_dofiles_2 = "To use this feature, press the [Dofile Folder] button on the button to open the folder. Copy your *.lua mod that runs with \"dofile()\" in here." , 31 | text_help_dofiles_3 = "Press [Scan] button to refresh the mod list." , 32 | text_help_dofiles_4 = "After the mod list has been loaded, press the [Run] button in front of them to run them with a press of button. No moar dofile()!" , 33 | text_help_dofiles_5 = "You can delete the example dofile modes if you want." , 34 | text_no_dofiles = "You don't have any dofile mods..." , 35 | text_please_scan = "Please scan the mods first..." , 36 | button_mods_folder = "Mods Folder" , 37 | button_dofile_folder = "Dofile Folder" , 38 | button_dofile_run = "Run" , 39 | console_msg_mod_enable = "[CETMM] %{modname} has been enabled." , 40 | console_msg_mod_enable_error = "[CETMM] Error when trying to enable %{modname}" , 41 | console_msg_mod_disable = "[CETMM] %{modname} has been disabled." , 42 | console_msg_mod_disable_error = "[CETMM] Error when trying to disable %{modname}" , 43 | text_select_lang = "Selecte a Language (Needs font support)", 44 | tooltip_btn_howto_change_font = "How to change font", 45 | text_select_settings = "Settings" , 46 | tooltip_btn_settings = "Settings" , 47 | tooltip_btn_help = "Help" , 48 | text_error_window_1 = "Error!!" , 49 | text_error_window_2 = "CET Mod Manager failed to load it's file module!" , 50 | text_error_window_3 = "Please make sure it's installed correctly." , 51 | text_error_window_4 = "1. Try to uninstall the old version first, and make a clean installation." , 52 | text_error_window_5 = "2. If you are using vortex, try to install manually." , 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/lang/example.lua: -------------------------------------------------------------------------------- 1 | return { 2 | example = { --Example needs to be changed to language code. 3 | console_msg_loaded1 = "************************************************" , 4 | console_msg_loaded2 = " Cyber Engine Tweaks Mod Manager Loaded... " , 5 | console_msg_loaded3 = " Please bind a hotkey in Cyber Engine Tweaks, " , 6 | console_msg_loaded4 = " if this is your first time launch. " , 7 | console_msg_loaded5 = "************************************************" , 8 | hotkey_manager = "Mod Manager Interface" , 9 | hotkey_dofiles = "Dofile Interface" , 10 | console_msg_scan = "[CETMM] Mod scan complete." , 11 | console_msg_autoscan_on = "[CETMM] Auto scan enabled." , 12 | console_msg_autoscan_off = "[CETMM] Auto scan disabled." , 13 | console_msg_autoapear_on = "[CETMM] Now automatically opens with console." , 14 | console_msg_autoapear_off = "[CETMM] No longer automatically opens with console." , 15 | console_msg_dofile_run = "[CETMM] Executing %{dofilename}." , 16 | console_msg_dofile_done = "[CETMM] Done." , 17 | window_title = "Cyber Engine Tweaks Mod Manager" , 18 | button_dofiles = "Dofile Mods" , 19 | button_scan = "Scan" , 20 | button_autoscan_on = "Auto Scan On" , 21 | button_autoscan_off = "Auto Scan Off" , 22 | button_autoappear_on = "Auto Appear On" , 23 | button_autoappear_off = "Auto Appear Off" , 24 | text_help_manager_1 = "Press [Scan] to scan the Cyber Engine Tweaks mods you have installed." , 25 | text_help_manager_2 = "Tick/untick the checkbox to enable/disable mods." , 26 | text_help_manager_3 = "Change [Windowed Mode] in Game\'s [Settings] - [Video] to [Windows Borderless] to avoid being thrown out to desktop when pressing [Scan]." , 27 | text_help_manager_4 = "After Enabling/Disabling mods, press the [Reload ALL Mods] button on console to reload the mods." , 28 | text_help_manager_5 = "Press [Auto Scan] button to enable auto scan when the mod manager is loaded." , 29 | text_help_dofiles_1 = "You can run your favorite \"dofile()\" lua mods here with a press of button." , 30 | text_help_dofiles_2 = "To use this feature, press the [Dofile Folder] button on the button to open the folder. Copy your *.lua mod that runs with \"dofile()\" in here." , 31 | text_help_dofiles_3 = "Press [Scan] button to refresh the mod list." , 32 | text_help_dofiles_4 = "After the mod list has been loaded, press the [Run] button in front of them to run them with a press of button. No moar dofile()!" , 33 | text_help_dofiles_5 = "You can delete the example dofile modes if you want." , 34 | text_no_dofiles = "You don't have any dofile mods..." , 35 | text_please_scan = "Please scan the mods first..." , 36 | button_mods_folder = "Mods Folder" , 37 | button_dofile_folder = "Dofile Folder" , 38 | button_dofile_run = "Run" , 39 | console_msg_mod_enable = "[CETMM] %{modname} has been enabled." , 40 | console_msg_mod_enable_error = "[CETMM] Error when trying to enable %{modname}" , 41 | console_msg_mod_disable = "[CETMM] %{modname} has been disabled." , 42 | console_msg_mod_disable_error = "[CETMM] Error when trying to disable %{modname}" , 43 | text_select_lang = "Selecte a Language (Needs font support)", 44 | text_select_settings = "Settings" , 45 | tooltip_btn_settings = "Settings" , 46 | tooltip_btn_help = "Help" , 47 | text_error_window_1 = "Error!!" , 48 | text_error_window_2 = "CET Mod Manager failed to load it's file module!" , 49 | text_error_window_3 = "Please make sure it's installed correctly." , 50 | text_error_window_4 = "1. Try to uninstall the old version first, and make a clean installation." , 51 | text_error_window_5 = "2. If you are using vortex, try to install manually." , 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /scripts/lang/fr_fr.lua: -------------------------------------------------------------------------------- 1 | -- Translator : ReActif 2 | return { 3 | fr_fr = { 4 | console_msg_loaded1 = "************************************************" , 5 | console_msg_loaded2 = " Cyber Engine Tweaks Mod Manager est chargé... " , 6 | console_msg_loaded3 = " Lier un raccourci dans Cyber Engine Tweaks, " , 7 | console_msg_loaded4 = " si c'est votre premier lancement. " , 8 | console_msg_loaded5 = "************************************************" , 9 | hotkey_manager = "Interface de Mod Manager" , 10 | hotkey_dofiles = "Interface de Dofile" , 11 | console_msg_scan = "[CETMM] Analyse du mod terminée." , 12 | console_msg_autoscan_on = "[CETMM] Analyse auto activée." , 13 | console_msg_autoscan_off = "[CETMM] Analyse auto désactivée." , 14 | console_msg_autoapear_on = "[CETMM] S'ouvre automatiquement avec la console." , 15 | console_msg_autoapear_off = "[CETMM] Ne s'ouvre plus automatiquement avec la console." , 16 | console_msg_dofile_run = "[CETMM] Exécution de %{dofilename}." , 17 | console_msg_dofile_done = "[CETMM] Terminé." , 18 | window_title = "Cyber Engine Tweaks Mod Manager" , 19 | button_dofiles = "Mods Dofile" , 20 | button_scan = "Scanner" , 21 | button_autoscan_on = "Scanner auto ON" , 22 | button_autoscan_off = "Scanner auto OFF" , 23 | button_autoappear_on = "Apparition auto ON" , 24 | button_autoappear_off = "Apparition auto OFF" , 25 | text_help_manager_1 = "Appuyez sur [Scanner] pour analyser les mods CET que vous avez installés." , 26 | text_help_manager_2 = "Cochez/décochez la case pour activer/désactiver les mods." , 27 | text_help_manager_3 = "Changez le [Mode fenêtré] dans [Paramètres] - [Vidéo] du jeu en [Fenêtré sans bordure] pour éviter d'être basculer sur le bureau en appuyant sur [Scanner]." , 28 | text_help_manager_4 = "Après avoir activé/désactivé les mods, appuyez sur le bouton [Reload all mods] de la console pour recharger les mods." , 29 | text_help_manager_5 = "Appuyez sur le bouton [Auto Scan] pour activer le scan automatique lorsque le gestionnaire de mods est chargé." , 30 | text_help_dofiles_1 = "Vous pouvez exécuter vos mods lua favoris \"dofile()\" ici en appuyant sur un bouton." , 31 | text_help_dofiles_2 = "Pour utiliser cette fonction, appuyez sur le bouton [Dossier Dofile] pour ouvrir le dossier. Copiez votre mod *.lua qui fonctionne avec \"dofile()\" dans ce dossier." , 32 | text_help_dofiles_3 = "Appuyez sur le bouton [Scanner] pour actualiser la liste des modules." , 33 | text_help_dofiles_4 = "Une fois la liste des mods chargée, appuyez sur le bouton [Run] en face de chacun d'eux pour les exécuter en appuyant sur le bouton. Plus besoin de dofile() !" , 34 | text_help_dofiles_5 = "Vous pouvez supprimer les exemples de mods dofile si vous le souhaitez." , 35 | text_no_dofiles = "Vous n'avez pas de mods dofile..." , 36 | text_please_scan = "Veuillez d'abord scanner les mods..." , 37 | button_mods_folder = "Dossier Mods" , 38 | button_dofile_folder = "Dossier Dofile" , 39 | button_dofile_run = "Exécuter" , 40 | console_msg_mod_enable = "[CETMM] %{modname} a été activé." , 41 | console_msg_mod_enable_error = "[CETMM] Erreur d'activation de %{modname}." , 42 | console_msg_mod_disable = "[CETMM] %{modname} a été désactivé." , 43 | console_msg_mod_disable_error = "[CETMM] Erreur de désactivation de %{modname}." , 44 | text_select_lang = "Sélection de langue (nécessite une police adapté)" , 45 | tooltip_btn_howto_change_font = "Comment changer de police" , 46 | text_select_settings = "Paramètres" , 47 | tooltip_btn_settings = "Paramètres" , 48 | tooltip_btn_help = "Aide" , 49 | text_error_window_1 = "Erreur !" , 50 | text_error_window_2 = "CET Mod Manager n'a pas réussi à charger son module de fichier !" , 51 | text_error_window_3 = "Assure-toi qu'il est installé correctement." , 52 | text_error_window_4 = "1. Essaie de désinstaller l'ancienne version d'abord, et fais une installation propre." , 53 | text_error_window_5 = "2. Si vous utilisez vortex, essayez d'installer manuellement." , 54 | } 55 | } -------------------------------------------------------------------------------- /scripts/lang/ja_jp.lua: -------------------------------------------------------------------------------- 1 | -- Translator : Mingming Cui 2 | return { 3 | ja_jp = { 4 | console_msg_loaded1 = "**********************************************************" , 5 | console_msg_loaded2 = " Cyber Engine Tweaksモッドマネージャーがロードされました" , 6 | console_msg_loaded3 = " 初めての起動される場合は、Cyber Engine Tweaksで" , 7 | console_msg_loaded4 = " ホットキーを設定してください" , 8 | console_msg_loaded5 = "**********************************************************" , 9 | hotkey_manager = "モッドマネージャー界面" , 10 | hotkey_dofiles = "Dofileスクリプト界面" , 11 | console_msg_scan = "[CETMM] モッドスキャンが完了しました。" , 12 | console_msg_autoscan_on = "[CETMM] 自動スキャンが有効化されました。" , 13 | console_msg_autoscan_off = "[CETMM] 自動スキャンが無効化されました。" , 14 | console_msg_autoapear_on = "[CETMM] コンソールと一緒に自動的に開くようになりました。" , 15 | console_msg_autoapear_off = "[CETMM] コンソールと一緒に自動的に開かないようになりました。" , 16 | console_msg_dofile_run = "[CETMM] %{dofilename}実行中。" , 17 | console_msg_dofile_done = "[CETMM] 実行完了。" , 18 | window_title = "Cyber Engine Tweaksモッドマネージャー" , 19 | button_dofiles = "Dofileスクリプト" , 20 | button_scan = "スキャン" , 21 | button_autoscan_on = "自動スキャンオン" , 22 | button_autoscan_off = "自動スキャンオフ" , 23 | button_autoappear_on = "自動表示オン" , 24 | button_autoappear_off = "自動表示オフ" , 25 | text_help_manager_1 = "「スキャン」を押して、インストールしたCyber Engine Tweaksモッドをスキャンします。" , 26 | text_help_manager_2 = "チェックボックスをオン/オフにして、モッドを有効か/無効かにすることができます。" , 27 | text_help_manager_3 = "ゲームの「設定」-「ビデオ」-「画面モード」を「ボーダレスウィンドウ」に変更したら、「スキャン」を押したときにデスクトップに戻されないようなります。" , 28 | text_help_manager_4 = "モッドを有効/無効にした後、コンソールの「Reload ALL Mods」ボタンを押してモッドをリロードしてください。" , 29 | text_help_manager_5 = "「自動スキャン」ボタンを押すと、モッドマネージャーがロードされるときに自動的にモッドをスキャンすることになります。" , 30 | text_help_dofiles_1 = "お気に入りの\"dofile()\"スクリプトをボタン一つで実行することができます。" , 31 | text_help_dofiles_2 = "この機能を使用するには、「Dofileフォルダ」ボタンを押して、フォルダを開いてください。そして、*.lua のスクリプトをこのフォルダにコピーしてください。" , 32 | text_help_dofiles_3 = "「スキャン」ボタンを押して、モッドリストを更新してください。" , 33 | text_help_dofiles_4 = "モッドリストがロードされたら、スクリプト前の「実行」ボタンを押すだけで実行することができます。さらばdofile()!" , 34 | text_help_dofiles_5 = "必要に応じて、サンプルのdofileスクリプトを削除してください。" , 35 | text_no_dofiles = "dofileスクリプがありません..." , 36 | text_please_scan = "モッドをスキャンしてください..." , 37 | button_mods_folder = "モッドフォルダ" , 38 | button_dofile_folder = "Dofileフォルダ" , 39 | button_dofile_run = "実行" , 40 | console_msg_mod_enable = "[CETMM] %{modname}が有効化されました。" , 41 | console_msg_mod_enable_error = "[CETMM] %{modname}を有効化するときにエラーが発生されました。" , 42 | console_msg_mod_disable = "[CETMM] %{modname}が無効化されました。" , 43 | console_msg_mod_disable_error = "[CETMM] %{modname}を無効化するときにエラーが発生されました。" , 44 | text_select_settings = "設定" , 45 | text_select_lang = "言語の選択(フォントのサポートが必要)" , 46 | tooltip_btn_settings = "設定" , 47 | tooltip_btn_help = "ヘルプ", 48 | text_error_window_1 = "エラー!!" , 49 | text_error_window_2 = "CETモッドマネージャーがモジュールのロードに失敗しました!" , 50 | -- text_error_window_3 = "Please make sure it's installed correctly." , 51 | -- text_error_window_4 = "1. Try to uninstall the old version first, and make a clean installation." , 52 | -- text_error_window_5 = "2. If you are using vortex, try to install manually." , 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/lang/lang.lua: -------------------------------------------------------------------------------- 1 | return { 2 | { id = "en_us", name = "English" }, 3 | { id = "zh_cn", name = "简体中文 (Simplified Chinese)" }, 4 | { id = "zh_tw", name = "正體中文 (Traditional Chinese)" }, 5 | { id = "ja_jp", name = "日本語 (Japanese)" }, 6 | { id = "ru_ru", name = "Русский (Russian)" }, 7 | { id = "de_de", name = "Deutsch (German)" }, 8 | { id = "tr_tc", name = "Türkçe (Turkish)" }, 9 | { id = "ro_ro", name = "Limba Română (Romanian)" }, 10 | { id = "pt_br", name = "português (Brazilian Portuguese)" }, 11 | { id = "fr_fr", name = "Français (French)"}, 12 | -- { id = "example", name = "Example Language (Example)"}, 13 | } 14 | -------------------------------------------------------------------------------- /scripts/lang/pt_br.lua: -------------------------------------------------------------------------------- 1 | -- Translator: mathfelin 2 | return { 3 | pt_br = { 4 | console_msg_loaded1 = "************************************************" , 5 | console_msg_loaded2 = " Cyber Engine Tweaks Mod Manager Carregado... " , 6 | console_msg_loaded3 = " Por favor, aperte uma tecla de atalho em Cyber Engine Tweaks, " , 7 | console_msg_loaded4 = " esta e a sua primeira vez de lancamento. " , 8 | console_msg_loaded5 = "************************************************" , 9 | hotkey_manager = "Interface do Mod Manager" , 10 | hotkey_dofiles = "Interface de Arquivo" , 11 | console_msg_scan = "[CETMM] Varredura de Mod Completa." , 12 | console_msg_autoscan_on = "[CETMM] Varredura automatica ativado." , 13 | console_msg_autoscan_off = "[CETMM] Varredura automatica desativado." , 14 | console_msg_autoapear_on = "[CETMM] Abre automaticamente o console." , 15 | console_msg_autoapear_off = "[CETMM] Não abre automaticamente o console." , 16 | console_msg_dofile_run = "[CETMM] Executando %{nome do ficheiro}." , 17 | console_msg_dofile_done = "[CETMM] Feito." , 18 | window_title = "Cyber Engine Tweaks Mod gestor" , 19 | button_dofiles = "Modos de arquivo" , 20 | button_scan = "Analisar" , 21 | button_autoscan_on = "Varredura automatica ligado" , 22 | button_autoscan_off = "Varredura automatica desligado" , 23 | button_autoappear_on = "Aparecimento automatico ligado" , 24 | button_autoappear_off = "Aparecimento automatico desligado" , 25 | text_help_manager_1 = "Pressionar [Varrer] para analisar mods instalados em Cyber Engine Tweaks." , 26 | text_help_manager_2 = "Marcar/desmarcar a caixa de verificação para ativar/desativar mods." , 27 | text_help_manager_3 = "Alterar [Windowed Mode] em Jogo\'s [Configurações] - [Video] para [Janelas sem Bordas] para evitar ser atirado para o ambiente de trabalho, pressionar [Varrer]." , 28 | text_help_manager_4 = "Depois de habilitar/desabilitar os mods, pressione o [Recarregar TODOS os Mods] botão no console para recarregar os mods." , 29 | text_help_manager_5 = "Pressionar [Varredura automatica] para ativar a varredura automática quando o mod gestor é carregado." , 30 | text_help_dofiles_1 = "Pode executar o seu favorito \"arquivo()\" lua mods aqui com uma prensa de botão." , 31 | text_help_dofiles_2 = "Para utilizar esta funcionalidade, pressionar o botão [Arquivo pasta] para abrir a pasta. Copie o seu *.lua mod que corre com \"arquivo()\" aqui." , 32 | text_help_dofiles_3 = "Pressionar [Varrer] botão para atualizar a lista mod." , 33 | text_help_dofiles_4 = "Após a lista de mods ser carregada, pressionar o botão [Executar] botão na frente deles para os executar com um apertar de botão. Nenhum arquivo do moar()!" , 34 | text_help_dofiles_5 = "Pode apagar os modos de arquivo de exemplo, se quiser." , 35 | text_no_dofiles = "Não tem nenhum mods de arquivo..." , 36 | text_please_scan = "Por favor, escaneie os mods primeiro..." , 37 | button_mods_folder = "Pasta de Mods" , 38 | button_dofile_folder = "Arquivar Pasta" , 39 | button_dofile_run = "Executar" , 40 | console_msg_mod_enable = "[CETMM] %{nome do mod} foi ativado." , 41 | console_msg_mod_enable_error = "[CETMM] Erro ao tentar ativar %{nome do mod}" , 42 | console_msg_mod_disable = "[CETMM] %{nome do mod} foi desativado." , 43 | console_msg_mod_disable_error = "[CETMM] Erro ao tentar desativar %{nome do mod}" , 44 | text_select_lang = "Seleccionar um idioma (Necessita de suporte de fontes)", 45 | text_select_settings = "Configurações" , 46 | tooltip_btn_settings = "Configurações" , 47 | tooltip_btn_help = "Ajuda" , 48 | text_error_window_1 = "Erro!!" , 49 | text_error_window_2 = "CET Mod gestor Não carregou o seu modulo de arquivo!" , 50 | text_error_window_3 = "Por favor, certifique-se de que esta instalado correctamente." , 51 | text_error_window_4 = "1. desinstalar primeiro a versao antiga, e fazer uma instalacao limpa." , 52 | text_error_window_5 = "2. Se estiver a utilizar o vortex, tente instalar manualmente." , 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/lang/ro_ro.lua: -------------------------------------------------------------------------------- 1 | -- Translator: Maddmaniak 2 | return { 3 | ro_ro = { 4 | console_msg_loaded1 = "************************************************" , 5 | console_msg_loaded2 = " Cyber Engine Tweaks Mod Manager Incarcat... " , 6 | console_msg_loaded3 = " Setati o tasta in Cyber Engine Tweaks, " , 7 | console_msg_loaded4 = " daca sunteti la prima setare/lansare. " , 8 | console_msg_loaded5 = "************************************************" , 9 | hotkey_manager = "Interfata Mod Manager" , 10 | hotkey_dofiles = "Dofile Interfata" , 11 | console_msg_scan = "[CETMM] Mod scanare complet." , 12 | console_msg_autoscan_on = "[CETMM] Auto scanare activata." , 13 | console_msg_autoscan_off = "[CETMM] Auto scanare dezactivata." , 14 | console_msg_autoapear_on = "[CETMM] Acum se deschide automat cu consola." , 15 | console_msg_autoapear_off = "[CETMM] Nu se mai deschide automat cu consola." , 16 | console_msg_dofile_run = "[CETMM] Se executa %{dofilename}." , 17 | console_msg_dofile_done = "[CETMM] Terminat." , 18 | window_title = "Cyber Engine Tweaks Mod Manager" , 19 | button_dofiles = "Dofile Mod" , 20 | button_scan = "Scanare" , 21 | button_autoscan_on = "Auto Scanare pornita" , 22 | button_autoscan_off = "Auto Scanare oprita" , 23 | button_autoappear_on = "Auto Aparitie pornit" , 24 | button_autoappear_off = "Auto Aparitie oprit" , 25 | text_help_manager_1 = "Apasa [Scan] pentru a scana modurile Cyber Engine Tweaks pe care le-ati instalat." , 26 | text_help_manager_2 = "Bifati / debifati caseta de selectare pentru a activa / dezactiva modurile." , 27 | text_help_manager_3 = "Schimbati [Modul Windowed] in [Setari] - [Video] a jocului din [Windows fara margini- Borderless] pentru a evita iesirea aplicatiei pe desktop cand apasati [Scanare]." , 28 | text_help_manager_4 = "Dupa activarea / dezactivarea modurilor, apasati butonul [Reincarcati toate modurile] de pe consolaă pentru a reincarca modurile." , 29 | text_help_manager_5 = "Apasati butonul [Scanare automata] pentru a activa scanarea automata la incarcarea mod managerului." , 30 | text_help_dofiles_1 = "Puteti rula modurile preferate \"dofile ()\" .lua aici, doar la o apasare de buton." , 31 | text_help_dofiles_2 = "Pentru a utiliza aceasta caracteristica, apasati butonul [Dofile Folder] pentru a deschide folderul. Copiati modul dvs. * .lua care ruleaza cu \"dofile ()\" aici." , 32 | text_help_dofiles_3 = "Apasati butonul [Scan] pentru a re-incarca lista cu moduri. " , 33 | text_help_dofiles_4 = "Dupaă ce lista de moduri a fost incarcata, apasati butonul [Run] din fata lor pentru a le rula cu o apasare de buton. Fara fisier moar ()!" , 34 | text_help_dofiles_5 = "Puteti șsterge exemplele de moduri de fisier dofile, daca doriti." , 35 | text_no_dofiles = "Nu aveti niciun mod de fisier do..." , 36 | text_please_scan = "Va rugam saăscanati mai intai modificarile(modurile)..." , 37 | button_mods_folder = "Foldere Mods. " , 38 | button_dofile_folder = "Foldere Dofile. " , 39 | button_dofile_run = "Ruleaza " , 40 | console_msg_mod_enable = "[CETMM] %{modname} a fost activat. " , 41 | console_msg_mod_enable_error = "[CETMM] Eroare la incarcarea modului.. %{modname}" , 42 | console_msg_mod_disable = "[CETMM] %{modname} a fost dezactivat." , 43 | console_msg_mod_disable_error = "[CETMM] Eroare la dezactivarea modului.. %{modname}" , 44 | text_select_lang = "Selectati o limba (Necesita suport pentru fonturi)", 45 | text_select_settings = "Setari" , 46 | tooltip_btn_settings = "Setari" , 47 | tooltip_btn_help = "Ajutor" , 48 | -- text_error_window_1 = "Error!!" , 49 | -- text_error_window_2 = "CET Mod Manager failed to load it's file module!" , 50 | -- text_error_window_3 = "Please make sure it's installed correctly." , 51 | -- text_error_window_4 = "1. Try to uninstall the old version first, and make a clean installation." , 52 | -- text_error_window_5 = "2. If you are using vortex, try to install manually." , 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/lang/ru_ru.lua: -------------------------------------------------------------------------------- 1 | -- Translator : vanja-san 2 | return { 3 | ru_ru = { 4 | console_msg_loaded1 = "****************************************************" , 5 | console_msg_loaded2 = " Менеджер модов Cyber Engine Tweaks загружен... " , 6 | console_msg_loaded3 = " Привяжите горячую клавишу в Cyber Engine Tweaks, " , 7 | console_msg_loaded4 = " если это ваш первый запуск. " , 8 | console_msg_loaded5 = "****************************************************" , 9 | hotkey_manager = "Интерфейс менеджера модов" , 10 | hotkey_dofiles = "Интерфейс Dofile" , 11 | console_msg_scan = "[CETMM] Сканирование модов завершено." , 12 | console_msg_autoscan_on = "[CETMM] Автосканирование включено." , 13 | console_msg_autoscan_off = "[CETMM] Автосканирование выключено." , 14 | console_msg_autoapear_on = "[CETMM] Теперь автоматически открывается с консолью." , 15 | console_msg_autoapear_off = "[CETMM] Больше не открывается автоматически с консолью." , 16 | console_msg_dofile_run = "[CETMM] Выполнение %{dofilename}." , 17 | console_msg_dofile_done = "[CETMM] Готово." , 18 | window_title = "Менеджер модов Cyber Engine Tweaks" , 19 | button_dofiles = "Dofile моды" , 20 | button_scan = "Сканировать" , 21 | button_autoscan_on = "Автосканирование: ВКЛЮЧЕНО" , 22 | button_autoscan_off = "Автосканирование: ВЫКЛЮЧЕНО" , 23 | button_autoappear_on = "Автооткрытие: ВКЛЮЧЕНО" , 24 | button_autoappear_off = "Автооткрытие: ВЫКЛЮЧЕНО" , 25 | text_help_manager_1 = "Нажмите [Сканировать], чтобы Cyber Engine Tweaks произвёл поиск установленных модов." , 26 | text_help_manager_2 = "Установите/снимите флажок для включения/отключения модов." , 27 | text_help_manager_3 = "Измените [Оконный режим] в игре: [Настройки] - [Видео] на [Оконный без полей], чтобы избежать вылета игры на рабочий стол при нажатии [Сканировать]." , 28 | text_help_manager_4 = "После включения/отключения модов, нажмите кнопку [Перезагрузить все моды] на консоли, чтобы перезагрузить моды." , 29 | text_help_manager_5 = "Нажмите кнопку [Автосканирование], чтобы включить автоматическое сканирование при загрузке менеджера модов." , 30 | text_help_dofiles_1 = "Здесь вы можете запускать свои любимые lua-моды \"dofile()\" одним нажатием кнопки." , 31 | text_help_dofiles_2 = "Чтобы использовать эту функцию, нажмите кнопку [Папка Dofile], чтобы открыть папку. Скопируйте сюда свой мод *.lua который работает с \"dofile()\"." , 32 | text_help_dofiles_3 = "Нажмите кнопку [Сканировать], чтобы обновить список модов." , 33 | text_help_dofiles_4 = "После загрузки списка модов нажмите кнопку [Запустить] перед ними, чтобы запустить их одним нажатием кнопки. Теперь без dofile()!" , 34 | text_help_dofiles_5 = "Если хотите, вы можете удалить примеры режимов dofile." , 35 | text_no_dofiles = "У вас нет dofile модов..." , 36 | text_please_scan = "Сначала просканируйте моды..." , 37 | button_mods_folder = "Папка модов" , 38 | button_dofile_folder = "Папка Dofile" , 39 | button_dofile_run = "Запустить" , 40 | console_msg_mod_enable = "[CETMM] %{modname}: Включен" , 41 | console_msg_mod_enable_error = "[CETMM] %{modname}: Ошибка включения" , 42 | console_msg_mod_disable = "[CETMM] %{modname}: Отключен" , 43 | console_msg_mod_disable_error = "[CETMM] %{modname}: Ошибка отключения" , 44 | text_select_lang = "Выберите язык (Требуется поддержка шрифтов)", 45 | text_select_settings = "Настройки" , 46 | tooltip_btn_settings = "Настройки" , 47 | tooltip_btn_help = "Помощь", 48 | text_error_window_1 = "Ошибка!!!" , 49 | text_error_window_2 = "Менеджер модов CET: Не удалось загрузить модуль!" , 50 | text_error_window_3 = "Убедитесь, что он установлен правильно." , 51 | text_error_window_4 = "1. Попробуйте сначала удалить старую версию и произвести чистую установку." , 52 | text_error_window_5 = "2. Если вы используете Vortex, попробуйте установить его вручную." , 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/lang/tr_tc.lua: -------------------------------------------------------------------------------- 1 | --Translator: sebepne 2 | return { 3 | tr_tc = { 4 | console_msg_loaded1 = "********************************************************" , 5 | console_msg_loaded2 = " Cyber Engine Tweaks Mod Yöneticisi Yüklendi... " , 6 | console_msg_loaded3 = " Lütfen Cyber ​​Engine Tweaks'e bir kısayol tuşu bağlayın, " , 7 | console_msg_loaded4 = " Bunu ilk kez başlatıyorsanız. " , 8 | console_msg_loaded5 = "********************************************************" , 9 | hotkey_manager = "Mod Yöneticisi Arayüzü" , 10 | hotkey_dofiles = "Dofile Arayüzü" , 11 | console_msg_scan = "[CETMM] Mod taraması tamamlandı." , 12 | console_msg_autoscan_on = "[CETMM] Otomatik tarama etkinleştirildi." , 13 | console_msg_autoscan_off = "[CETMM] Otomatik tarama devre dışı bırakıldı." , 14 | console_msg_autoapear_on = "[CETMM] Artık konsol ile otomatik olarak açılıyor." , 15 | console_msg_autoapear_off = "[CETMM] Artık konsol ile otomatik olarak açılmıyor." , 16 | console_msg_dofile_run = "[CETMM] Yürütülüyor %{dofilename}." , 17 | console_msg_dofile_done = "[CETMM] Bitti." , 18 | window_title = "Cyber ​​Engine Tweaks Mod Yöneticisi" , 19 | button_dofiles = "Dofile Modları" , 20 | button_scan = "Tarama" , 21 | button_autoscan_on = "Otomatik Tarama Açık" , 22 | button_autoscan_off = "Otomatik Tarama Kapalı" , 23 | button_autoappear_on = "Otomatik Görünme Açık" , 24 | button_autoappear_off = "Otomatik Görünme Kapalı" , 25 | text_help_manager_1 = "Yüklediğiniz Cyber Engine Tweaks modlarını taramak için [Tara] ya basın." , 26 | text_help_manager_2 = "Modları etkinleştirmek devre dışı bırakmak için onay kutusunu işaretleyin işaretini kaldırın." , 27 | text_help_manager_3 = "[Tara] tuşuna basıldığında masaüstüne atılmasını önlemek için Oyunlar [Ayarlar] - [Video] 'da [Pencereli Mod]' u [Windows Kenarlıksız] olarak değiştirin." , 28 | text_help_manager_4 = "Modları Etkinleştirdikten Devre Dışı Bıraktıktan sonra, modları yeniden yüklemek için konsoldaki [TÜM Modları Yeniden Yükle] düğmesine basın.." , 29 | text_help_manager_5 = "Mod yöneticisi yüklendiğinde otomatik taramayı etkinleştirmek için [Otomatik Tarama] düğmesine basın." , 30 | text_help_dofiles_1 = "Favori \"dofile()\" lua modlarınızı burada bir düğmeye basarak çalıştırabilirsiniz." , 31 | text_help_dofiles_2 = "Bu özelliği kullanmak için, klasörü açmak üzere düğme üzerindeki [Dofile Folder] düğmesine basın. \"dofile()\" ile çalışan .lua modunuzu buraya kopyalayın." , 32 | text_help_dofiles_3 = "Mod listesini yenilemek için [Tara] düğmesine basın." , 33 | text_help_dofiles_4 = "Mod listesi yüklendikten sonra, bir düğmeye basarak çalıştırmak için önlerindeki [Çalıştır] düğmesine basın. Moar dofile()!" , 34 | text_help_dofiles_5 = "İsterseniz örnek dofile modlarını silebilirsiniz.." , 35 | text_no_dofiles = "Dofile modunuz yok ..." , 36 | text_please_scan = "Lütfen önce modları tarayın ..." , 37 | button_mods_folder = "Mod Klasörü" , 38 | button_dofile_folder = "Dofile Klasörü" , 39 | button_dofile_run = "Çalıştır" , 40 | console_msg_mod_enable = "[CETMM] %{modname} etkinleştirildi." , 41 | console_msg_mod_enable_error = "[CETMM] Etkinleştirmeye çalışırken hata oluştu %{modname}" , 42 | console_msg_mod_disable = "[CETMM] %{modname} devre dışı bırakıldı." , 43 | console_msg_mod_disable_error = "[CETMM] Devre dışı bırakmaya çalışırken hata oluştu %{modname}" , 44 | text_select_lang = "Bir Dil Seçin (Yazı tipi desteği gerekir)", 45 | text_select_settings = "Ayarlar" , 46 | tooltip_btn_settings = "Ayarlar" , 47 | tooltip_btn_help = "Yardım" , 48 | -- text_error_window_1 = "Error!!" , 49 | -- text_error_window_2 = "CET Mod Manager failed to load it's file module!" , 50 | -- text_error_window_3 = "Please make sure it's installed correctly." , 51 | -- text_error_window_4 = "1. Try to uninstall the old version first, and make a clean installation." , 52 | -- text_error_window_5 = "2. If you are using vortex, try to install manually." , 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/lang/zh_cn.lua: -------------------------------------------------------------------------------- 1 | -- Translator : Mingming Cui 2 | return { 3 | zh_cn = { 4 | console_msg_loaded1 = "************************************************" , 5 | console_msg_loaded2 = " Cyber Engine Tweaks模组管理器已加载..." , 6 | console_msg_loaded3 = " 如果是初次安装使用,请先在Cyber Engine Tweaks" , 7 | console_msg_loaded4 = " 里设置开启界面的热键。" , 8 | console_msg_loaded5 = "************************************************" , 9 | hotkey_manager = "模组管理界面" , 10 | hotkey_dofiles = "Dofile脚本界面" , 11 | console_msg_scan = "[CETMM] 模组扫描完成。" , 12 | console_msg_autoscan_on = "[CETMM] 自动扫描已打开。" , 13 | console_msg_autoscan_off = "[CETMM] 自动扫描已关闭。" , 14 | console_msg_autoapear_on = "[CETMM] 现在跟随控制台自动显示。" , 15 | console_msg_autoapear_off = "[CETMM] 不在跟随控制台自动显示。" , 16 | console_msg_dofile_run = "[CETMM] 正在执行 %{dofilename}。" , 17 | console_msg_dofile_done = "[CETMM] 执行完毕。" , 18 | window_title = "Cyber Engine Tweaks模组管理器" , 19 | button_dofiles = "Dofile脚本" , 20 | button_scan = "扫描" , 21 | button_autoscan_on = "自动扫描已打开" , 22 | button_autoscan_off = "自动扫描已关闭" , 23 | button_autoappear_on = "自动显示已打开" , 24 | button_autoappear_off = "自动显示已关闭" , 25 | text_help_manager_1 = "点击【扫描】按钮以扫描你已安装的Cyber Engine Tweaks模组。" , 26 | text_help_manager_2 = "勾选或取消模组前的选择框以启用或禁用该模组。" , 27 | text_help_manager_3 = "把游戏【设置】-【视频】-【窗口模式】改成【无边框窗口】以避免点击【扫描】按钮时游戏弹出至桌面。" , 28 | text_help_manager_4 = "在启用或禁用模组之后,点击控制台里的【重载全部模组】按钮以生效。" , 29 | text_help_manager_5 = "点击【自动扫描】按钮以打开模组管理器加载时自动扫描的功能。" , 30 | text_help_dofiles_1 = "你可以在这里不需要输入任何代码一键运行你喜爱的“dofile()”脚本模组。" , 31 | text_help_dofiles_2 = "点击【Dofile脚本文件夹】按钮打开文件夹。把你的 *.lua 脚本放进该文件里。" , 32 | text_help_dofiles_3 = "点击【扫描】按钮以刷新脚本列表。" , 33 | text_help_dofiles_4 = "脚本列表更新之后,点击你想运行的脚本前的【执行】按钮以执行该脚本。" , 34 | text_help_dofiles_5 = "你可以随时删除这些示例脚本。" , 35 | text_no_dofiles = "你没有任何Dofile脚本..." , 36 | text_please_scan = "请先扫描模组..." , 37 | button_mods_folder = "模组文件夹" , 38 | button_dofile_folder = "Dofile脚本文件夹" , 39 | button_dofile_run = "执行" , 40 | console_msg_mod_enable = "[CETMM] 模组%{modname}已启用。" , 41 | console_msg_mod_enable_error = "[CETMM] 尝试启用模组%{modname}时发生错误" , 42 | console_msg_mod_disable = "[CETMM] 模组%{modname}已禁用。" , 43 | console_msg_mod_disable_error = "[CETMM] 尝试禁用模组%{modname}时发生错误", 44 | text_select_settings = "设置" , 45 | text_select_lang = "选择语言(需要字体支持)" , 46 | tooltip_btn_settings = "设置" , 47 | tooltip_btn_help = "帮助", 48 | text_error_window_1 = "错误!!" , 49 | text_error_window_2 = "CET模组管理器无法加载运行库!" , 50 | -- text_error_window_3 = "Please make sure it's installed correctly." , 51 | -- text_error_window_4 = "1. Try to uninstall the old version first, and make a clean installation." , 52 | -- text_error_window_5 = "2. If you are using vortex, try to install manually." , 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/lang/zh_tw.lua: -------------------------------------------------------------------------------- 1 | -- Translator : Mingming Cui 2 | return { 3 | zh_tw = { 4 | console_msg_loaded1 = "************************************************" , 5 | console_msg_loaded2 = " Cyber Engine Tweaks模組管理器已加載..." , 6 | console_msg_loaded3 = " 如果這是您的首次啟動,請在Cyber Engine Tweaks" , 7 | console_msg_loaded4 = " 中綁定一個熱鍵。 " , 8 | console_msg_loaded5 = "************************************************" , 9 | hotkey_manager = "模組管理界面" , 10 | hotkey_dofiles = "Dofile腳本界面" , 11 | console_msg_scan = "[CETMM] 模组掃描完成。" , 12 | console_msg_autoscan_on = "[CETMM] 已啟用自動掃描。" , 13 | console_msg_autoscan_off = "[CETMM] 已禁用自動掃描。" , 14 | console_msg_autoapear_on = "[CETMM] 現在隨著控制台自動打開。" , 15 | console_msg_autoapear_off = "[CETMM] 不在隨著控制台自動打開。" , 16 | console_msg_dofile_run = "[CETMM] 正在執行 %{dofilename}。" , 17 | console_msg_dofile_done = "[CETMM] 執行完畢。" , 18 | window_title = "Cyber Engine Tweaks模組管理器" , 19 | button_dofiles = "Dofile腳本" , 20 | button_scan = "掃描" , 21 | button_autoscan_on = "自動掃描已啟用" , 22 | button_autoscan_off = "自動掃描已禁用" , 23 | button_autoappear_on = "自動顯示已啟用" , 24 | button_autoappear_off = "自動顯示已禁用" , 25 | text_help_manager_1 = "按【掃描】按鈕掃描您已安裝的Cyber Engine Tweaks模組。" , 26 | text_help_manager_2 = "勾選或取消勾選模組前的複選框以啟用或禁用該模組。" , 27 | text_help_manager_3 = "將游戲的【設定】-【影像】中的【視窗模式】更改為【無邊框視窗】,以避免在按【掃描】時被彈出到桌面上。" , 28 | text_help_manager_4 = "啟用/禁用模組後,按控制台上的【Reload ALL Mods】按鈕以重新加載模組。" , 29 | text_help_manager_5 = "按【自動掃描】按鈕以啟用模組管理器加載後自動掃描的功能。" , 30 | text_help_dofiles_1 = "您可以在這裡不需要輸入任何代碼一鍵運行您喜愛的“dofile()”腳本模組。" , 31 | text_help_dofiles_2 = "按【Dofile腳本資料夾】按鈕打開資料夾。把您的 *.lua 腳本放進該文件裡。" , 32 | text_help_dofiles_3 = "按【掃描】按鈕以刷新腳本列表。" , 33 | text_help_dofiles_4 = "加載腳本列表後,按它們前面的【執行】按鈕以一鍵運行它們。" , 34 | text_help_dofiles_5 = "您可以根據需要刪除示例的Dofile腳本。" , 35 | text_no_dofiles = "您沒有任何dofile腳本..." , 36 | text_please_scan = "請先掃描模組..." , 37 | button_mods_folder = "模组資料夾" , 38 | button_dofile_folder = "Dofile腳本資料夾" , 39 | button_dofile_run = "執行" , 40 | console_msg_mod_enable = "[CETMM] 模组%{modname}已啟用。" , 41 | console_msg_mod_enable_error = "[CETMM] 嘗試啟用、%{modname}模组時出錯" , 42 | console_msg_mod_disable = "[CETMM] 模组%{modname}已禁用。" , 43 | console_msg_mod_disable_error = "[CETMM] 嘗試禁用%{modname}模组時出錯" , 44 | text_select_settings = "設置" , 45 | text_select_lang = "選擇語言(需要字體支持)" , 46 | tooltip_btn_settings = "設置" , 47 | tooltip_btn_help = "幫助", 48 | text_error_window_1 = "錯誤!!" , 49 | text_error_window_2 = "CET模組管理器無法加載運行庫!" , 50 | -- text_error_window_3 = "Please make sure it's installed correctly." , 51 | -- text_error_window_4 = "1. Try to uninstall the old version first, and make a clean installation." , 52 | -- text_error_window_5 = "2. If you are using vortex, try to install manually." , 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /scripts/modules/CETMM.lua: -------------------------------------------------------------------------------- 1 | ---@class CETMM 2 | CETMM = {} 3 | 4 | local m_gui ---@type gui 5 | local m_event ---@type event 6 | local m_hotkeys ---@type hotkeys 7 | local m_options ---@type options 8 | local m_locale ---@type locale 9 | local m_dofiles ---@type dofiles 10 | local m_version ---@type string 11 | local m_backend ---@type backend 12 | local m_uninstalled = false 13 | 14 | function CETMM.GetUISystem() 15 | return m_gui 16 | end 17 | 18 | function CETMM.GetOptions() 19 | return m_options 20 | end 21 | 22 | function CETMM.GetLocale() 23 | return m_locale 24 | end 25 | 26 | function CETMM.GetDofiles() 27 | return m_dofiles 28 | end 29 | 30 | function CETMM.GetVersion() 31 | return m_version 32 | end 33 | 34 | function CETMM.GetBackEnd() 35 | return m_backend 36 | end 37 | 38 | function CETMM.IsUninstalled() 39 | return m_uninstalled 40 | end 41 | 42 | function CETMM.Initialize() 43 | m_options = require ("modules/options") 44 | m_locale = require ("modules/locale") 45 | m_dofiles = require ("modules/dofiles") 46 | m_event = require ("modules/event") 47 | m_hotkeys = require("modules/hotkeys") 48 | m_version = require ("modules/version") 49 | 50 | -- Load config 51 | m_options.Load() 52 | m_locale.Initialize() 53 | 54 | registerForEvent("onInit", function() 55 | -- init 56 | m_backend = require ("modules/backend") 57 | m_uninstalled = m_backend.GetUninstall().IsAsiRemoved() 58 | if not m_uninstalled then 59 | m_backend.GetMods().Scan() 60 | m_dofiles.Scan() 61 | end 62 | m_gui = require ("modules/gui") 63 | end) 64 | end 65 | 66 | function CETMM.Update() 67 | registerForEvent("onUpdate", function() 68 | 69 | end) 70 | end 71 | 72 | function CETMM.Event() -- Hotkey, Console event.. 73 | if not m_uninstalled then 74 | m_event.Register() 75 | m_hotkeys.Register() 76 | end 77 | end 78 | 79 | function CETMM.Render() 80 | registerForEvent("onDraw", function() 81 | m_gui.Initialize() 82 | m_gui.Render() 83 | end) 84 | end 85 | 86 | function CETMM.Shutdown() 87 | registerForEvent("onShutdown", function() 88 | m_options.Save() 89 | end) 90 | end -------------------------------------------------------------------------------- /scripts/modules/backend.lua: -------------------------------------------------------------------------------- 1 | ---@class backend 2 | local backend = { 3 | GetMods = CETMMEXT.GetMods, ---@type fun(): Mods 4 | OpenModsFolder = CETMMEXT.OpenModsFolder, ---@type fun(): void 5 | OpenDofilesFolder = CETMMEXT.OpenDofilesFolder, ---@type fun(): void 6 | OpenUrl = CETMMEXT.OpenUrl, ---@type fun(url: string): void 7 | GetFonts = CETMMEXT.GetFonts, ---@type fun(): Fonts 8 | GetUninstall = CETMMEXT.GetUninstall ---@type fun(): Uninstall 9 | } 10 | 11 | return backend -------------------------------------------------------------------------------- /scripts/modules/core/class/dofile.lua: -------------------------------------------------------------------------------- 1 | local helper = require ("modules/core/helper") 2 | 3 | ---@class dofile 4 | ---@field m_name string 5 | ---@field m_path path 6 | ---@field m_formated_name string 7 | local _dofile = {} 8 | _dofile.__index = _dofile 9 | 10 | -- dofile constructor 11 | 12 | setmetatable(_dofile, { 13 | __call = function (cls, ...) 14 | return cls.New(...) 15 | end, 16 | }) 17 | 18 | 19 | ---@param aPath path 20 | ---@return dofile 21 | function _dofile.New(aPath) -- path: aPath 22 | local self = setmetatable({}, _dofile) 23 | self.m_name = aPath:Stem():ToString() 24 | self.m_path = aPath 25 | self.m_formated_name = helper.format_name(self.m_name) 26 | return self 27 | end 28 | 29 | -- methods 30 | 31 | function _dofile.GetName(self) 32 | return self.m_name 33 | end 34 | 35 | function _dofile.GetPath(self) 36 | return self.m_path 37 | end 38 | 39 | function _dofile.GetFormatedName(self) 40 | return self.m_formated_name 41 | end 42 | 43 | function _dofile.Run(self) 44 | local rt, err = pcall(dofile, self.m_path:ToString()) 45 | if (not rt) then 46 | print(string.format("Error executing \"%s\": %s.", self.m_formated_name, err)) 47 | end 48 | end 49 | 50 | return _dofile -------------------------------------------------------------------------------- /scripts/modules/core/class/path.lua: -------------------------------------------------------------------------------- 1 | -- Path class 2 | 3 | ---@class path 4 | ---@field m_path string 5 | local path = {} 6 | path.__index = path 7 | 8 | -- private functions 9 | 10 | ---@param aPath string 11 | ---@return string 12 | local function sanitize_Path(aPath) 13 | local sanitized_Path = aPath:gsub("\\", "/") 14 | return sanitized_Path 15 | end 16 | 17 | -- Path constructor 18 | 19 | setmetatable(path, { 20 | __call = function (cls, ...) 21 | return cls.New(...) 22 | end, 23 | }) 24 | 25 | ---@param aPath string 26 | ---@return path 27 | function path.New(aPath) 28 | local self = setmetatable({}, path) 29 | self.m_path = sanitize_Path(aPath) 30 | return self 31 | end 32 | 33 | -- Path methods 34 | 35 | ---Path "/" operator 36 | ---@param lhs string|path 37 | ---@param rhs string|path 38 | ---@return path 39 | function path.__div (lhs, rhs) 40 | local new_path = (type(lhs) == "string" and sanitize_Path(lhs) or lhs:ToString()) .. "/" .. (type(rhs) == "string" and sanitize_Path(rhs) or rhs:ToString()) 41 | return path.New(new_path) 42 | end 43 | 44 | function path.ToString(self) 45 | return self.m_path 46 | end 47 | 48 | function path.ToWinFormat(self) 49 | local win_formated = self.m_path:gsub("/", "\\") 50 | return win_formated 51 | end 52 | 53 | function path.ToWinExcFormat(self) 54 | local win_excformated = self.m_path:gsub("/", "\\\\") 55 | return win_excformated 56 | end 57 | 58 | function path.Append(self, aPath) 59 | local new_path = self.m_path .. "/" .. aPath 60 | return path.New(new_path) 61 | end 62 | 63 | function path.ParentPath(self) 64 | local parent_Path 65 | if self.m_path == "/" then 66 | parent_Path = self.m_path 67 | elseif self.m_path:find("/$") then 68 | parent_Path = self.m_path:gsub("/[^/]-/$", "") 69 | else 70 | parent_Path = self.m_path:gsub("/[^/]-$", "") 71 | end 72 | return path.New(parent_Path) 73 | end 74 | 75 | function path.FileName(self) 76 | local file_name = self.m_path:gsub(".*/", "") 77 | return path.New(file_name) 78 | end 79 | 80 | function path.Stem(self) 81 | local stem 82 | local file_name = self:FileName():ToString() 83 | if file_name:find("^%.[^%.]*$") then 84 | stem = file_name 85 | else 86 | stem = file_name:gsub("%.[^%.]-$", "") 87 | end 88 | return path.New(stem) 89 | end 90 | 91 | function path.Extension(self) 92 | local file_name = self:FileName():ToString() 93 | local extension = file_name:match("%.[^%.]*$") 94 | return path.New(extension) 95 | end 96 | 97 | function path.HasExtension(self) 98 | local file_name = self:FileName():ToString() 99 | return file_name:find("%.[^%.]*$") and true or false 100 | end 101 | 102 | return path -------------------------------------------------------------------------------- /scripts/modules/core/helper.lua: -------------------------------------------------------------------------------- 1 | ---@class helper 2 | local helper = {} 3 | 4 | ---@param aName string 5 | function helper.format_name(aName) 6 | if string.find(aName, "_") then 7 | return string.gsub(" "..string.gsub(aName, "_" , " "), "%W%l", string.upper):sub(2) 8 | elseif string.find(aName, "-") then 9 | return string.gsub(" "..string.gsub(aName, "-" , " "), "%W%l", string.upper):sub(2) 10 | else 11 | return string.gsub(" "..aName, "%W%l", string.upper):sub(2) 12 | end 13 | end 14 | 15 | -- https://gist.github.com/haggen/2fd643ea9a261fea2094#gistcomment-2339900 16 | ---@param length number 17 | function helper.randomHash(length) 18 | local charset = {} do -- [0-9a-zA-Z] 19 | for c = 48, 57 do table.insert(charset, string.char(c)) end 20 | for c = 65, 90 do table.insert(charset, string.char(c)) end 21 | for c = 97, 122 do table.insert(charset, string.char(c)) end 22 | end 23 | if not length or length <= 0 then return '' end 24 | math.randomseed(os.clock()^5) 25 | return helper.randomHash(length - 1) .. charset[math.random(1, #charset)] 26 | end 27 | 28 | return helper -------------------------------------------------------------------------------- /scripts/modules/dofiles.lua: -------------------------------------------------------------------------------- 1 | local path = require ("modules/core/class/path") 2 | local _dofile = require ("modules/core/class/dofile") 3 | 4 | ---@class dofiles 5 | ---@field m_data dofile[] 6 | local dofiles = { 7 | m_data = {}, 8 | } 9 | 10 | -- public methods 11 | 12 | function dofiles.Scan() 13 | dofiles.Clear() 14 | 15 | local dofile_list = dir("dofiles") 16 | for _, entry in ipairs(dofile_list) do 17 | if entry.type == "file" and entry.name:match("(.+)%.lua$") then 18 | local entry_path = path("dofiles") / entry.name 19 | table.insert(dofiles.m_data, _dofile(entry_path)) 20 | end 21 | end 22 | 23 | end 24 | 25 | function dofiles.Clear() 26 | dofiles.m_data = {} 27 | end 28 | 29 | function dofiles.Get() 30 | return dofiles.m_data 31 | end 32 | 33 | return dofiles -------------------------------------------------------------------------------- /scripts/modules/event.lua: -------------------------------------------------------------------------------- 1 | ---@class event 2 | local event = {} 3 | 4 | function event.Register() 5 | registerForEvent("onOverlayOpen", function() 6 | if CETMM.GetOptions().m_autoappear then 7 | CETMM.GetUISystem().GetWindow().m_draw = true 8 | end 9 | end) 10 | 11 | registerForEvent("onOverlayClose", function() 12 | if CETMM.GetOptions().m_autoappear then 13 | CETMM.GetUISystem().GetWindow().m_draw = false 14 | end 15 | end) 16 | end 17 | 18 | return event 19 | -------------------------------------------------------------------------------- /scripts/modules/gui/dpi.lua: -------------------------------------------------------------------------------- 1 | ---@class dpi 2 | local dpi = {} 3 | local m_fontscale 4 | local m_displayRes = {} 5 | local m_defaultVars = {} 6 | 7 | local function get_vars() 8 | local style = ImGui.GetStyle() 9 | local vars = { 10 | WindowPadding = { x = style.WindowPadding.x, y = style.WindowPadding.y }, 11 | WindowRounding = style.WindowRounding, 12 | ChildRounding = style.ChildRounding, 13 | PopupRounding = style.PopupRounding, 14 | FramePadding = { x = style.FramePadding.x, y = style.FramePadding.y }, 15 | FrameRounding = style.FrameRounding, 16 | ItemSpacing = { x = style.ItemSpacing.x, y = style.ItemSpacing.y }, 17 | ItemInnerSpacing = { x = style.ItemInnerSpacing.x, y = style.ItemInnerSpacing.y }, 18 | CellPadding = { x = style.CellPadding.x, y = style.CellPadding.y }, 19 | TouchExtraPadding = { x = style.TouchExtraPadding.x, y = style.TouchExtraPadding.y }, 20 | IndentSpacing = style.IndentSpacing, 21 | ColumnsMinSpacing = style.ColumnsMinSpacing, 22 | ScrollbarSize = style.ScrollbarSize, 23 | ScrollbarRounding = style.ScrollbarRounding, 24 | GrabMinSize = style.GrabMinSize, 25 | GrabRounding = style.GrabRounding, 26 | LogSliderDeadzone = style.LogSliderDeadzone, 27 | TabRounding = style.TabRounding, 28 | TabMinWidthForCloseButton = style.TabMinWidthForCloseButton, 29 | DisplayWindowPadding = { x = style.DisplayWindowPadding.x, y = style.DisplayWindowPadding.y }, 30 | DisplaySafeAreaPadding = { x = style.DisplaySafeAreaPadding.x, y = style.DisplaySafeAreaPadding.y }, 31 | MouseCursorScale = style.MouseCursorScale; 32 | } 33 | return vars 34 | end 35 | 36 | function dpi.Initialize() 37 | m_displayRes.x, m_displayRes.y = GetDisplayResolution() 38 | m_fontscale = ImGui.GetFontSize()/18 39 | m_defaultVars = get_vars() 40 | end 41 | 42 | function dpi.GetDisplayResolution() 43 | return m_displayRes 44 | end 45 | 46 | 47 | function dpi.GetScale() 48 | return m_fontscale 49 | end 50 | 51 | function dpi.Scale(aNumber) 52 | return aNumber * m_fontscale 53 | end 54 | 55 | function dpi.PushScale() 56 | local vars = get_vars() 57 | local style = ImGui.GetStyle() 58 | for key, value in pairs(vars) do 59 | if type(value) == "table" then 60 | style[key].x = math.floor(value.x * m_fontscale) 61 | style[key].y = math.floor(value.y * m_fontscale) 62 | else 63 | style[key] = math.floor(value * m_fontscale) 64 | end 65 | end 66 | end 67 | 68 | function dpi.PopScale() 69 | local style = ImGui.GetStyle() 70 | for key, value in pairs(m_defaultVars) do 71 | if type(value) == "table" then 72 | style[key].x = value.x 73 | style[key].y = value.y 74 | else 75 | style[key] = value 76 | end 77 | end 78 | end 79 | 80 | return dpi -------------------------------------------------------------------------------- /scripts/modules/gui/init.lua: -------------------------------------------------------------------------------- 1 | ---@class gui 2 | local gui = {} 3 | local m_dpi = require ("modules/gui/dpi") 4 | local m_themeSys = require ("modules/gui/themeSys") 5 | local m_widgets = require ("modules/gui/widgets") 6 | local m_window = require ("modules/gui/window") 7 | local m_windows = require ("modules/gui/windows") 8 | local m_initialized = false 9 | local m_showUninstall = false 10 | 11 | function gui.GetDPI() 12 | return m_dpi 13 | end 14 | 15 | function gui.GetThemeSys() 16 | return m_themeSys 17 | end 18 | 19 | function gui.GetWindow() 20 | return m_window 21 | end 22 | 23 | function gui.Initialize() 24 | if not m_initialized then 25 | m_showUninstall = CETMM.IsUninstalled() 26 | m_dpi.Initialize() 27 | if m_showUninstall then 28 | m_themeSys.Load("default", true) 29 | else 30 | m_themeSys.Initialize() 31 | m_window.Initialize() 32 | end 33 | m_initialized = true 34 | end 35 | end 36 | 37 | function gui.Render() 38 | m_themeSys.PushTheme() 39 | if m_showUninstall then 40 | m_windows.uninstall.Render() 41 | else 42 | m_window.Render() 43 | end 44 | m_themeSys.PopTheme() 45 | end 46 | 47 | return gui -------------------------------------------------------------------------------- /scripts/modules/gui/themeSys.lua: -------------------------------------------------------------------------------- 1 | ---@class themeSys 2 | local themeSys = { 3 | themes = { 4 | default = require("modules/gui/themes/default"), 5 | ua_special = require("modules/gui/themes/ua_special"), 6 | white = require("modules/gui/themes/white"), 7 | }, 8 | currentTheme = {} ---@type baseTheme 9 | } 10 | 11 | function themeSys.Initialize() 12 | local theme = CETMM.GetOptions().m_theme 13 | themeSys.Load(theme) 14 | end 15 | 16 | ---Load theme 17 | ---@param aTheme string 18 | ---@param aNoSave? bool 19 | function themeSys.Load(aTheme, aNoSave) 20 | if themeSys.themes[aTheme] then 21 | themeSys.currentTheme = themeSys.themes[aTheme] 22 | else 23 | themeSys.currentTheme = themeSys.themes.default 24 | spdlog.error(string.format("Failed to load theme %s, loaded default theme instead.", aTheme)) 25 | end 26 | if not aNoSave then 27 | CETMM.GetOptions().m_theme = themeSys.currentTheme:GetName() 28 | CETMM.GetOptions().Save() 29 | end 30 | end 31 | 32 | function themeSys.GetCurrentTheme() 33 | return themeSys.currentTheme 34 | end 35 | 36 | ---@param aStyle ImGuiCol 37 | ---@param aColor number[] 38 | function themeSys.PushColor(aStyle, aColor) 39 | ImGui.PushStyleColor(aStyle, unpack(aColor)) 40 | end 41 | 42 | function themeSys.PushTheme() 43 | themeSys.PushColor(ImGuiCol.TitleBg, themeSys.currentTheme:GetStyleColor("TitleBg" )) 44 | themeSys.PushColor(ImGuiCol.TitleBgCollapsed, themeSys.currentTheme:GetStyleColor("TitleBgCollapsed" )) 45 | themeSys.PushColor(ImGuiCol.TitleBgActive, themeSys.currentTheme:GetStyleColor("TitleBgActive" )) 46 | themeSys.PushColor(ImGuiCol.Border, themeSys.currentTheme:GetStyleColor("Border" )) 47 | themeSys.PushColor(ImGuiCol.WindowBg, themeSys.currentTheme:GetStyleColor("WindowBg" )) 48 | themeSys.PushColor(ImGuiCol.ScrollbarBg, themeSys.currentTheme:GetStyleColor("ScrollbarBg" )) 49 | themeSys.PushColor(ImGuiCol.ScrollbarGrab, themeSys.currentTheme:GetStyleColor("ScrollbarGrab" )) 50 | themeSys.PushColor(ImGuiCol.ScrollbarGrabHovered, themeSys.currentTheme:GetStyleColor("ScrollbarGrabHovered" )) 51 | themeSys.PushColor(ImGuiCol.ScrollbarGrabActive, themeSys.currentTheme:GetStyleColor("ScrollbarGrabActive" )) 52 | themeSys.PushColor(ImGuiCol.ResizeGrip, themeSys.currentTheme:GetStyleColor("ResizeGrip" )) 53 | themeSys.PushColor(ImGuiCol.ResizeGripHovered, themeSys.currentTheme:GetStyleColor("ResizeGripHovered" )) 54 | themeSys.PushColor(ImGuiCol.ResizeGripActive, themeSys.currentTheme:GetStyleColor("ResizeGripActive" )) 55 | themeSys.PushColor(ImGuiCol.Text, themeSys.currentTheme:GetStyleColor("Text" )) 56 | themeSys.PushColor(ImGuiCol.Header, themeSys.currentTheme:GetStyleColor("Header" )) 57 | themeSys.PushColor(ImGuiCol.HeaderHovered, themeSys.currentTheme:GetStyleColor("HeaderHovered" )) 58 | themeSys.PushColor(ImGuiCol.HeaderActive, themeSys.currentTheme:GetStyleColor("HeaderActive" )) 59 | themeSys.PushColor(ImGuiCol.CheckMark, themeSys.currentTheme:GetStyleColor("CheckMark" )) 60 | themeSys.PushColor(ImGuiCol.FrameBg, themeSys.currentTheme:GetStyleColor("FrameBg" )) 61 | themeSys.PushColor(ImGuiCol.FrameBgHovered, themeSys.currentTheme:GetStyleColor("FrameBgHovered" )) 62 | themeSys.PushColor(ImGuiCol.FrameBgActive, themeSys.currentTheme:GetStyleColor("FrameBgActive" )) 63 | themeSys.PushColor(ImGuiCol.Button, themeSys.currentTheme:GetStyleColor("Button" )) 64 | themeSys.PushColor(ImGuiCol.ButtonHovered, themeSys.currentTheme:GetStyleColor("ButtonHovered" )) 65 | themeSys.PushColor(ImGuiCol.ButtonActive, themeSys.currentTheme:GetStyleColor("ButtonActive" )) 66 | themeSys.PushColor(ImGuiCol.Separator, themeSys.currentTheme:GetStyleColor("Separator" )) 67 | themeSys.PushColor(ImGuiCol.PopupBg, themeSys.currentTheme:GetStyleColor("PopupBg" )) 68 | 69 | ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, 8, 8) 70 | ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 0) 71 | end 72 | 73 | function themeSys.PopTheme() 74 | ImGui.PopStyleColor(25) 75 | ImGui.PopStyleVar(2) 76 | end 77 | 78 | return themeSys -------------------------------------------------------------------------------- /scripts/modules/gui/themes/baseTheme.lua: -------------------------------------------------------------------------------- 1 | ---@class baseTheme 2 | ---@operator call(string):baseTheme 3 | local baseTheme = { 4 | name = "default", 5 | colors = {}, 6 | } 7 | baseTheme.__index = baseTheme 8 | 9 | -- baseTheme constructor 10 | 11 | setmetatable(baseTheme, { 12 | __call = function (cls, ...) 13 | return cls.New(...) 14 | end, 15 | }) 16 | 17 | 18 | ---@param aName string 19 | ---@return baseTheme 20 | function baseTheme.New(aName) -- path: aPath 21 | local self = setmetatable({}, baseTheme) 22 | self.name = aName or self.name 23 | return self 24 | end 25 | 26 | -- methods 27 | function baseTheme.GetName(self) 28 | return self.name 29 | end 30 | 31 | ---Safe call method 32 | ---@param self baseTheme 33 | ---@param aMethod string 34 | ---@param ... any 35 | ---@return any 36 | function baseTheme.Call(self, aMethod, ...) 37 | if self[aMethod] then 38 | return self[aMethod](self, ...) 39 | end 40 | end 41 | 42 | ---Only call method in specific theme 43 | ---@param self baseTheme 44 | ---@param aThemeName string 45 | ---@param aMethod string 46 | ---@param ... any 47 | ---@return any 48 | function baseTheme.CallIf(self, aThemeName, aMethod, ...) 49 | if self.name == aThemeName and self[aMethod] then 50 | return self[aMethod](self, ...) 51 | end 52 | end 53 | 54 | ---@param self baseTheme 55 | ---@param aGuiColor string 56 | ---@return float[] 57 | function baseTheme.GetStyleColor(self, aGuiColor) 58 | return self.colors[aGuiColor] 59 | end 60 | 61 | return baseTheme -------------------------------------------------------------------------------- /scripts/modules/gui/themes/default.lua: -------------------------------------------------------------------------------- 1 | local baseTheme = require("modules/gui/themes/baseTheme") 2 | 3 | ---@class themeDefault : baseTheme 4 | local themeDefault = baseTheme("default") 5 | 6 | themeDefault.colors = { 7 | Text = { 1 , 0.44, 0.4 , 1 }, 8 | TextDisabled = { 0.48, 0.39, 0.40, 1 }, 9 | WindowBg = { 0.06, 0.04, 0.06, 0.9 }, 10 | ChildBg = { 0.06, 0.04, 0.06, 0.9 }, 11 | PopupBg = { 0.06, 0.04, 0.06, 0.9 }, 12 | Border = { 0.3 , 0.07, 0.08, 1 }, 13 | BorderShadow = { 0 , 0 , 0 , 0 }, 14 | FrameBg = { 0.57, 0.17, 0.16, 1 }, 15 | FrameBgHovered = { 0.32, 0.09, 0.11, 1 }, 16 | FrameBgActive = { 0.1 , 0.05, 0.05, 1 }, 17 | FrameBgDisabled = { 0.48, 0.39, 0.40, 1 }, 18 | FrameBgHoveredDisabled = { 0.48, 0.39, 0.40, 1 }, 19 | FrameBgActiveDisabled = { 0.48, 0.39, 0.40, 1 }, 20 | TitleBg = { 0.06, 0.04, 0.06, 0.9 }, 21 | TitleBgActive = { 0.06, 0.04, 0.06, 0.9 }, 22 | TitleBgCollapsed = { 0.06, 0.04, 0.06, 0.9 }, 23 | MenuBarBg = { 0 , 0 , 0 , 0 }, 24 | ScrollbarBg = { 0.06, 0.04, 0.06, 0 }, 25 | ScrollbarGrab = { 0.57, 0.17, 0.16, 1 }, 26 | ScrollbarGrabHovered = { 0.57, 0.17, 0.16, 1 }, 27 | ScrollbarGrabActive = { 0.57, 0.17, 0.16, 1 }, 28 | CheckMark = { 1 , 0.44, 0.4 , 1 }, 29 | CheckMarkTrueDisabled = { 0.34, 0.22, 0.24, 1 }, 30 | CheckMarkFalseDisabled = { 0.48, 0.39, 0.40, 1 }, 31 | SliderGrab = { 0 , 0 , 0 , 0 }, 32 | SliderGrabActive = { 0 , 0 , 0 , 0 }, 33 | Button = { 0.57, 0.17, 0.16, 1 }, 34 | ButtonHovered = { 0.45, 0.13, 0.14, 1 }, 35 | ButtonActive = { 0.57, 0.17, 0.16, 1 }, 36 | Header = { 0.22, 0.64, 0.69, 0.2 }, 37 | HeaderHovered = { 0.22, 0.64, 0.69, 0.3 }, 38 | HeaderActive = { 0.22, 0.64, 0.69, 0.5 }, 39 | Separator = { 0.3 , 0.07, 0.08, 1 }, 40 | SeparatorHovered = { 0.29, 0.77, 0.79, 1 }, 41 | SeparatorActive = { 0.29, 0.77, 0.79, 1 }, 42 | ResizeGrip = { 0.06, 0.04, 0.06, 1 }, 43 | ResizeGripHovered = { 1 , 0.44, 0.4 , 1 }, 44 | ResizeGripActive = { 1 , 0.44, 0.4 , 1 }, 45 | Tab = { 0 , 0 , 0 , 0 }, 46 | TabHovered = { 0 , 0 , 0 , 0 }, 47 | TabActive = { 0 , 0 , 0 , 0 }, 48 | TabUnfocused = { 0 , 0 , 0 , 0 }, 49 | TabUnfocusedActive = { 0 , 0 , 0 , 0 }, 50 | DockingPreview = { 0 , 0 , 0 , 0 }, 51 | DockingEmptyBg = { 0 , 0 , 0 , 0 }, 52 | PlotLines = { 0 , 0 , 0 , 0 }, 53 | PlotLinesHovered = { 0 , 0 , 0 , 0 }, 54 | PlotHistogram = { 0 , 0 , 0 , 0 }, 55 | PlotHistogramHovered = { 0 , 0 , 0 , 0 }, 56 | TextSelectedBg = { 0 , 0 , 0 , 0 }, 57 | DragDropTarget = { 0 , 0 , 0 , 0 }, 58 | NavHighlight = { 0 , 0 , 0 , 0 }, 59 | NavWindowingHighlight = { 0 , 0 , 0 , 0 }, 60 | NavWindowingDimBg = { 0 , 0 , 0 , 0 }, 61 | ModalWindowDimBg = { 0 , 0 , 0 , 0 }, 62 | ModalWindowDarkening = { 0 , 0 , 0 , 0 }, 63 | COUNT = { 0 , 0 , 0 , 0 }, 64 | CustomToggleOn = { 0.29, 0.77, 0.79, 1 }, 65 | CustomToggleOnHovered = { 0.20, 0.56, 0.59, 1 }, 66 | CustomToggleOnActive = { 0.29, 0.77, 0.79, 1 }, 67 | CustomToggleOnText = { 0 , 0 , 0 , 1 }, 68 | CustomToggleOnDisable = { 0.04, 0.11, 0.12, 1 }, 69 | CustomToggleOnDisableHovered = { 0.05, 0.16, 0.16, 1 }, 70 | CustomToggleOnDisableText = { 0.06, 0.18, 0.2 , 1 }, 71 | CustomToggleOff = { 0.57, 0.18, 0.16, 1 }, 72 | CustomToggleOffHovered = { 0.45, 0.13, 0.14, 1 }, 73 | CustomToggleOffDisable = { 0.1 , 0.04, 0.07, 1 }, 74 | CustomToggleOffDisableHovered = { 0.16, 0.06, 0.07, 1 }, 75 | CustomToggleOffDisableText = { 0.22, 0.07, 0.07, 1 }, 76 | AltText = { 0.29, 0.77, 0.79, 1 }, 77 | Hidden = { 0 , 0 , 0 , 0 }, 78 | } 79 | 80 | return themeDefault -------------------------------------------------------------------------------- /scripts/modules/gui/themes/ua_special.lua: -------------------------------------------------------------------------------- 1 | local baseTheme = require("modules/gui/themes/baseTheme") 2 | 3 | ---@class themeUA : baseTheme 4 | local themeUA = baseTheme("ua_special") 5 | 6 | themeUA.colors = { 7 | Text = { 0.96, 0.81, 0.00, 1 }, 8 | TextDisabled = { 0.48, 0.39, 0.40, 1 }, 9 | WindowBg = { 0.05, 0.11, 0.18, 0.9 }, 10 | ChildBg = { 0.05, 0.11, 0.18, 0.9 }, 11 | PopupBg = { 0.05, 0.11, 0.18, 0.9 }, 12 | Border = { 0.60, 0.51, 0.00, 1 }, 13 | BorderShadow = { 0 , 0 , 0 , 0 }, 14 | FrameBg = { 0.00, 0.35, 0.71, 1 }, 15 | FrameBgHovered = { 0.00, 0.44, 0.90, 1 }, 16 | FrameBgActive = { 0.00, 0.35, 0.71, 1 }, 17 | FrameBgDisabled = { 0.48, 0.39, 0.40, 1 }, 18 | FrameBgHoveredDisabled = { 0.48, 0.39, 0.40, 1 }, 19 | FrameBgActiveDisabled = { 0.48, 0.39, 0.40, 1 }, 20 | TitleBg = { 0.05, 0.11, 0.18, 0.9 }, 21 | TitleBgActive = { 0.05, 0.11, 0.18, 0.9 }, 22 | TitleBgCollapsed = { 0.05, 0.11, 0.18, 0.9 }, 23 | MenuBarBg = { 0.05, 0.11, 0.18, 0.9 }, 24 | ScrollbarBg = { 0.06, 0.04, 0.06, 0 }, 25 | ScrollbarGrab = { 0.00, 0.35, 0.71, 1 }, 26 | ScrollbarGrabHovered = { 0.00, 0.44, 0.90, 1 }, 27 | ScrollbarGrabActive = { 0.00, 0.35, 0.71, 1 }, 28 | CheckMark = { 0.96, 0.81, 0.00, 1 }, 29 | CheckMarkTrueDisabled = { 0.34, 0.22, 0.24, 1 }, 30 | CheckMarkFalseDisabled = { 0.48, 0.39, 0.40, 1 }, 31 | SliderGrab = { 0 , 0 , 0 , 0 }, 32 | SliderGrabActive = { 0 , 0 , 0 , 0 }, 33 | Button = { 0.00, 0.35, 0.71, 1 }, 34 | ButtonHovered = { 0.00, 0.44, 0.90, 1 }, 35 | ButtonActive = { 0.00, 0.35, 0.71, 1 }, 36 | Header = { 0.00, 0.21, 0.43, 0.6 }, 37 | HeaderHovered = { 0.00, 0.21, 0.43, 0.9 }, 38 | HeaderActive = { 0.00, 0.21, 0.43, 0.9 }, 39 | Separator = { 0.60, 0.51, 0.00, 0.5 }, 40 | SeparatorHovered = { 0.29, 0.77, 0.79, 1 }, 41 | SeparatorActive = { 0.29, 0.77, 0.79, 1 }, 42 | ResizeGrip = { 0.05, 0.11, 0.18, 1 }, 43 | ResizeGripHovered = { 0.96, 0.81, 0.00, 1 }, 44 | ResizeGripActive = { 0.96, 0.81, 0.00, 1 }, 45 | Tab = { 0 , 0 , 0 , 0 }, 46 | TabHovered = { 0 , 0 , 0 , 0 }, 47 | TabActive = { 0 , 0 , 0 , 0 }, 48 | TabUnfocused = { 0 , 0 , 0 , 0 }, 49 | TabUnfocusedActive = { 0 , 0 , 0 , 0 }, 50 | DockingPreview = { 0 , 0 , 0 , 0 }, 51 | DockingEmptyBg = { 0 , 0 , 0 , 0 }, 52 | PlotLines = { 0 , 0 , 0 , 0 }, 53 | PlotLinesHovered = { 0 , 0 , 0 , 0 }, 54 | PlotHistogram = { 0 , 0 , 0 , 0 }, 55 | PlotHistogramHovered = { 0 , 0 , 0 , 0 }, 56 | TextSelectedBg = { 0 , 0 , 0 , 0 }, 57 | DragDropTarget = { 0 , 0 , 0 , 0 }, 58 | NavHighlight = { 0 , 0 , 0 , 0 }, 59 | NavWindowingHighlight = { 0 , 0 , 0 , 0 }, 60 | NavWindowingDimBg = { 0 , 0 , 0 , 0 }, 61 | ModalWindowDimBg = { 0 , 0 , 0 , 0 }, 62 | ModalWindowDarkening = { 0 , 0 , 0 , 0 }, 63 | COUNT = { 0 , 0 , 0 , 0 }, 64 | CustomToggleOn = { 0.96, 0.81, 0.00, 1 }, 65 | CustomToggleOnHovered = { 0.81, 0.67, 0.00, 1 }, 66 | CustomToggleOnActive = { 0.96, 0.81, 0.00, 1 }, 67 | CustomToggleOnText = { 0.00, 0.44, 0.90, 1 }, 68 | CustomToggleOnDisable = { 0.04, 0.11, 0.12, 1 }, 69 | CustomToggleOnDisableHovered = { 0.05, 0.16, 0.16, 1 }, 70 | CustomToggleOnDisableText = { 0.06, 0.18, 0.2 , 1 }, 71 | CustomToggleOff = { 0.57, 0.18, 0.16, 1 }, 72 | CustomToggleOffHovered = { 0.45, 0.13, 0.14, 1 }, 73 | CustomToggleOffDisable = { 0.1 , 0.04, 0.07, 1 }, 74 | CustomToggleOffDisableHovered = { 0.16, 0.06, 0.07, 1 }, 75 | CustomToggleOffDisableText = { 0.22, 0.07, 0.07, 1 }, 76 | AltText = { 0.00, 0.44, 0.90, 1 }, 77 | Hidden = { 0 , 0 , 0 , 0 }, 78 | } 79 | 80 | function themeUA.RenderFooter(self) 81 | ImGui.TableSetColumnIndex(1) 82 | ImGui.PushStyleColor(ImGuiCol.Text, unpack(self.colors.Border)) 83 | ImGui.Text("We stand with Ukraine!") 84 | ImGui.PopStyleColor(1) 85 | end 86 | 87 | return themeUA -------------------------------------------------------------------------------- /scripts/modules/gui/themes/white.lua: -------------------------------------------------------------------------------- 1 | local baseTheme = require("modules/gui/themes/baseTheme") 2 | 3 | ---@class themeWhite : baseTheme 4 | local themeWhite = baseTheme("white") 5 | 6 | themeWhite.states = {} 7 | 8 | themeWhite.def_colors = { 9 | Text = { 1 , 1 , 1 , 1 }, 10 | TextDisabled = { 1 , 1 , 1 , 1 }, 11 | WindowBg = { 1 , 1 , 1 , 1 }, 12 | ChildBg = { 1 , 1 , 1 , 1 }, 13 | PopupBg = { 1 , 1 , 1 , 1 }, 14 | Border = { 1 , 1 , 1 , 1 }, 15 | BorderShadow = { 1 , 1 , 1 , 1 }, 16 | FrameBg = { 1 , 1 , 1 , 1 }, 17 | FrameBgHovered = { 1 , 1 , 1 , 1 }, 18 | FrameBgActive = { 1 , 1 , 1 , 1 }, 19 | FrameBgDisabled = { 1 , 1 , 1 , 1 }, 20 | FrameBgHoveredDisabled = { 1 , 1 , 1 , 1 }, 21 | FrameBgActiveDisabled = { 1 , 1 , 1 , 1 }, 22 | TitleBg = { 1 , 1 , 1 , 1 }, 23 | TitleBgActive = { 1 , 1 , 1 , 1 }, 24 | TitleBgCollapsed = { 1 , 1 , 1 , 1 }, 25 | MenuBarBg = { 1 , 1 , 1 , 1 }, 26 | ScrollbarBg = { 1 , 1 , 1 , 1 }, 27 | ScrollbarGrab = { 1 , 1 , 1 , 1 }, 28 | ScrollbarGrabHovered = { 1 , 1 , 1 , 1 }, 29 | ScrollbarGrabActive = { 1 , 1 , 1 , 1 }, 30 | CheckMark = { 1 , 1 , 1 , 1 }, 31 | CheckMarkTrueDisabled = { 1 , 1 , 1 , 1 }, 32 | CheckMarkFalseDisabled = { 1 , 1 , 1 , 1 }, 33 | SliderGrab = { 1 , 1 , 1 , 1 }, 34 | SliderGrabActive = { 1 , 1 , 1 , 1 }, 35 | Button = { 1 , 1 , 1 , 1 }, 36 | ButtonHovered = { 1 , 1 , 1 , 1 }, 37 | ButtonActive = { 1 , 1 , 1 , 1 }, 38 | Header = { 1 , 1 , 1 , 1 }, 39 | HeaderHovered = { 1 , 1 , 1 , 1 }, 40 | HeaderActive = { 1 , 1 , 1 , 1 }, 41 | Separator = { 1 , 1 , 1 , 1 }, 42 | SeparatorHovered = { 1 , 1 , 1 , 1 }, 43 | SeparatorActive = { 1 , 1 , 1 , 1 }, 44 | ResizeGrip = { 1 , 1 , 1 , 1 }, 45 | ResizeGripHovered = { 1 , 1 , 1 , 1 }, 46 | ResizeGripActive = { 1 , 1 , 1 , 1 }, 47 | Tab = { 1 , 1 , 1 , 1 }, 48 | TabHovered = { 1 , 1 , 1 , 1 }, 49 | TabActive = { 1 , 1 , 1 , 1 }, 50 | TabUnfocused = { 1 , 1 , 1 , 1 }, 51 | TabUnfocusedActive = { 1 , 1 , 1 , 1 }, 52 | DockingPreview = { 1 , 1 , 1 , 1 }, 53 | DockingEmptyBg = { 1 , 1 , 1 , 1 }, 54 | PlotLines = { 1 , 1 , 1 , 1 }, 55 | PlotLinesHovered = { 1 , 1 , 1 , 1 }, 56 | PlotHistogram = { 1 , 1 , 1 , 1 }, 57 | PlotHistogramHovered = { 1 , 1 , 1 , 1 }, 58 | TextSelectedBg = { 1 , 1 , 1 , 1 }, 59 | DragDropTarget = { 1 , 1 , 1 , 1 }, 60 | NavHighlight = { 1 , 1 , 1 , 1 }, 61 | NavWindowingHighlight = { 1 , 1 , 1 , 1 }, 62 | NavWindowingDimBg = { 1 , 1 , 1 , 1 }, 63 | ModalWindowDimBg = { 1 , 1 , 1 , 1 }, 64 | ModalWindowDarkening = { 1 , 1 , 1 , 1 }, 65 | COUNT = { 1 , 1 , 1 , 1 }, 66 | CustomToggleOn = { 1 , 1 , 1 , 1 }, 67 | CustomToggleOnHovered = { 1 , 1 , 1 , 1 }, 68 | CustomToggleOnActive = { 1 , 1 , 1 , 1 }, 69 | CustomToggleOnText = { 1 , 1 , 1 , 1 }, 70 | CustomToggleOnDisable = { 1 , 1 , 1 , 1 }, 71 | CustomToggleOnDisableHovered = { 1 , 1 , 1 , 1 }, 72 | CustomToggleOnDisableText = { 1 , 1 , 1 , 1 }, 73 | CustomToggleOff = { 1 , 1 , 1 , 1 }, 74 | CustomToggleOffHovered = { 1 , 1 , 1 , 1 }, 75 | CustomToggleOffDisable = { 1 , 1 , 1 , 1 }, 76 | CustomToggleOffDisableHovered = { 1 , 1 , 1 , 1 }, 77 | CustomToggleOffDisableText = { 1 , 1 , 1 , 1 }, 78 | AltText = { 1 , 1 , 1 , 1 }, 79 | Hidden = { 1 , 1 , 1 , 1 }, 80 | } 81 | 82 | themeWhite.hvr_colors = { 83 | Text = { 0.20, 0.20, 0.20, 1 }, 84 | TextDisabled = { 0.48, 0.39, 0.40, 1 }, 85 | WindowBg = { 1 , 1 , 1 , 0.9 }, 86 | ChildBg = { 1 , 1 , 1 , 0.9 }, 87 | PopupBg = { 1 , 1 , 1 , 0.9 }, 88 | Border = { 0.5 , 0.5 , 0.5 , 1 }, 89 | BorderShadow = { 0 , 0 , 0 , 0 }, 90 | FrameBg = { 1 , 1 , 1 , 1 }, 91 | FrameBgHovered = { 0.80, 0.80, 0.80, 1 }, 92 | FrameBgActive = { 1 , 1 , 1 , 1 }, 93 | FrameBgDisabled = { 0.48, 0.39, 0.40, 1 }, 94 | FrameBgHoveredDisabled = { 0.48, 0.39, 0.40, 1 }, 95 | FrameBgActiveDisabled = { 0.48, 0.39, 0.40, 1 }, 96 | TitleBg = { 1 , 1 , 1 , 0.9 }, 97 | TitleBgActive = { 1 , 1 , 1 , 0.9 }, 98 | TitleBgCollapsed = { 1 , 1 , 1 , 0.9 }, 99 | MenuBarBg = { 1 , 1 , 1 , 0.9 }, 100 | ScrollbarBg = { 0.06, 0.04, 0.06, 0 }, 101 | ScrollbarGrab = { 1 , 1 , 1 , 1 }, 102 | ScrollbarGrabHovered = { 0.80, 0.80, 0.80, 1 }, 103 | ScrollbarGrabActive = { 1 , 1 , 1 , 1 }, 104 | CheckMark = { 0.20, 0.20, 0.20, 1 }, 105 | CheckMarkTrueDisabled = { 0.20, 0.20, 0.20, 1 }, 106 | CheckMarkFalseDisabled = { 0.20, 0.20, 0.20, 1 }, 107 | SliderGrab = { 0 , 0 , 0 , 0 }, 108 | SliderGrabActive = { 0 , 0 , 0 , 0 }, 109 | Button = { 1 , 1 , 1 , 1 }, 110 | ButtonHovered = { 0.80, 0.80, 0.80, 1 }, 111 | ButtonActive = { 1 , 1 , 1 , 1 }, 112 | Header = { 0.80, 0.80, 0.80, 0.6 }, 113 | HeaderHovered = { 0.80, 0.80, 0.80, 0.9 }, 114 | HeaderActive = { 0.80, 0.80, 0.80, 0.9 }, 115 | Separator = { 0.5 , 0.5 , 0.5 , 1 }, 116 | SeparatorHovered = { 0.5 , 0.5 , 0.5 , 1 }, 117 | SeparatorActive = { 0.5 , 0.5 , 0.5 , 1 }, 118 | ResizeGrip = { 0.80, 0.80, 0.80, 1 }, 119 | ResizeGripHovered = { 0.70, 0.70, 0.70, 1 }, 120 | ResizeGripActive = { 0.70, 0.70, 0.70, 1 }, 121 | Tab = { 0 , 0 , 0 , 0 }, 122 | TabHovered = { 0 , 0 , 0 , 0 }, 123 | TabActive = { 0 , 0 , 0 , 0 }, 124 | TabUnfocused = { 0 , 0 , 0 , 0 }, 125 | TabUnfocusedActive = { 0 , 0 , 0 , 0 }, 126 | DockingPreview = { 0 , 0 , 0 , 0 }, 127 | DockingEmptyBg = { 0 , 0 , 0 , 0 }, 128 | PlotLines = { 0 , 0 , 0 , 0 }, 129 | PlotLinesHovered = { 0 , 0 , 0 , 0 }, 130 | PlotHistogram = { 0 , 0 , 0 , 0 }, 131 | PlotHistogramHovered = { 0 , 0 , 0 , 0 }, 132 | TextSelectedBg = { 0 , 0 , 0 , 0 }, 133 | DragDropTarget = { 0 , 0 , 0 , 0 }, 134 | NavHighlight = { 0 , 0 , 0 , 0 }, 135 | NavWindowingHighlight = { 0 , 0 , 0 , 0 }, 136 | NavWindowingDimBg = { 0 , 0 , 0 , 0 }, 137 | ModalWindowDimBg = { 0 , 0 , 0 , 0 }, 138 | ModalWindowDarkening = { 0 , 0 , 0 , 0 }, 139 | COUNT = { 0 , 0 , 0 , 0 }, 140 | CustomToggleOn = { 0.80, 0.80, 0.80, 1 }, 141 | CustomToggleOnHovered = { 0.70, 0.70, 0.70, 1 }, 142 | CustomToggleOnActive = { 0.80, 0.80, 0.80, 1 }, 143 | CustomToggleOnText = { 0.20, 0.20, 0.20, 1 }, 144 | CustomToggleOnDisable = { 0.04, 0.11, 0.12, 1 }, 145 | CustomToggleOnDisableHovered = { 0.05, 0.16, 0.16, 1 }, 146 | CustomToggleOnDisableText = { 0.06, 0.18, 0.2 , 1 }, 147 | CustomToggleOff = { 0.57, 0.18, 0.16, 1 }, 148 | CustomToggleOffHovered = { 0.45, 0.13, 0.14, 1 }, 149 | CustomToggleOffDisable = { 0.1 , 0.04, 0.07, 1 }, 150 | CustomToggleOffDisableHovered = { 0.16, 0.06, 0.07, 1 }, 151 | CustomToggleOffDisableText = { 0.22, 0.07, 0.07, 1 }, 152 | AltText = { 0.80, 0.80, 0.80, 1 }, 153 | Hidden = { 0 , 0 , 0 , 0 }, 154 | } 155 | 156 | ---@param self themeWhite 157 | ---@param aGuiColor string 158 | ---@return float[] 159 | function themeWhite.GetStyleColor(self, aGuiColor) 160 | for window, hovering in pairs(self.states) do 161 | if hovering then 162 | return self.hvr_colors[aGuiColor] 163 | end 164 | end 165 | return self.def_colors[aGuiColor] 166 | end 167 | 168 | ---@param aWindow string 169 | function themeWhite.GetHoverState(self, aWindow) 170 | self.states[aWindow] = ImGui.IsWindowHovered(bit32.bor(ImGuiHoveredFlags.RootAndChildWindows, ImGuiHoveredFlags.AllowWhenBlockedByActiveItem, ImGuiHoveredFlags.AllowWhenBlockedByPopup)) 171 | end 172 | 173 | return themeWhite -------------------------------------------------------------------------------- /scripts/modules/gui/widgets/btnToggle.lua: -------------------------------------------------------------------------------- 1 | local dpi = require ("modules/gui/dpi") 2 | local themeSys = require ("modules/gui/themeSys") 3 | 4 | -- config 5 | local padding_x = 5 6 | local padding_y = 5 7 | 8 | ---@param aLabel string|string[] 9 | ---@param aValue boolean 10 | ---@param aSizeX? number 11 | ---@param aSizeY? number 12 | ---@param aAutoscale? boolean 13 | local function btnToggle(aLabel, aValue, aSizeX, aSizeY, aAutoscale) 14 | if type(aLabel) == "table" then 15 | aLabel = aValue and aLabel[1] or aLabel[2] 16 | end 17 | aSizeX = aSizeX or 0 18 | aSizeY = aSizeY or 0 19 | aAutoscale = aAutoscale==nil or aAutoscale 20 | if aAutoscale then 21 | aSizeX = dpi.Scale(aSizeX) 22 | aSizeY = dpi.Scale(aSizeY) 23 | end 24 | local imgui_style = ImGui.GetStyle() 25 | ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, imgui_style.FramePadding.x + dpi.Scale(padding_x), imgui_style.FramePadding.y + dpi.Scale(padding_y)) 26 | if aValue then 27 | themeSys.PushColor(ImGuiCol.Button, themeSys.GetCurrentTheme():GetStyleColor("CustomToggleOn")) 28 | themeSys.PushColor(ImGuiCol.ButtonHovered, themeSys.GetCurrentTheme():GetStyleColor("CustomToggleOnHovered")) 29 | themeSys.PushColor(ImGuiCol.ButtonActive, themeSys.GetCurrentTheme():GetStyleColor("CustomToggleOnActive")) 30 | themeSys.PushColor(ImGuiCol.Text, themeSys.GetCurrentTheme():GetStyleColor("CustomToggleOnText")) 31 | else 32 | themeSys.PushColor(ImGuiCol.Button, themeSys.GetCurrentTheme():GetStyleColor("Button")) 33 | themeSys.PushColor(ImGuiCol.ButtonHovered, themeSys.GetCurrentTheme():GetStyleColor("ButtonHovered")) 34 | themeSys.PushColor(ImGuiCol.ButtonActive, themeSys.GetCurrentTheme():GetStyleColor("ButtonActive")) 35 | themeSys.PushColor(ImGuiCol.Text, themeSys.GetCurrentTheme():GetStyleColor("Text")) 36 | end 37 | if ImGui.Button(aLabel, aSizeX, aSizeY) then 38 | aValue = not aValue 39 | end 40 | ImGui.PopStyleColor(4) 41 | ImGui.PopStyleVar(1) 42 | return aValue 43 | end 44 | 45 | return btnToggle -------------------------------------------------------------------------------- /scripts/modules/gui/widgets/button.lua: -------------------------------------------------------------------------------- 1 | local dpi = require ("modules/gui/dpi") 2 | 3 | -- config 4 | local padding_x = 5 5 | local padding_y = 5 6 | 7 | ---Button autoscales by default 8 | ---@param aLabel string 9 | ---@param aSizeX? number 10 | ---@param aSizeY? number 11 | ---@param aAutoscale? boolean 12 | ---@return boolean 13 | local function button(aLabel, aSizeX, aSizeY, aAutoscale) 14 | aSizeX = aSizeX or 0 15 | aSizeY = aSizeY or 0 16 | aAutoscale = aAutoscale==nil or aAutoscale 17 | if aAutoscale then 18 | aSizeX = dpi.Scale(aSizeX) 19 | aSizeY = dpi.Scale(aSizeY) 20 | end 21 | local imgui_style = ImGui.GetStyle() 22 | ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, imgui_style.FramePadding.x + dpi.Scale(padding_x), imgui_style.FramePadding.y + dpi.Scale(padding_y)) 23 | local pressed = ImGui.Button(aLabel, aSizeX, aSizeY) 24 | ImGui.PopStyleVar(1) 25 | return pressed 26 | end 27 | 28 | return button -------------------------------------------------------------------------------- /scripts/modules/gui/widgets/init.lua: -------------------------------------------------------------------------------- 1 | ---@class widget 2 | local widgets = { 3 | btnToggle = require ("modules/gui/widgets/btnToggle"), 4 | button = require("modules/gui/widgets/button"), 5 | } 6 | 7 | return widgets -------------------------------------------------------------------------------- /scripts/modules/gui/window.lua: -------------------------------------------------------------------------------- 1 | local dpi = require("modules/gui/dpi") 2 | local i18n = require("modules/i18n") 3 | local languages = require("lang/lang") 4 | local widgets = require("modules/gui/widgets") 5 | local themeSys = require("modules/gui/themeSys") 6 | local options = CETMM.GetOptions() 7 | local mods = CETMM.GetBackEnd().GetMods() 8 | local dofiles = CETMM.GetDofiles() 9 | 10 | ---@class window 11 | local window = { 12 | m_draw = false, 13 | m_draw_about = false, 14 | m_about_title = "", 15 | m_about_text = "", 16 | m_over_size = false, 17 | m_btn_Dofiles = false, 18 | m_btn_Scan = false, 19 | m_btn_Help = false 20 | } 21 | 22 | local layout = { 23 | _ = 0, 24 | tb_modlist_height = 0, 25 | tb_footer_heigh = 0, 26 | header_btn_height = 0 27 | } 28 | 29 | local function renderAboutWindow() 30 | local draw_lastframe = window.m_draw_about 31 | window.m_draw_about = ImGui.Begin(window.m_about_title, window.m_draw_about, bit32.bor(ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.NoResize)) 32 | if draw_lastframe then 33 | themeSys.GetCurrentTheme():CallIf("white", "GetHoverState", "about") 34 | ImGui.SetWindowPos(dpi.GetDisplayResolution().x / 2 - dpi.Scale(300), 35 | dpi.Scale(dpi.GetDisplayResolution().y * 0.1), 36 | ImGuiCond.FirstUseEver) 37 | ImGui.SetWindowSize(dpi.Scale(600), 38 | dpi.GetDisplayResolution().y * 0.8, ImGuiCond.FirstUseEver) 39 | ImGui.Text(window.m_about_text) 40 | ImGui.End() 41 | end 42 | end 43 | 44 | ---@param aFile string 45 | ---@return string 46 | local function loadFile(aFile) 47 | local text = "" 48 | local file = io.open(aFile) 49 | if file ~= nil then 50 | text = file:read("*a") 51 | file:close() 52 | end 53 | return text 54 | end 55 | 56 | local function settings_popup() 57 | ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, dpi.Scale(8), dpi.Scale(12)) 58 | if ImGui.BeginPopup("Settings", ImGuiWindowFlags.NoMove) then 59 | ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, dpi.Scale(8), dpi.Scale(15)) -- Menu item height 60 | ImGui.Text(i18n("text_select_settings")) 61 | 62 | options.m_autoappear = widgets.btnToggle({ 63 | i18n("button_autoappear_on"), i18n("button_autoappear_off"), 64 | }, options.m_autoappear) 65 | 66 | ImGui.Separator() 67 | 68 | -- Theme 69 | if ImGui.BeginMenu(IconGlyphs.TelevisionGuide.."\t".."Theme") then 70 | if select(2, ImGui.MenuItem("Default", "", options.m_theme == "default")) then 71 | themeSys.Load("default") 72 | end 73 | if select(2, ImGui.MenuItem("UA Special", "", options.m_theme == "ua_special")) then 74 | themeSys.Load("ua_special") 75 | end 76 | if select(2, ImGui.MenuItem("White", "", options.m_theme == "white")) then 77 | themeSys.Load("white") 78 | end 79 | ImGui.EndMenu() 80 | end 81 | 82 | -- Language menu 83 | if ImGui.BeginMenu(IconGlyphs.Translate.."\t".."Language") then 84 | for _, entry in ipairs(languages) do 85 | if select(2, ImGui.MenuItem(entry.name, "", options.m_lang == entry.id)) then 86 | options.m_lang = entry.id 87 | CETMM.GetLocale().SetLocale() 88 | end 89 | end 90 | 91 | ImGui.EndMenu() 92 | end 93 | 94 | -- Select language hint text and help button 95 | 96 | ImGui.Separator() 97 | 98 | if ImGui.MenuItem(IconGlyphs.CardAccountDetails.."\t".."License") then 99 | window.m_about_title = "License" 100 | window.m_draw_about = true 101 | window.m_about_text = loadFile("LICENSE") 102 | end 103 | if ImGui.MenuItem(IconGlyphs.License.."\t".."Third Party License") then 104 | window.m_about_title = "Third Party License" 105 | window.m_draw_about = true 106 | window.m_about_text = loadFile("Third_Party_LICENSES") 107 | end 108 | if ImGui.MenuItem(IconGlyphs.Update.."\t"..string.format([[%s (v%s)]], "Check Update", 109 | CETMM.GetVersion())) then 110 | CETMM.GetBackEnd().OpenUrl("update") 111 | end 112 | 113 | ImGui.Separator() 114 | 115 | if ImGui.MenuItem(IconGlyphs.Coffee.."\t".."Buy me a coffee") then 116 | CETMM.GetBackEnd().OpenUrl("coffee") 117 | end 118 | 119 | ImGui.PopStyleVar() -- Pop menu item height 120 | ImGui.EndPopup() 121 | end 122 | ImGui.PopStyleVar() 123 | end 124 | 125 | -- public methods 126 | 127 | function window.Initialize() 128 | window.m_over_size = 600 * dpi.GetScale() > dpi.GetDisplayResolution().y * 0.8 129 | end 130 | 131 | function window.Render() 132 | local draw_lastframe = window.m_draw 133 | window.m_draw = ImGui.Begin(i18n("window_title").."###CETMM_MAIN_WINDOW", window.m_draw) 134 | if draw_lastframe then 135 | -- Hover check for white theme 136 | themeSys.GetCurrentTheme():CallIf("white", "GetHoverState", "main") 137 | -- Set window size and position 138 | ImGui.SetWindowPos(dpi.GetDisplayResolution().x / 2 - 210 * dpi.GetScale(), 139 | dpi.GetDisplayResolution().y / 2 - 320 * dpi.GetScale(), 140 | ImGuiCond.FirstUseEver) 141 | if window.m_over_size then 142 | ImGui.SetWindowSize(420 * dpi.GetScale(), 143 | dpi.GetDisplayResolution().y * 0.8, ImGuiCond.FirstUseEver) 144 | else 145 | ImGui.SetWindowSize(420 * dpi.GetScale(), 640 * dpi.GetScale(), 146 | ImGuiCond.FirstUseEver) 147 | end 148 | 149 | -- Header Buttons 150 | if ImGui.BeginTable("header_btns", 2, ImGuiTableFlags.NoSavedSettings) then 151 | ImGui.TableSetupColumn("col1", ImGuiTableColumnFlags.WidthStretch) 152 | ImGui.TableSetupColumn("col2", ImGuiTableColumnFlags.WidthFixed) 153 | ImGui.TableNextRow() 154 | ImGui.TableSetColumnIndex(0) 155 | window.m_btn_Dofiles = widgets.btnToggle(i18n("button_dofiles"), 156 | window.m_btn_Dofiles) 157 | ImGui.TableSetColumnIndex(1) 158 | 159 | -- Scan Button 160 | if widgets.button(IconGlyphs.MagnifyScan.." "..i18n("button_scan")) then 161 | mods.Scan() 162 | dofiles.Scan() 163 | end 164 | 165 | layout._, layout.header_btn_height = ImGui.GetItemRectSize() 166 | 167 | ImGui.SameLine() 168 | 169 | -- Settings Button 170 | if widgets.button(IconGlyphs.Cog, layout.header_btn_height, layout.header_btn_height, false) then 171 | ImGui.OpenPopup("Settings") 172 | end 173 | if ImGui.IsItemHovered() then 174 | ImGui.SetTooltip(i18n("tooltip_btn_settings")) 175 | end 176 | 177 | -- Settings Popup Menu 178 | settings_popup() 179 | 180 | ImGui.SameLine() 181 | 182 | -- Help Button 183 | window.m_btn_Help = widgets.btnToggle(IconGlyphs.Help, window.m_btn_Help, 184 | layout.header_btn_height, 185 | layout.header_btn_height, false) 186 | if ImGui.IsItemHovered() then 187 | ImGui.SetTooltip(i18n("tooltip_btn_help")) 188 | end 189 | 190 | ImGui.EndTable() 191 | end 192 | 193 | -- Helper Text 194 | if window.m_btn_Help then 195 | if not window.m_btn_Dofiles then 196 | ImGui.TextWrapped(i18n("text_help_manager_1")) 197 | ImGui.Spacing() 198 | ImGui.TextWrapped(i18n("text_help_manager_2")) 199 | ImGui.Spacing() 200 | ImGui.TextWrapped(i18n("text_help_manager_3")) 201 | ImGui.Spacing() 202 | ImGui.TextWrapped(i18n("text_help_manager_4")) 203 | ImGui.Spacing() 204 | ImGui.TextWrapped(i18n("text_help_manager_5")) 205 | else 206 | themeSys.PushColor(ImGuiCol.Text, themeSys.GetCurrentTheme():GetStyleColor("AltText")) 207 | ImGui.TextWrapped(i18n("text_help_dofiles_1")) 208 | ImGui.Spacing() 209 | ImGui.TextWrapped(i18n("text_help_dofiles_2")) 210 | ImGui.Spacing() 211 | ImGui.TextWrapped(i18n("text_help_dofiles_3")) 212 | ImGui.Spacing() 213 | ImGui.TextWrapped(i18n("text_help_dofiles_4")) 214 | ImGui.Spacing() 215 | ImGui.TextWrapped(i18n("text_help_dofiles_5")) 216 | ImGui.PopStyleColor(1) 217 | end 218 | ImGui.Spacing() 219 | end 220 | 221 | -- Mod List 222 | layout._, layout.tb_modlist_height = ImGui.GetContentRegionAvail() 223 | ImGui.PushStyleVar(ImGuiStyleVar.CellPadding, dpi.Scale(4), dpi.Scale(6)) 224 | if ImGui.BeginTable("mod_list", 2, bit32.bor( 225 | ImGuiTableFlags.NoSavedSettings, 226 | ImGuiTableFlags.ScrollY), 0, 227 | layout.tb_modlist_height - layout.tb_footer_heigh - 228 | ImGui.GetStyle().ItemSpacing.y) then 229 | 230 | ImGui.TableSetupColumn("cb", ImGuiTableColumnFlags.WidthFixed) 231 | ImGui.TableSetupColumn("name", ImGuiTableColumnFlags.WidthStretch) 232 | 233 | -- Mod list 234 | if not window.m_btn_Dofiles then 235 | ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, 5, 5) 236 | 237 | if #mods.GetCETMods() == 0 then -- Hint text when not scanned 238 | ImGui.TableNextRow(ImGuiTableRowFlags.None, 30 * dpi.GetScale()) 239 | ImGui.TableSetColumnIndex(0) 240 | ImGui.Text(i18n.translate("text_please_scan")) 241 | 242 | else 243 | for _, entry in ipairs(mods.GetCETMods()) do 244 | ImGui.TableNextRow(ImGuiTableRowFlags.None, 30 * dpi.GetScale()) 245 | ImGui.TableSetColumnIndex(0) 246 | ImGui.BeginDisabled(entry:GetName() == "cet_mod_manager") 247 | local state, pressed = ImGui.Checkbox("##" .. entry:GetName(), 248 | entry:IsEnabled()) 249 | ImGui.EndDisabled() 250 | if pressed then 251 | entry:Toggle() 252 | end 253 | ImGui.TableSetColumnIndex(1) 254 | ImGui.Text(entry:GetFormatedName()) 255 | end 256 | end 257 | 258 | ImGui.PopStyleVar(1) 259 | 260 | -- Dofile list 261 | else 262 | if (#dofiles.Get()) == 0 then -- Hint text when no dofiles 263 | ImGui.TableNextRow(ImGuiTableRowFlags.None, 30 * dpi.GetScale()) 264 | ImGui.TableSetColumnIndex(0) 265 | ImGui.Text(i18n.translate("text_no_dofiles")) 266 | 267 | else 268 | for _, entry in ipairs(dofiles.Get()) do 269 | ImGui.TableNextRow(ImGuiTableRowFlags.None, 30 * dpi.GetScale()) 270 | ImGui.TableSetColumnIndex(0) 271 | if widgets.button(i18n("button_dofile_run").."##" .. entry:GetName()) then 272 | entry:Run() 273 | end 274 | ImGui.TableSetColumnIndex(1) 275 | ImGui.Text(entry:GetFormatedName()) 276 | end 277 | end 278 | end 279 | 280 | ImGui.EndTable() 281 | end 282 | ImGui.PopStyleVar(1) 283 | 284 | -- Footer Buttons 285 | if ImGui.BeginTable("footer_btns", 2, ImGuiTableFlags.NoSavedSettings) then 286 | ImGui.TableSetupColumn("col1", ImGuiTableColumnFlags.WidthStretch) 287 | ImGui.TableSetupColumn("col2", ImGuiTableColumnFlags.WidthFixed) 288 | ImGui.TableNextRow() 289 | ImGui.TableSetColumnIndex(0) 290 | 291 | if widgets.button(IconGlyphs.FolderHome.." "..i18n("button_mods_folder")) then 292 | CETMM.GetBackEnd().OpenModsFolder() 293 | end 294 | 295 | ImGui.SameLine() 296 | 297 | if widgets.button(IconGlyphs.FolderFile.." "..i18n("button_dofile_folder")) then 298 | CETMM.GetBackEnd().OpenDofilesFolder() 299 | end 300 | 301 | themeSys.GetCurrentTheme():CallIf("ua_special", "RenderFooter") 302 | 303 | ImGui.EndTable() 304 | end 305 | layout._, layout.tb_footer_heigh = ImGui.GetItemRectSize() 306 | ImGui.End() 307 | end 308 | 309 | renderAboutWindow() 310 | -- renderFontWidnow() 311 | end 312 | 313 | return window 314 | -------------------------------------------------------------------------------- /scripts/modules/gui/windows/init.lua: -------------------------------------------------------------------------------- 1 | local windows = { 2 | uninstall = require("modules/gui/windows/uninstall"), 3 | } 4 | 5 | 6 | return windows -------------------------------------------------------------------------------- /scripts/modules/gui/windows/uninstall.lua: -------------------------------------------------------------------------------- 1 | local backend = require("modules/backend") 2 | local EXT_Uninstall = backend.GetUninstall() 3 | local widget = require("modules/gui/widgets") 4 | local dpi = require("modules/gui/dpi") 5 | 6 | ---@class windows.uninstall 7 | local uninstall = { 8 | m_draw = true, 9 | m_removeConfig = false, 10 | m_removeDofiles = false, 11 | } 12 | 13 | function uninstall.Render() 14 | if uninstall.m_draw then 15 | ImGui.Begin(IconGlyphs.AlertDecagramOutline.." CET Mod Manager Uninstalled", bit32.bor(ImGuiWindowFlags.NoSavedSettings, ImGuiWindowFlags.AlwaysAutoResize, ImGuiWindowFlags.NoCollapse)) 16 | ImGui.SetWindowPos((dpi.GetDisplayResolution().x - ImGui.GetWindowWidth())/2, (dpi.GetDisplayResolution().y - ImGui.GetWindowHeight())/2, ImGuiCond.Always) 17 | ImGui.Text("It appears that you have uninstalled CET Mod Manager,\nDo you want to remove the leftover files?") 18 | ImGui.Spacing() 19 | uninstall.m_removeConfig = ImGui.Checkbox("Remove the config file.", uninstall.m_removeConfig) 20 | uninstall.m_removeDofiles = ImGui.Checkbox("Remove the Dofile folder and it's contents.", uninstall.m_removeDofiles) 21 | ImGui.Spacing() 22 | 23 | if ImGui.BeginTable("footer_btns", 2, ImGuiTableFlags.NoSavedSettings) then 24 | ImGui.TableSetupColumn("col1", ImGuiTableColumnFlags.WidthStretch) 25 | ImGui.TableSetupColumn("col2", ImGuiTableColumnFlags.WidthStretch) 26 | ImGui.TableNextRow() 27 | ImGui.TableSetColumnIndex(1) 28 | 29 | if widget.button(IconGlyphs.CheckBold.."\tYes\t", 80, 0, true) then 30 | EXT_Uninstall.SetFilesToRemove(true, uninstall.m_removeConfig, uninstall.m_removeDofiles) 31 | uninstall.m_draw = false 32 | end 33 | ImGui.SameLine() 34 | if widget.button(IconGlyphs.CloseThick.."\tNo\t", 80, 0, true) then 35 | uninstall.m_draw = false 36 | end 37 | 38 | ImGui.EndTable() 39 | end 40 | ImGui.End() 41 | end 42 | end 43 | 44 | return uninstall -------------------------------------------------------------------------------- /scripts/modules/hotkeys.lua: -------------------------------------------------------------------------------- 1 | local i18n = require("modules/i18n") 2 | 3 | ---@class hotkeys 4 | local hotkeys = {} 5 | 6 | -- public 7 | function hotkeys.Register() 8 | registerHotkey("hotkey_manager", i18n.translate("hotkey_manager"), function () 9 | CETMM.GetUISystem().GetWindow().m_btn_Dofiles = false 10 | CETMM.GetUISystem().GetWindow().m_draw = not CETMM.GetUISystem().GetWindow().m_draw 11 | end) 12 | 13 | registerHotkey("hotkey_dofiles", i18n.translate("hotkey_dofiles"), function () 14 | CETMM.GetUISystem().GetWindow().m_btn_Dofiles = true 15 | CETMM.GetUISystem().GetWindow().m_draw = not CETMM.GetUISystem().GetWindow().m_draw 16 | end) 17 | end 18 | 19 | return hotkeys -------------------------------------------------------------------------------- /scripts/modules/i18n/README.md: -------------------------------------------------------------------------------- 1 | Forked from https://github.com/kikito/i18n.lua 2 | 3 | i18n.lua 4 | ======== 5 | 6 | [![Build Status](https://travis-ci.org/kikito/i18n.lua.png?branch=master)](https://travis-ci.org/kikito/i18n.lua) 7 | 8 | A very complete i18n lib for Lua 9 | 10 | Description 11 | =========== 12 | 13 | ``` lua 14 | i18n = require 'i18n' 15 | 16 | -- loading stuff 17 | i18n.set('en.welcome', 'welcome to this program') 18 | i18n.load({ 19 | en = { 20 | good_bye = "good-bye!", 21 | age_msg = "your age is %{age}.", 22 | phone_msg = { 23 | one = "you have one new message.", 24 | other = "you have %{count} new messages." 25 | } 26 | } 27 | }) 28 | i18n.loadFile('path/to/your/project/i18n/de.lua') -- load German language file 29 | i18n.loadFile('path/to/your/project/i18n/fr.lua') -- load French language file 30 | … -- section 'using language files' below describes structure of files 31 | 32 | -- setting the translation context 33 | i18n.setLocale('en') -- English is the default locale anyway 34 | 35 | -- getting translations 36 | i18n.translate('welcome') -- Welcome to this program 37 | i18n('welcome') -- Welcome to this program 38 | i18n('age_msg', {age = 18}) -- Your age is 18. 39 | i18n('phone_msg', {count = 1}) -- You have one new message. 40 | i18n('phone_msg', {count = 2}) -- You have 2 new messages. 41 | i18n('good_bye') -- Good-bye! 42 | 43 | ``` 44 | 45 | Interpolation 46 | ============= 47 | 48 | You can interpolate variables in 3 different ways: 49 | 50 | ``` lua 51 | -- the most usual one 52 | i18n.set('variables', 'Interpolating variables: %{name} %{age}') 53 | i18n('variables', {name='john', 'age'=10}) -- Interpolating variables: john 10 54 | 55 | i18n.set('lua', 'Traditional Lua way: %d %s') 56 | i18n('lua', {1, 'message'}) -- Traditional Lua way: 1 message 57 | 58 | i18n.set('combined', 'Combined: %.q %.d %.o') 59 | i18n('combined', {name='john', 'age'=10}) -- Combined: john 10 12k 60 | ``` 61 | 62 | 63 | 64 | Pluralization 65 | ============= 66 | 67 | This lib implements the [unicode.org plural rules](http://cldr.unicode.org/index/cldr-spec/plural-rules). Just set the locale you want to use and it will deduce the appropiate pluralization rules: 68 | 69 | ``` lua 70 | i18n = require 'i18n' 71 | 72 | i18n.load({ 73 | en = { 74 | msg = { 75 | one = "one message", 76 | other = "%{count} messages" 77 | } 78 | }, 79 | ru = { 80 | msg = { 81 | one = "1 сообщение", 82 | few = "%{count} сообщения", 83 | many = "%{count} сообщений", 84 | other = "%{count} сообщения" 85 | } 86 | } 87 | }) 88 | 89 | i18n('msg', {count = 1}) -- one message 90 | i18n.setLocale('ru') 91 | i18n('msg', {count = 5}) -- 5 сообщений 92 | ``` 93 | 94 | The appropiate rule is chosen by finding the 'root' of the locale used: for example if the current locale is 'fr-CA', the 'fr' rules will be applied. 95 | 96 | If the provided functions are not enough (i.e. invented languages) it's possible to specify a custom pluralization function in the second parameter of setLocale. This function must return 'one', 'few', 'other', etc given a number. 97 | 98 | Fallbacks 99 | ========= 100 | 101 | When a value is not found, the lib has several fallback mechanisms: 102 | 103 | * First, it will look in the current locale's parents. For example, if the locale was set to 'en-US' and the key 'msg' was not found there, it will be looked over in 'en'. 104 | * Second, if the value is not found in the locale ancestry, a 'fallback locale' (by default: 'en') can be used. If the fallback locale has any parents, they will be looked over too. 105 | * Third, if all the locales have failed, but there is a param called 'default' on the provided data, it will be used. 106 | * Otherwise the translation will return nil. 107 | 108 | The parents of a locale are found by splitting the locale by its hyphens. Other separation characters (spaces, underscores, etc) are not supported. 109 | 110 | Using language files 111 | ==================== 112 | 113 | It might be a good idea to store each translation in a different file. This is supported via the 'i18n.loadFile' directive: 114 | 115 | ``` lua 116 | … 117 | i18n.loadFile('path/to/your/project/i18n/de.lua') -- German translation 118 | i18n.loadFile('path/to/your/project/i18n/en.lua') -- English translation 119 | i18n.loadFile('path/to/your/project/i18n/fr.lua') -- French translation 120 | … 121 | ``` 122 | 123 | The German language file 'de.lua' should read: 124 | 125 | ``` lua 126 | return { 127 | de = { 128 | good_bye = "Auf Wiedersehen!", 129 | age_msg = "Ihr Alter beträgt %{age}.", 130 | phone_msg = { 131 | one = "Sie haben eine neue Nachricht.", 132 | other = "Sie haben %{count} neue Nachrichten." 133 | } 134 | } 135 | } 136 | ``` 137 | 138 | If desired, you can also store all translations in one single file (eg. 'translations.lua'): 139 | 140 | ``` lua 141 | return { 142 | de = { 143 | good_bye = "Auf Wiedersehen!", 144 | age_msg = "Ihr Alter beträgt %{age}.", 145 | phone_msg = { 146 | one = "Sie haben eine neue Nachricht.", 147 | other = "Sie haben %{count} neue Nachrichten." 148 | } 149 | }, 150 | fr = { 151 | good_bye = "Au revoir !", 152 | age_msg = "Vous avez %{age} ans.", 153 | phone_msg = { 154 | one = "Vous avez une noveau message.", 155 | other = "Vous avez %{count} noveaux messages." 156 | } 157 | }, 158 | … 159 | } 160 | ``` 161 | 162 | Specs 163 | ===== 164 | This project uses [busted](https://github.com/Olivine-Labs/busted) for its specs. If you want to run the specs, you will have to install it first. Then just execute the following from the root inspect folder: 165 | 166 | busted 167 | -------------------------------------------------------------------------------- /scripts/modules/i18n/init.lua: -------------------------------------------------------------------------------- 1 | local i18n = {} 2 | 3 | local store 4 | local locale 5 | local pluralizeFunction 6 | local defaultLocale = 'en_us' 7 | local fallbackLocale = defaultLocale 8 | 9 | local currentFilePath = "modules/i18n" 10 | 11 | local plural = require(currentFilePath .. '/plural') 12 | local interpolate = require(currentFilePath .. '/interpolate') 13 | local variants = require(currentFilePath .. '/variants') 14 | local version = require(currentFilePath .. '/version') 15 | 16 | i18n.plural, i18n.interpolate, i18n.variants, i18n.version, i18n._VERSION = 17 | plural, interpolate, variants, version, version 18 | 19 | -- private stuff 20 | 21 | local function dotSplit(str) 22 | local fields, length = {},0 23 | str:gsub("[^%.]+", function(c) 24 | length = length + 1 25 | fields[length] = c 26 | end) 27 | return fields, length 28 | end 29 | 30 | local function isPluralTable(t) 31 | return type(t) == 'table' and type(t.other) == 'string' 32 | end 33 | 34 | local function isPresent(str) 35 | return type(str) == 'string' and #str > 0 36 | end 37 | 38 | local function assertPresent(functionName, paramName, value) 39 | if isPresent(value) then return end 40 | 41 | local msg = "i18n.%s requires a non-empty string on its %s. Got %s (a %s value)." 42 | error(msg:format(functionName, paramName, tostring(value), type(value))) 43 | end 44 | 45 | local function assertPresentOrPlural(functionName, paramName, value) 46 | if isPresent(value) or isPluralTable(value) then return end 47 | 48 | local msg = "i18n.%s requires a non-empty string or plural-form table on its %s. Got %s (a %s value)." 49 | error(msg:format(functionName, paramName, tostring(value), type(value))) 50 | end 51 | 52 | local function assertPresentOrTable(functionName, paramName, value) 53 | if isPresent(value) or type(value) == 'table' then return end 54 | 55 | local msg = "i18n.%s requires a non-empty string or table on its %s. Got %s (a %s value)." 56 | error(msg:format(functionName, paramName, tostring(value), type(value))) 57 | end 58 | 59 | local function assertFunctionOrNil(functionName, paramName, value) 60 | if value == nil or type(value) == 'function' then return end 61 | 62 | local msg = "i18n.%s requires a function (or nil) on param %s. Got %s (a %s value)." 63 | error(msg:format(functionName, paramName, tostring(value), type(value))) 64 | end 65 | 66 | local function defaultPluralizeFunction(count) 67 | return plural.get(variants.root(i18n.getLocale()), count) 68 | end 69 | 70 | local function pluralize(t, data) 71 | assertPresentOrPlural('interpolatePluralTable', 't', t) 72 | data = data or {} 73 | local count = data.count or 1 74 | local plural_form = pluralizeFunction(count) 75 | return t[plural_form] 76 | end 77 | 78 | local function treatNode(node, data) 79 | if type(node) == 'string' then 80 | return interpolate(node, data) 81 | elseif isPluralTable(node) then 82 | return interpolate(pluralize(node, data), data) 83 | end 84 | return node 85 | end 86 | 87 | local function recursiveLoad(currentContext, data) 88 | local composedKey 89 | for k,v in pairs(data) do 90 | composedKey = (currentContext and (currentContext .. '.') or "") .. tostring(k) 91 | assertPresent('load', composedKey, k) 92 | assertPresentOrTable('load', composedKey, v) 93 | if type(v) == 'string' then 94 | i18n.set(composedKey, v) 95 | else 96 | recursiveLoad(composedKey, v) 97 | end 98 | end 99 | end 100 | 101 | local function localizedTranslate(key, loc, data) 102 | local path, length = dotSplit(loc .. "." .. key) 103 | local node = store 104 | 105 | for i=1, length do 106 | node = node[path[i]] 107 | if not node then return nil end 108 | end 109 | 110 | return treatNode(node, data) 111 | end 112 | 113 | -- public interface 114 | 115 | function i18n.set(key, value) 116 | assertPresent('set', 'key', key) 117 | assertPresentOrPlural('set', 'value', value) 118 | 119 | local path, length = dotSplit(key) 120 | local node = store 121 | 122 | for i=1, length-1 do 123 | key = path[i] 124 | node[key] = node[key] or {} 125 | node = node[key] 126 | end 127 | 128 | local lastKey = path[length] 129 | node[lastKey] = value 130 | end 131 | 132 | function i18n.translate(key, data) 133 | assertPresent('translate', 'key', key) 134 | 135 | data = data or {} 136 | local usedLocale = data.locale or locale 137 | 138 | local fallbacks = variants.fallbacks(usedLocale, fallbackLocale) 139 | for i=1, #fallbacks do 140 | local value = localizedTranslate(key, fallbacks[i], data) 141 | if value then return value end 142 | end 143 | 144 | return data.default 145 | end 146 | 147 | function i18n.setLocale(newLocale, newPluralizeFunction) 148 | assertPresent('setLocale', 'newLocale', newLocale) 149 | assertFunctionOrNil('setLocale', 'newPluralizeFunction', newPluralizeFunction) 150 | locale = newLocale 151 | pluralizeFunction = newPluralizeFunction or defaultPluralizeFunction 152 | end 153 | 154 | function i18n.setFallbackLocale(newFallbackLocale) 155 | assertPresent('setFallbackLocale', 'newFallbackLocale', newFallbackLocale) 156 | fallbackLocale = newFallbackLocale 157 | end 158 | 159 | function i18n.getFallbackLocale() 160 | return fallbackLocale 161 | end 162 | 163 | function i18n.getLocale() 164 | return locale 165 | end 166 | 167 | function i18n.reset() 168 | store = {} 169 | plural.reset() 170 | i18n.setLocale(defaultLocale) 171 | i18n.setFallbackLocale(defaultLocale) 172 | end 173 | 174 | function i18n.load(data) 175 | recursiveLoad(nil, data) 176 | end 177 | 178 | function i18n.loadFile(path) 179 | local chunk = assert(loadfile(path)) 180 | local data = chunk() 181 | i18n.load(data) 182 | end 183 | 184 | setmetatable(i18n, {__call = function(_, ...) return i18n.translate(...) end}) 185 | 186 | i18n.reset() 187 | 188 | return i18n 189 | -------------------------------------------------------------------------------- /scripts/modules/i18n/interpolate.lua: -------------------------------------------------------------------------------- 1 | local unpack = unpack or table.unpack -- lua 5.2 compat 2 | 3 | local FORMAT_CHARS = { c=1, d=1, E=1, e=1, f=1, g=1, G=1, i=1, o=1, u=1, X=1, x=1, s=1, q=1, ['%']=1 } 4 | 5 | -- matches a string of type %{age} 6 | local function interpolateValue(string, variables) 7 | return string:gsub("(.?)%%{%s*(.-)%s*}", 8 | function (previous, key) 9 | if previous == "%" then 10 | return 11 | else 12 | return previous .. tostring(variables[key]) 13 | end 14 | end) 15 | end 16 | 17 | -- matches a string of type %.d 18 | local function interpolateField(string, variables) 19 | return string:gsub("(.?)%%<%s*(.-)%s*>%.([cdEefgGiouXxsq])", 20 | function (previous, key, format) 21 | if previous == "%" then 22 | return 23 | else 24 | return previous .. string.format("%" .. format, variables[key] or "nil") 25 | end 26 | end) 27 | end 28 | 29 | local function escapePercentages(string) 30 | return string:gsub("(%%)(.?)", function(_, char) 31 | if FORMAT_CHARS[char] then 32 | return "%" .. char 33 | else 34 | return "%%" .. char 35 | end 36 | end) 37 | end 38 | 39 | local function unescapePercentages(string) 40 | return string:gsub("(%%%%)(.?)", function(_, char) 41 | if FORMAT_CHARS[char] then 42 | return "%" .. char 43 | else 44 | return "%%" .. char 45 | end 46 | end) 47 | end 48 | 49 | local function interpolate(pattern, variables) 50 | variables = variables or {} 51 | local result = pattern 52 | result = interpolateValue(result, variables) 53 | result = interpolateField(result, variables) 54 | result = escapePercentages(result) 55 | result = string.format(result, unpack(variables)) 56 | result = unescapePercentages(result) 57 | return result 58 | end 59 | 60 | return interpolate 61 | -------------------------------------------------------------------------------- /scripts/modules/i18n/plural.lua: -------------------------------------------------------------------------------- 1 | local plural = {} 2 | local defaultFunction = nil 3 | -- helper functions 4 | 5 | local function assertPresentString(functionName, paramName, value) 6 | if type(value) ~= 'string' or #value == 0 then 7 | local msg = "Expected param %s of function %s to be a string, but got %s (a value of type %s) instead" 8 | error(msg:format(paramName, functionName, tostring(value), type(value))) 9 | end 10 | end 11 | 12 | local function assertNumber(functionName, paramName, value) 13 | if type(value) ~= 'number' then 14 | local msg = "Expected param %s of function %s to be a number, but got %s (a value of type %s) instead" 15 | error(msg:format(paramName, functionName, tostring(value), type(value))) 16 | end 17 | end 18 | 19 | -- transforms "foo bar baz" into {'foo','bar','baz'} 20 | local function words(str) 21 | local result, length = {}, 0 22 | str:gsub("%S+", function(word) 23 | length = length + 1 24 | result[length] = word 25 | end) 26 | return result 27 | end 28 | 29 | local function isInteger(n) 30 | return n == math.floor(n) 31 | end 32 | 33 | local function between(value, min, max) 34 | return value >= min and value <= max 35 | end 36 | 37 | local function inside(v, list) 38 | for i=1, #list do 39 | if v == list[i] then return true end 40 | end 41 | return false 42 | end 43 | 44 | 45 | -- pluralization functions 46 | 47 | local pluralization = {} 48 | 49 | local f1 = function(n) 50 | return n == 1 and "one" or "other" 51 | end 52 | pluralization[f1] = words([[ 53 | af asa bem bez bg bn brx ca cgg chr da de dv ee el 54 | en eo es et eu fi fo fur fy gl gsw gu ha haw he is 55 | it jmc kaj kcg kk kl ksb ku lb lg mas ml mn mr nah 56 | nb nd ne nl nn no nr ny nyn om or pa pap ps pt rm 57 | rof rwk saq seh sn so sq ss ssy st sv sw syr ta te 58 | teo tig tk tn ts ur ve vun wae xh xog zu 59 | ]]) 60 | 61 | local f2 = function(n) 62 | return (n == 0 or n == 1) and "one" or "other" 63 | end 64 | pluralization[f2] = words("ak am bh fil guw hi ln mg nso ti tl wa") 65 | 66 | local f3 = function(n) 67 | if not isInteger(n) then return 'other' end 68 | return (n == 0 and "zero") or 69 | (n == 1 and "one") or 70 | (n == 2 and "two") or 71 | (between(n % 100, 3, 10) and "few") or 72 | (between(n % 100, 11, 99) and "many") or 73 | "other" 74 | end 75 | pluralization[f3] = {'ar'} 76 | 77 | local f4 = function() 78 | return "other" 79 | end 80 | pluralization[f4] = words([[ 81 | az bm bo dz fa hu id ig ii ja jv ka kde kea km kn 82 | ko lo ms my root sah ses sg th to tr vi wo yo zh 83 | ]]) 84 | 85 | local f5 = function(n) 86 | if not isInteger(n) then return 'other' end 87 | local n_10, n_100 = n % 10, n % 100 88 | return (n_10 == 1 and n_100 ~= 11 and 'one') or 89 | (between(n_10, 2, 4) and not between(n_100, 12, 14) and 'few') or 90 | ((n_10 == 0 or between(n_10, 5, 9) or between(n_100, 11, 14)) and 'many') or 91 | 'other' 92 | end 93 | pluralization[f5] = words('be bs hr ru sh sr uk') 94 | 95 | local f6 = function(n) 96 | if not isInteger(n) then return 'other' end 97 | local n_10, n_100 = n % 10, n % 100 98 | return (n_10 == 1 and not inside(n_100, {11,71,91}) and 'one') or 99 | (n_10 == 2 and not inside(n_100, {12,72,92}) and 'two') or 100 | (inside(n_10, {3,4,9}) and 101 | not between(n_100, 10, 19) and 102 | not between(n_100, 70, 79) and 103 | not between(n_100, 90, 99) 104 | and 'few') or 105 | (n ~= 0 and n % 1000000 == 0 and 'many') or 106 | 'other' 107 | end 108 | pluralization[f6] = {'br'} 109 | 110 | local f7 = function(n) 111 | return (n == 1 and 'one') or 112 | ((n == 2 or n == 3 or n == 4) and 'few') or 113 | 'other' 114 | end 115 | pluralization[f7] = {'cz', 'sk'} 116 | 117 | local f8 = function(n) 118 | return (n == 0 and 'zero') or 119 | (n == 1 and 'one') or 120 | (n == 2 and 'two') or 121 | (n == 3 and 'few') or 122 | (n == 6 and 'many') or 123 | 'other' 124 | end 125 | pluralization[f8] = {'cy'} 126 | 127 | local f9 = function(n) 128 | return (n >= 0 and n < 2 and 'one') or 129 | 'other' 130 | end 131 | pluralization[f9] = {'ff', 'fr', 'kab'} 132 | 133 | local f10 = function(n) 134 | return (n == 1 and 'one') or 135 | (n == 2 and 'two') or 136 | ((n == 3 or n == 4 or n == 5 or n == 6) and 'few') or 137 | ((n == 7 or n == 8 or n == 9 or n == 10) and 'many') or 138 | 'other' 139 | end 140 | pluralization[f10] = {'ga'} 141 | 142 | local f11 = function(n) 143 | return ((n == 1 or n == 11) and 'one') or 144 | ((n == 2 or n == 12) and 'two') or 145 | (isInteger(n) and (between(n, 3, 10) or between(n, 13, 19)) and 'few') or 146 | 'other' 147 | end 148 | pluralization[f11] = {'gd'} 149 | 150 | local f12 = function(n) 151 | local n_10 = n % 10 152 | return ((n_10 == 1 or n_10 == 2 or n % 20 == 0) and 'one') or 153 | 'other' 154 | end 155 | pluralization[f12] = {'gv'} 156 | 157 | local f13 = function(n) 158 | return (n == 1 and 'one') or 159 | (n == 2 and 'two') or 160 | 'other' 161 | end 162 | pluralization[f13] = words('iu kw naq se sma smi smj smn sms') 163 | 164 | local f14 = function(n) 165 | return (n == 0 and 'zero') or 166 | (n == 1 and 'one') or 167 | 'other' 168 | end 169 | pluralization[f14] = {'ksh'} 170 | 171 | local f15 = function(n) 172 | return (n == 0 and 'zero') or 173 | (n > 0 and n < 2 and 'one') or 174 | 'other' 175 | end 176 | pluralization[f15] = {'lag'} 177 | 178 | local f16 = function(n) 179 | if not isInteger(n) then return 'other' end 180 | if between(n % 100, 11, 19) then return 'other' end 181 | local n_10 = n % 10 182 | return (n_10 == 1 and 'one') or 183 | (between(n_10, 2, 9) and 'few') or 184 | 'other' 185 | end 186 | pluralization[f16] = {'lt'} 187 | 188 | local f17 = function(n) 189 | return (n == 0 and 'zero') or 190 | ((n % 10 == 1 and n % 100 ~= 11) and 'one') or 191 | 'other' 192 | end 193 | pluralization[f17] = {'lv'} 194 | 195 | local f18 = function(n) 196 | return((n % 10 == 1 and n ~= 11) and 'one') or 197 | 'other' 198 | end 199 | pluralization[f18] = {'mk'} 200 | 201 | local f19 = function(n) 202 | return (n == 1 and 'one') or 203 | ((n == 0 or 204 | (n ~= 1 and isInteger(n) and between(n % 100, 1, 19))) 205 | and 'few') or 206 | 'other' 207 | end 208 | pluralization[f19] = {'mo', 'ro'} 209 | 210 | local f20 = function(n) 211 | if n == 1 then return 'one' end 212 | if not isInteger(n) then return 'other' end 213 | local n_100 = n % 100 214 | return ((n == 0 or between(n_100, 2, 10)) and 'few') or 215 | (between(n_100, 11, 19) and 'many') or 216 | 'other' 217 | end 218 | pluralization[f20] = {'mt'} 219 | 220 | local f21 = function(n) 221 | if n == 1 then return 'one' end 222 | if not isInteger(n) then return 'other' end 223 | local n_10, n_100 = n % 10, n % 100 224 | 225 | return ((between(n_10, 2, 4) and not between(n_100, 12, 14)) and 'few') or 226 | ((n_10 == 0 or n_10 == 1 or between(n_10, 5, 9) or between(n_100, 12, 14)) and 'many') or 227 | 'other' 228 | end 229 | pluralization[f21] = {'pl'} 230 | 231 | local f22 = function(n) 232 | return (n == 0 or n == 1) and 'one' or 233 | 'other' 234 | end 235 | pluralization[f22] = {'shi'} 236 | 237 | local f23 = function(n) 238 | local n_100 = n % 100 239 | return (n_100 == 1 and 'one') or 240 | (n_100 == 2 and 'two') or 241 | ((n_100 == 3 or n_100 == 4) and 'few') or 242 | 'other' 243 | end 244 | pluralization[f23] = {'sl'} 245 | 246 | local f24 = function(n) 247 | return (isInteger(n) and (n == 0 or n == 1 or between(n, 11, 99)) and 'one') 248 | or 'other' 249 | end 250 | pluralization[f24] = {'tzm'} 251 | 252 | local pluralizationFunctions = {} 253 | for f,locales in pairs(pluralization) do 254 | for _,locale in ipairs(locales) do 255 | pluralizationFunctions[locale] = f 256 | end 257 | end 258 | 259 | -- public interface 260 | 261 | function plural.get(locale, n) 262 | assertPresentString('i18n.plural.get', 'locale', locale) 263 | assertNumber('i18n.plural.get', 'n', n) 264 | 265 | local f = pluralizationFunctions[locale] or defaultFunction 266 | 267 | return f(math.abs(n)) 268 | end 269 | 270 | function plural.setDefaultFunction(f) 271 | defaultFunction = f 272 | end 273 | 274 | function plural.reset() 275 | defaultFunction = pluralizationFunctions['en'] 276 | end 277 | 278 | plural.reset() 279 | 280 | return plural 281 | -------------------------------------------------------------------------------- /scripts/modules/i18n/variants.lua: -------------------------------------------------------------------------------- 1 | local variants = {} 2 | 3 | local function reverse(arr, length) 4 | local result = {} 5 | for i=1, length do result[i] = arr[length-i+1] end 6 | return result, length 7 | end 8 | 9 | local function concat(arr1, len1, arr2, len2) 10 | for i = 1, len2 do 11 | arr1[len1 + i] = arr2[i] 12 | end 13 | return arr1, len1 + len2 14 | end 15 | 16 | function variants.ancestry(locale) 17 | local result, length, accum = {},0,nil 18 | locale:gsub("[^%-]+", function(c) 19 | length = length + 1 20 | accum = accum and (accum .. '-' .. c) or c 21 | result[length] = accum 22 | end) 23 | return reverse(result, length) 24 | end 25 | 26 | function variants.isParent(parent, child) 27 | return not not child:match("^".. parent .. "%-") 28 | end 29 | 30 | function variants.root(locale) 31 | return locale:match("[^%-]+") 32 | end 33 | 34 | function variants.fallbacks(locale, fallbackLocale) 35 | if locale == fallbackLocale or 36 | variants.isParent(fallbackLocale, locale) then 37 | return variants.ancestry(locale) 38 | end 39 | if variants.isParent(locale, fallbackLocale) then 40 | return variants.ancestry(fallbackLocale) 41 | end 42 | 43 | local ancestry1, length1 = variants.ancestry(locale) 44 | local ancestry2, length2 = variants.ancestry(fallbackLocale) 45 | 46 | return concat(ancestry1, length1, ancestry2, length2) 47 | end 48 | 49 | return variants 50 | -------------------------------------------------------------------------------- /scripts/modules/i18n/version.lua: -------------------------------------------------------------------------------- 1 | return '0.9.2' 2 | -------------------------------------------------------------------------------- /scripts/modules/locale.lua: -------------------------------------------------------------------------------- 1 | local i18n = require ("modules/i18n") 2 | 3 | ---@class locale 4 | local locale = {} 5 | 6 | function locale.Initialize() 7 | i18n.loadFile("lang/en_us.lua") 8 | locale.SetLocale() 9 | end 10 | 11 | function locale.SetLocale() 12 | i18n.loadFile(string.format("lang/%s.lua", CETMM.GetOptions().m_lang)) 13 | i18n.setLocale(CETMM.GetOptions().m_lang) 14 | end 15 | 16 | return locale -------------------------------------------------------------------------------- /scripts/modules/options.lua: -------------------------------------------------------------------------------- 1 | ---@class options 2 | ---@field m_lang string 3 | ---@field m_autoappear boolean 4 | ---@field m_theme string 5 | local options = { 6 | m_lang = "en_us", 7 | m_autoappear = true, 8 | m_theme = "default" -- change the default theme here 9 | } 10 | 11 | -- private functions 12 | 13 | -- set the option to default value if it doesn't exist in the config file 14 | local function setOption(val, def) 15 | if val == nil then 16 | return def 17 | else 18 | return val 19 | end 20 | end 21 | 22 | -- public methods 23 | 24 | function options.Load() 25 | local file = io.open("config.json", "r") 26 | 27 | if file then 28 | local config = json.decode(file:read("*a")) 29 | file:close() 30 | 31 | options.m_lang = setOption(config.lang, options.m_lang) 32 | options.m_autoappear = setOption(config.autoappear, options.m_autoappear) 33 | options.m_theme = setOption(config.theme, options.m_theme) 34 | end 35 | 36 | options.Save() 37 | end 38 | 39 | function options.Save() 40 | local config = {} 41 | 42 | config["lang"] = options.m_lang 43 | config["autoappear"] = options.m_autoappear 44 | config["theme"] = options.m_theme 45 | 46 | local file = io.open("config.json", "w") 47 | if file ~= nil then 48 | file:write(json.encode(config)) 49 | file:close() 50 | end 51 | end 52 | 53 | return options -------------------------------------------------------------------------------- /scripts/modules/types.lua: -------------------------------------------------------------------------------- 1 | ---Type defines for backend 2 | ---@meta 3 | ---@diagnostic disable 4 | 5 | ---@class FontStyle 6 | ---@field family string 7 | ---@field style string 8 | 9 | ---@class FontFamily 10 | ---@field family string 11 | ---@field styles FontStyle[] 12 | 13 | ---@class Fonts 14 | ---@field currentFamily FontFamily 15 | ---@field currentStyle FontStyle 16 | ---@field currentGlyph string 17 | ---@field currentSize number 18 | ---@field settingChanged boolean 19 | ---@field families FontFamily[] 20 | ---@field SetFont fun(aFontFamily: FontFamily, aFontStyle: FontStyle, aGlyph: string, aSize: number): nil 21 | 22 | ---@class Mod 23 | ---@field GetName fun(): string 24 | ---@field GetFormatedName fun(): string 25 | ---@field IsEnabled fun(): boolean 26 | ---@field Toggle fun(): nil 27 | 28 | ---@class Mods 29 | ---@field Scan fun(): nil 30 | ---@field GetCETMods fun(): Mod[] 31 | 32 | ---@class Uninstall 33 | ---@field IsAsiRemoved fun(): bool 34 | ---@field SetFilesToRemove fun(aRemoveFiles: bool, aRemoveConfig: bool, aRemoveDofiles: bool): nil -------------------------------------------------------------------------------- /src/CETMM/CETMM.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "CETMM.h" 3 | 4 | void CETMM::Initialize() 5 | { 6 | GetUninstall().Initialize(); 7 | } 8 | 9 | void CETMM::Shutdown() 10 | { 11 | 12 | // final execute; 13 | if (ShouldRestart()) 14 | Get().restartGame(); 15 | 16 | GetUninstall().Uninitialize(); 17 | } 18 | 19 | CETMM& CETMM::Get() 20 | { 21 | static CETMM instance; 22 | return instance; 23 | } 24 | 25 | const Paths& CETMM::GetPaths() 26 | { 27 | return Get().m_paths; 28 | } 29 | 30 | Mods& CETMM::GetMods() 31 | { 32 | return Get().m_mods; 33 | } 34 | 35 | CETMMEXT& CETMM::GetCETMMEXT() 36 | { 37 | return Get().m_cetmmext; 38 | } 39 | 40 | Uninstall& CETMM::GetUninstall() 41 | { 42 | return Get().m_uninstall; 43 | } 44 | 45 | const bool CETMM::ShouldRestart() 46 | { 47 | return Get().m_restart; 48 | } 49 | 50 | void CETMM::SetRestart(bool aRestart) 51 | { 52 | Get().m_restart = aRestart; 53 | } 54 | 55 | 56 | void CETMM::restartGame() 57 | { 58 | STARTUPINFO lpStartupInfo; 59 | PROCESS_INFORMATION lpProcessInfo; 60 | 61 | ZeroMemory( &lpStartupInfo, sizeof( lpStartupInfo ) ); 62 | lpStartupInfo.cb = sizeof( lpStartupInfo ); 63 | ZeroMemory( &lpProcessInfo, sizeof( lpProcessInfo ) ); 64 | 65 | LPWSTR cmdArgs = LPWSTR(L" -modded"); // launch game with redmod enabled 66 | CreateProcess( GetPaths().EXE().wstring().c_str(), 67 | cmdArgs, NULL, NULL, 68 | NULL, NULL, NULL, NULL, 69 | &lpStartupInfo, 70 | &lpProcessInfo 71 | ); 72 | } -------------------------------------------------------------------------------- /src/CETMM/CETMM.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Paths.h" 4 | #include "EXT/Mods.h" 5 | #include "EXT/CETMMEXT.h" 6 | #include "EXT/Uninstall.h" 7 | 8 | class CETMM 9 | { 10 | public: 11 | static void Initialize(); 12 | static void Shutdown(); 13 | static CETMM& Get(); 14 | 15 | static const Paths& GetPaths(); 16 | static Mods& GetMods(); 17 | static CETMMEXT& GetCETMMEXT(); 18 | static Uninstall& GetUninstall(); 19 | 20 | static const bool ShouldRestart(); 21 | static void SetRestart(bool aRestart); 22 | 23 | CETMM(const CETMM&) = delete; 24 | CETMM(CETMM&&) = delete; 25 | CETMM& operator=(const CETMM&) = delete; 26 | CETMM& operator=(CETMM&&) = delete; 27 | 28 | private: 29 | CETMM() {} 30 | ~CETMM() {} 31 | 32 | void restartGame(); 33 | 34 | Paths m_paths; 35 | Mods m_mods; 36 | CETMMEXT m_cetmmext; 37 | Uninstall m_uninstall; 38 | bool m_restart {false}; 39 | }; -------------------------------------------------------------------------------- /src/CETMM/EXT/Auth.cpp: -------------------------------------------------------------------------------- 1 | #include "Auth.h" 2 | 3 | 4 | void Auth::Initialize() { 5 | genAuthCode(); 6 | writeAuthCodeToFile(); 7 | writeRandNamesToFile(); 8 | } 9 | 10 | void Auth::Uninitialize() { 11 | revertFiles(); 12 | } 13 | 14 | bool Auth::Authenticate(std::string aAuthCode) { 15 | return aAuthCode == m_authCode; 16 | } 17 | 18 | std::string Auth::RandomizeName(std::string aClassName) 19 | { 20 | if (m_randNames.find(aClassName) != m_randNames.end()) 21 | return m_randNames[aClassName]; 22 | else 23 | { 24 | std::string rand_name = Utilities::random_string(m_randStrLength); 25 | m_randNames.insert({aClassName, rand_name}); 26 | return rand_name; 27 | } 28 | } 29 | 30 | const std::string Auth::GetClassName(std::string aClassName) 31 | { 32 | if (m_randNames.find(aClassName) != m_randNames.end()) 33 | { 34 | return m_randNames[aClassName]; 35 | } 36 | else 37 | spdlog::error("Can't get the hash of class: {}.", aClassName); 38 | } 39 | 40 | void Auth::genAuthCode() 41 | { 42 | m_authCode = Utilities::random_string(m_randStrLength); 43 | } 44 | 45 | void Auth::writeAuthCodeToFile() {} 46 | void Auth::writeRandNamesToFile() { 47 | std::string file_content = fmt::format(\ 48 | R"(local CETMMEXT = {{ 49 | OpenFolder = {CETMM}.OpenFolder, 50 | OpenUrl = {CETMM}.OpenUrl, 51 | }} 52 | 53 | return CETMMEXT)", 54 | fmt::arg("CETMM", GetClassName("CETMM"))); 55 | std::filesystem::path file_path = CETMM::GetPaths().RandNames(); 56 | // write to file 57 | } 58 | void Auth::revertFiles() { 59 | // remove this file 60 | CETMM::GetPaths().RandNames(); 61 | } -------------------------------------------------------------------------------- /src/CETMM/EXT/Auth.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "pch.h" 4 | 5 | class Auth 6 | { 7 | public: 8 | void Initialize(); 9 | void Uninitialize(); 10 | bool Authenticate(std::string aAuthCode); 11 | std::string RandomizeName(std::string aClassName); 12 | const std::string GetClassName(std::string aClassName); 13 | 14 | private: 15 | int m_randStrLength {12}; 16 | std::unordered_map m_randNames; 17 | std::string m_authCode; 18 | 19 | void genAuthCode(); 20 | void writeAuthCodeToFile(); 21 | void writeRandNamesToFile(); 22 | void revertFiles(); 23 | }; 24 | -------------------------------------------------------------------------------- /src/CETMM/EXT/CETMMEXT.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "RED4ext/Scripting/Natives/Generated/ink/ISystemRequestsHandler.hpp" 3 | #include "Misc.h" 4 | #include "CETMMEXT.h" 5 | 6 | // RED4ext impl 7 | 8 | RED4ext::TTypedClass cls("CETMMEXT"); 9 | 10 | RED4ext::CClass* CETMMEXT::GetNativeType() 11 | { 12 | return &cls; 13 | } 14 | 15 | 16 | // functions 17 | void RED4ext_CETMM::GetMods(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, RED4ext::Handle* aOut, int64_t a4) 18 | { 19 | aFrame->code++; 20 | 21 | if (aOut) 22 | { 23 | RED4ext::Handle handle(&CETMM::GetMods()); 24 | auto type = RED4ext::CRTTISystem::Get()->GetType("handle:Mods"); 25 | type->Assign(aOut, &handle); 26 | } 27 | } 28 | 29 | void RED4ext_CETMM::GetUninstall(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, RED4ext::Handle* aOut, int64_t a4) 30 | { 31 | aFrame->code++; 32 | 33 | if (aOut) 34 | { 35 | RED4ext::Handle handle(&CETMM::GetUninstall()); 36 | auto type = RED4ext::CRTTISystem::Get()->GetType("handle:Uninstall"); 37 | type->Assign(aOut, &handle); 38 | } 39 | } 40 | 41 | void RED4ext_CETMM::OpenModsFolder(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, void* aOut, int64_t a4) 42 | { 43 | aFrame->code++; 44 | 45 | Misc::openFolder(CETMM::GetPaths().CETMods()); 46 | } 47 | 48 | void RED4ext_CETMM::OpenDofilesFolder(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, void* aOut, int64_t a4) 49 | { 50 | aFrame->code++; 51 | 52 | Misc::openFolder(CETMM::GetPaths().CETMMRoot() / "dofiles"); 53 | } 54 | 55 | void RED4ext_CETMM::OpenUrl(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, void* aOut, int64_t a4) 56 | { 57 | RED4ext::CString* url_name; 58 | RED4ext::GetParameter(aFrame, &url_name); 59 | 60 | aFrame->code++; 61 | 62 | if (*url_name == "update") 63 | Misc::openUrl("https://www.nexusmods.com/cyberpunk2077/mods/895?tab=files"); 64 | 65 | if (*url_name == "coffee") 66 | Misc::openUrl("https://www.buymeacoffee.com/mingm"); 67 | 68 | if (*url_name == "font_wiki") 69 | Misc::openUrl("https://wiki.redmodding.org/cyber-engine-tweaks/getting-started/configuration/change-font-and-font-size#how-to-display-non-english-characters"); 70 | } 71 | 72 | void RED4ext_CETMM::RestartGame(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, void* aOut, int64_t a4) 73 | { 74 | aFrame->code++; 75 | CETMM::SetRestart(true); 76 | } 77 | 78 | 79 | // register 80 | 81 | void RED4ext_CETMM::Register() 82 | { 83 | RED4ext::CNamePool::Add("CETMMEXT"); 84 | cls.flags = {.isNative = true}; 85 | RED4ext::CRTTISystem::Get()->RegisterType(&cls); 86 | } 87 | 88 | void RED4ext_CETMM::PostRegister() 89 | { 90 | auto func_getMods = RED4ext::CClassStaticFunction::Create(&cls, "GetMods", "GetMods", &GetMods, {.isNative = true, .isStatic = true}); 91 | func_getMods->SetReturnType("handle:Mods"); 92 | cls.RegisterFunction(func_getMods); 93 | 94 | auto func_getUninstall = RED4ext::CClassStaticFunction::Create(&cls, "GetUninstall", "GetUninstall", &GetUninstall, {.isNative = true, .isStatic = true}); 95 | func_getUninstall->SetReturnType("handle:Uninstall"); 96 | cls.RegisterFunction(func_getUninstall); 97 | 98 | auto func_openModsFolder = RED4ext::CClassStaticFunction::Create(&cls, "OpenModsFolder", "OpenModsFolder", &OpenModsFolder, {.isNative = true, .isStatic = true}); 99 | cls.RegisterFunction(func_openModsFolder); 100 | 101 | auto func_openDofilesFolder = RED4ext::CClassStaticFunction::Create(&cls, "OpenDofilesFolder", "OpenDofilesFolder", &OpenDofilesFolder, {.isNative = true, .isStatic = true}); 102 | cls.RegisterFunction(func_openDofilesFolder); 103 | 104 | auto func_openUrl = RED4ext::CClassStaticFunction::Create(&cls, "OpenUrl", "OpenUrl", &OpenUrl, {.isNative = true, .isStatic = true}); 105 | func_openUrl->AddParam("String", "URLName"); 106 | cls.RegisterFunction(func_openUrl); 107 | 108 | auto func_restarGame = RED4ext::CClassStaticFunction::Create(&cls, "RestartGame", "RestartGame", &RestartGame, {.isNative = true, .isStatic = true}); 109 | cls.RegisterFunction(func_restarGame); 110 | } -------------------------------------------------------------------------------- /src/CETMM/EXT/CETMMEXT.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Mods.h" 4 | #include "Uninstall.h" 5 | 6 | struct CETMMEXT : RED4ext::IScriptable 7 | { 8 | public: 9 | CETMMEXT() {}; 10 | RED4ext::CClass *GetNativeType(); 11 | 12 | private: 13 | 14 | }; 15 | 16 | namespace RED4ext_CETMM 17 | { 18 | void GetMods(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, RED4ext::Handle* aOut, int64_t a4); 19 | void GetUninstall(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, RED4ext::Handle* aOut, int64_t a4); 20 | void OpenModsFolder(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, void* aOut, int64_t a4); 21 | void OpenDofilesFolder(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, void* aOut, int64_t a4); 22 | void OpenUrl(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, void* aOut, int64_t a4); 23 | void RestartGame(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, void* aOut, int64_t a4); 24 | 25 | void Register(); 26 | void PostRegister(); 27 | } -------------------------------------------------------------------------------- /src/CETMM/EXT/Misc.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Misc.h" 3 | 4 | void Misc::openFolder(std::filesystem::path aFolder) 5 | { 6 | ShellExecute(NULL, NULL, aFolder.wstring().c_str(), NULL, NULL, SW_SHOWNORMAL); 7 | } 8 | 9 | void Misc::openUrl(std::string aUrl) 10 | { 11 | ShellExecuteA(NULL, NULL, aUrl.c_str(), NULL, NULL , SW_SHOWNORMAL); 12 | } -------------------------------------------------------------------------------- /src/CETMM/EXT/Misc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Misc 4 | { 5 | void openFolder(std::filesystem::path aFolder); 6 | void openUrl(std::string aUrl); 7 | } // namespace Misc 8 | -------------------------------------------------------------------------------- /src/CETMM/EXT/Mod.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Mod.h" 3 | 4 | std::string to_string(MODTYPE aEnum) 5 | { 6 | switch (aEnum) 7 | { 8 | case MODTYPE::CET: return "CET"; 9 | case MODTYPE::ARCHIVE: return "ARCHIVE"; 10 | case MODTYPE::REDSCRIPT: return "REDSCRIPT"; 11 | case MODTYPE::ASI: return "ASI"; 12 | case MODTYPE::RED4EXT: return "RED4EXT"; 13 | case MODTYPE::REDMOD: return "REDMOD"; 14 | default: return "unknown"; 15 | } 16 | } 17 | 18 | Mod::Mod(RED4ext::CString aName, std::filesystem::path aPath, bool aEnabled, MODTYPE aType) 19 | :m_name{ aName }, m_path{ aPath }, m_enabled{ aEnabled }, m_type{ aType } 20 | { 21 | m_formatedName = formatName(m_name); 22 | } 23 | 24 | const RED4ext::CString Mod::GetName() const 25 | { 26 | return m_name; 27 | } 28 | 29 | const RED4ext::CString Mod::GetFormatedName() const 30 | { 31 | return m_formatedName; 32 | } 33 | 34 | const std::filesystem::path Mod::GetPath() const 35 | { 36 | return m_path; 37 | } 38 | 39 | const bool Mod::IsEnabled() const 40 | { 41 | return m_enabled; 42 | } 43 | 44 | const MODTYPE Mod::GetType() const 45 | { 46 | return m_type; 47 | } 48 | 49 | const std::string Mod::GetTypeName() 50 | { 51 | return to_string(m_type); 52 | } 53 | 54 | void Mod::SetName(RED4ext::CString aName) 55 | { 56 | m_name = aName; 57 | m_formatedName = formatName(m_name); 58 | } 59 | 60 | void Mod::SetPath(std::filesystem::path aPath) 61 | { 62 | m_path = aPath; 63 | } 64 | 65 | void Mod::SetEnabled(bool aEnabled) 66 | { 67 | m_enabled = aEnabled; 68 | } 69 | 70 | void Mod::SetType(MODTYPE aType) 71 | { 72 | m_type = aType; 73 | } 74 | 75 | void Mod::Toggle() 76 | { 77 | if (m_type != MODTYPE::CET) 78 | { 79 | return; 80 | } 81 | switch (m_enabled) 82 | { 83 | case true: 84 | if (changeCETModState(false)) 85 | m_enabled = false; 86 | break; 87 | 88 | case false: 89 | if (changeCETModState(true)) 90 | m_enabled = true; 91 | break; 92 | } 93 | } 94 | 95 | RED4ext::CString Mod::formatName(RED4ext::CString aName) 96 | { 97 | std::string name = std::string(aName.c_str()); 98 | std::replace( name.begin(), name.end(), '_', ' '); 99 | std::replace( name.begin(), name.end(), '-', ' '); 100 | for (int x = 0; x < name.length(); x++) 101 | { 102 | if (x == 0) 103 | { 104 | name[x] = toupper(name[x]); 105 | } 106 | else if (name[x - 1] == ' ') 107 | { 108 | name[x] = toupper(name[x]); 109 | } 110 | } 111 | return RED4ext::CString(name.c_str()); 112 | } 113 | 114 | bool Mod::changeCETModState(bool aEnable) 115 | { 116 | std::filesystem::path enabled_filename = "init.lua"; 117 | std::filesystem::path disabled_filename = "init.lua_disabled"; 118 | std::error_code err; 119 | switch (aEnable) 120 | { 121 | case true: 122 | std::filesystem::rename(m_path / disabled_filename, m_path / enabled_filename, err); 123 | if (err) { 124 | return false; 125 | } 126 | return true; 127 | 128 | case false: 129 | std::filesystem::rename(m_path / enabled_filename, m_path / disabled_filename, err); 130 | if (err) 131 | { 132 | return false; 133 | } 134 | return true; 135 | } 136 | } 137 | 138 | 139 | // RED4ext impl 140 | 141 | RED4ext::TTypedClass cls("Mod"); 142 | 143 | RED4ext::CClass* Mod::GetNativeType() 144 | { 145 | return &cls; 146 | } 147 | 148 | void red4ext_GetName(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, RED4ext::CString* aOut, int64_t a4) 149 | { 150 | aFrame->code++; 151 | 152 | if (aOut) 153 | { 154 | *aOut = reinterpret_cast(aContext)->GetName(); 155 | } 156 | } 157 | 158 | void red4ext_GetFormatedName(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, RED4ext::CString* aOut, int64_t a4) 159 | { 160 | aFrame->code++; 161 | 162 | if (aOut) 163 | { 164 | *aOut = reinterpret_cast(aContext)->GetFormatedName(); 165 | } 166 | } 167 | 168 | void red4ext_IsEnabled(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, bool* aOut, int64_t a4) 169 | { 170 | aFrame->code++; 171 | 172 | if (aOut) 173 | { 174 | *aOut = reinterpret_cast(aContext)->IsEnabled(); 175 | } 176 | } 177 | 178 | void red4ext_Toggle(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, void* aOut, int64_t a4) 179 | { 180 | aFrame->code++; 181 | 182 | reinterpret_cast(aContext)->Toggle(); 183 | } 184 | 185 | void RED4ext_Mod::Register() 186 | { 187 | RED4ext::CNamePool::Add("Mod"); 188 | RED4ext::CNamePool::Add("handle:Mod"); 189 | RED4ext::CRTTISystem::Get()->RegisterType(&cls); 190 | } 191 | 192 | void RED4ext_Mod::PostRegister() 193 | { 194 | auto func_getName = RED4ext::CClassFunction::Create(&cls, "GetName", "GetName", 195 | &red4ext_GetName, {.isNative = true}); 196 | func_getName->SetReturnType("String"); 197 | cls.RegisterFunction(func_getName); 198 | 199 | auto func_getFormatedName = RED4ext::CClassFunction::Create(&cls, "GetFormatedName", "GetFormatedName", 200 | &red4ext_GetFormatedName, {.isNative = true}); 201 | func_getFormatedName->SetReturnType("String"); 202 | cls.RegisterFunction(func_getFormatedName); 203 | 204 | auto func_isEnabled = RED4ext::CClassFunction::Create(&cls, "IsEnabled", "IsEnabled", 205 | &red4ext_IsEnabled, {.isNative = true}); 206 | func_isEnabled->SetReturnType("Bool"); 207 | cls.RegisterFunction(func_isEnabled); 208 | 209 | auto func_toggle = RED4ext::CClassFunction::Create(&cls, "Toggle", "Toggle", 210 | &red4ext_Toggle, {.isNative = true}); 211 | cls.RegisterFunction(func_toggle); 212 | } -------------------------------------------------------------------------------- /src/CETMM/EXT/Mod.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum class MODTYPE 4 | { 5 | CET, 6 | ARCHIVE, 7 | REDSCRIPT, 8 | ASI, 9 | RED4EXT, 10 | REDMOD 11 | }; 12 | 13 | struct Mod : RED4ext::IScriptable 14 | { 15 | public: 16 | RED4ext::CClass *GetNativeType(); 17 | 18 | Mod() {}; 19 | Mod(RED4ext::CString aName, std::filesystem::path aPath, bool aEnabled, MODTYPE aType); 20 | 21 | const RED4ext::CString GetName() const; 22 | const RED4ext::CString GetFormatedName() const; 23 | const std::filesystem::path GetPath() const; 24 | const bool IsEnabled() const; 25 | const MODTYPE GetType() const; 26 | const std::string GetTypeName(); 27 | void SetName(RED4ext::CString aName); 28 | void SetPath(std::filesystem::path aPath); 29 | void SetEnabled(bool aEnabled); 30 | void SetType(MODTYPE aType); 31 | void Toggle(); 32 | 33 | private: 34 | RED4ext::CString m_name; 35 | RED4ext::CString m_formatedName; 36 | std::filesystem::path m_path; 37 | bool m_enabled; 38 | MODTYPE m_type; 39 | 40 | RED4ext::CString formatName(RED4ext::CString aName); 41 | bool changeCETModState(bool aEnable); 42 | }; 43 | 44 | namespace RED4ext_Mod 45 | { 46 | void Register(); 47 | void PostRegister(); 48 | } -------------------------------------------------------------------------------- /src/CETMM/EXT/Mods.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Mods.h" 3 | 4 | void Mods::Scan() 5 | { 6 | m_cet = scan_mods(MODTYPE::CET); 7 | // m_archive = scan_mods(MODTYPE::ARCHIVE); 8 | // m_redscript = scan_mods(MODTYPE::REDSCRIPT); 9 | // m_asi = scan_mods(MODTYPE::ASI); 10 | // m_red4ext = scan_mods(MODTYPE::RED4EXT); 11 | // m_redmod = scan_mods(MODTYPE::REDMOD); 12 | } 13 | 14 | RED4ext::DynArray> &Mods::GetCETMods() 15 | { 16 | return m_cet; 17 | } 18 | 19 | RED4ext::DynArray> Mods::scan_mods(MODTYPE aType) 20 | { 21 | RED4ext::DynArray> mod_hnds; 22 | auto modType = RED4ext::CRTTISystem::Get()->GetClass("Mod"); 23 | switch (aType) 24 | { 25 | case MODTYPE::CET: 26 | for (const auto& entry : std::filesystem::directory_iterator(CETMM::GetPaths().CETMods())) 27 | { 28 | if (entry.is_directory() && std::filesystem::exists(entry.path() / "init.lua")) 29 | { 30 | auto mod = reinterpret_cast(modType->AllocInstance()); 31 | modType->ConstructCls(mod); 32 | mod->SetName(RED4ext::CString(entry.path().filename().string().c_str())); 33 | mod->SetPath(entry.path()); 34 | mod->SetEnabled(true); 35 | mod->SetType(MODTYPE::CET); 36 | mod_hnds.EmplaceBack(mod); 37 | } 38 | 39 | else if (entry.is_directory() && std::filesystem::exists(entry.path() / "init.lua_disabled")) 40 | { 41 | auto mod = reinterpret_cast(modType->AllocInstance()); 42 | modType->ConstructCls(mod); 43 | mod->SetName(RED4ext::CString(entry.path().filename().string().c_str())); 44 | mod->SetPath(entry.path()); 45 | mod->SetEnabled(false); 46 | mod->SetType(MODTYPE::CET); 47 | mod_hnds.EmplaceBack(mod); 48 | } 49 | } 50 | break; 51 | 52 | case MODTYPE::ARCHIVE: 53 | break; 54 | 55 | case MODTYPE::REDSCRIPT: 56 | break; 57 | 58 | case MODTYPE::ASI: 59 | break; 60 | 61 | case MODTYPE::RED4EXT: 62 | break; 63 | 64 | case MODTYPE::REDMOD: 65 | break; 66 | } 67 | 68 | return mod_hnds; 69 | } 70 | 71 | // red4ext impl 72 | 73 | RED4ext::TTypedClass cls("Mods"); 74 | 75 | RED4ext::CClass* Mods::GetNativeType() 76 | { 77 | return &cls; 78 | } 79 | 80 | void red4ext_Scan(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, void* aOut, int64_t a4) 81 | { 82 | RED4EXT_UNUSED_PARAMETER(aContext); 83 | RED4EXT_UNUSED_PARAMETER(a4); 84 | RED4EXT_UNUSED_PARAMETER(aOut); 85 | RED4EXT_UNUSED_PARAMETER(aFrame); 86 | 87 | aFrame->code++; 88 | 89 | CETMM::GetMods().Scan(); 90 | } 91 | 92 | void red4ext_GetCETMods(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, RED4ext::DynArray* aOut, int64_t a4) 93 | { 94 | aFrame->code++; 95 | 96 | if (aOut) 97 | { 98 | auto type = RED4ext::CRTTISystem::Get()->GetType("array:handle:Mod"); 99 | type->Assign(aOut, &CETMM::GetMods().GetCETMods()); 100 | } 101 | } 102 | 103 | void RED4ext_Mods::Register() 104 | { 105 | RED4ext::CNamePool::Add("Mods"); 106 | RED4ext::CNamePool::Add("handle:Mods"); 107 | RED4ext::CNamePool::Add("array:handle:Mod"); 108 | RED4ext::CRTTISystem::Get()->RegisterType(&cls); 109 | } 110 | 111 | void RED4ext_Mods::PostRegister() 112 | { 113 | auto func_scan = RED4ext::CClassStaticFunction::Create(&cls, "Scan", "Scan", 114 | &red4ext_Scan, {.isNative = true, .isStatic = true}); 115 | cls.RegisterFunction(func_scan); 116 | 117 | auto func_getCETMods = RED4ext::CClassStaticFunction::Create(&cls, "GetCETMods", "GetCETMods", 118 | &red4ext_GetCETMods, {.isNative = true, .isStatic = true}); 119 | func_getCETMods->SetReturnType("array:handle:Mod"); 120 | cls.RegisterFunction(func_getCETMods); 121 | } -------------------------------------------------------------------------------- /src/CETMM/EXT/Mods.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Mod.h" 4 | 5 | struct Mods : RED4ext::IScriptable 6 | { 7 | public: 8 | Mods() {}; 9 | RED4ext::CClass *GetNativeType(); 10 | void Scan(); 11 | RED4ext::DynArray> &GetCETMods(); 12 | 13 | private: 14 | RED4ext::DynArray> m_archive; 15 | RED4ext::DynArray> m_asi; 16 | RED4ext::DynArray> m_red4ext; 17 | RED4ext::DynArray> m_redscript; 18 | RED4ext::DynArray> m_cet; 19 | RED4ext::DynArray> m_redmod; 20 | 21 | RED4ext::DynArray> scan_mods(MODTYPE aType); 22 | }; 23 | 24 | namespace RED4ext_Mods 25 | { 26 | void Register(); 27 | void PostRegister(); 28 | } -------------------------------------------------------------------------------- /src/CETMM/EXT/TypeRegister.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Mod.h" 3 | #include "Mods.h" 4 | #include "CETMMEXT.h" 5 | 6 | namespace TypeRegister 7 | { 8 | void Register() 9 | { 10 | RED4ext_Mod::Register(); 11 | RED4ext_Mods::Register(); 12 | RED4ext_CETMM::Register(); 13 | RED4ext_Uninstall::Register(); 14 | } 15 | 16 | void PostRegister() 17 | { 18 | RED4ext_Mod::PostRegister(); 19 | RED4ext_Mods::PostRegister(); 20 | RED4ext_CETMM::PostRegister(); 21 | RED4ext_Uninstall::PostRegister(); 22 | } 23 | } -------------------------------------------------------------------------------- /src/CETMM/EXT/Uninstall.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Uninstall.h" 3 | 4 | void Uninstall::Initialize() 5 | { 6 | auto asi_path = CETMM::GetPaths().Plugins() / "cet_mod_manager.asi"; 7 | m_asiExists = std::filesystem::exists(asi_path); 8 | } 9 | 10 | void Uninstall::Uninitialize() 11 | { 12 | if (m_removeFiles) 13 | { 14 | // generate remove cmd 15 | std::vector dirs_to_del = {}; 16 | std::vector files_to_del = {}; 17 | 18 | auto ext_path = CETMM::GetPaths().Red4Ext() / "cet_mod_manager"; 19 | if (std::filesystem::exists(ext_path)) 20 | dirs_to_del.push_back(ext_path); 21 | 22 | auto lua_path = CETMM::GetPaths().CETMMRoot(); 23 | if (std::filesystem::exists(lua_path)) 24 | { 25 | if (m_removeConfig && m_removeDofiles) 26 | dirs_to_del.push_back(lua_path); 27 | else 28 | { 29 | for (auto const& dir_entry : std::filesystem::directory_iterator{lua_path}) 30 | { 31 | if (dir_entry.is_directory()) 32 | { 33 | if (!m_removeDofiles && dir_entry.path().filename() == "dofiles") continue; 34 | dirs_to_del.push_back(dir_entry.path()); 35 | } 36 | if (dir_entry.is_regular_file()) 37 | { 38 | if (!m_removeConfig && dir_entry.path().filename() == "config.json") continue; 39 | files_to_del.push_back(dir_entry.path()); 40 | } 41 | } 42 | } 43 | } 44 | 45 | std::wstring rmdir_str = L""; 46 | std::wstring del_str = L""; 47 | 48 | for (auto const& dir : dirs_to_del) 49 | { 50 | rmdir_str += L" \"" + dir.wstring() + L"\""; 51 | } 52 | 53 | for (auto const& file : files_to_del) 54 | { 55 | del_str += L" \"" + file.wstring() + L"\""; 56 | } 57 | 58 | if (dirs_to_del.size() > 0) 59 | rmdir_str = fmt::format(L" & rd /s /q{}", rmdir_str); 60 | if (files_to_del.size() > 0) 61 | del_str = fmt::format(L" & del{} /f /q", del_str); 62 | 63 | std::wstring cmdArgs = fmt::format(L"/c ping localhost -n 5 > nul{}{}", rmdir_str, del_str); 64 | 65 | // remove red4ext plugin 66 | STARTUPINFO lpStartupInfo; 67 | PROCESS_INFORMATION lpProcessInfo; 68 | 69 | ZeroMemory( &lpStartupInfo, sizeof( lpStartupInfo ) ); 70 | lpStartupInfo.cb = sizeof( lpStartupInfo ); 71 | ZeroMemory( &lpProcessInfo, sizeof( lpProcessInfo ) ); 72 | 73 | CreateProcess( L"C:\\Windows\\System32\\cmd.exe", 74 | cmdArgs.data(), NULL, NULL, 75 | FALSE, CREATE_NO_WINDOW, NULL, NULL, 76 | &lpStartupInfo, 77 | &lpProcessInfo 78 | ); 79 | CloseHandle(lpProcessInfo.hThread); 80 | CloseHandle(lpProcessInfo.hProcess); 81 | } 82 | } 83 | 84 | const bool Uninstall::IsAsiRemoved() const 85 | { 86 | return !m_asiExists; 87 | } 88 | 89 | void Uninstall::SetFilesToRemove(bool aRemove, bool aConfig, bool aDofiles) 90 | { 91 | m_removeFiles = aRemove; 92 | m_removeConfig = aConfig; 93 | m_removeDofiles = aDofiles; 94 | } 95 | 96 | // red4ext impl 97 | 98 | RED4ext::TTypedClass cls("Uninstall"); 99 | 100 | RED4ext::CClass* Uninstall::GetNativeType() 101 | { 102 | return &cls; 103 | } 104 | 105 | void red4ext_IsAsiRemoved(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, bool* aOut, int64_t a4) 106 | { 107 | aFrame->code++; 108 | 109 | if (aOut) 110 | { 111 | *aOut = CETMM::GetUninstall().IsAsiRemoved(); 112 | } 113 | } 114 | 115 | void red4ext_SetFilesToRemove(RED4ext::IScriptable* aContext, RED4ext::CStackFrame* aFrame, void* aOut, int64_t a4) 116 | { 117 | bool removeFiles; 118 | bool removeConfig; 119 | bool removeDofiles; 120 | RED4ext::GetParameter(aFrame, &removeFiles); 121 | RED4ext::GetParameter(aFrame, &removeConfig); 122 | RED4ext::GetParameter(aFrame, &removeDofiles); 123 | aFrame->code++; 124 | CETMM::GetUninstall().SetFilesToRemove(removeFiles, removeConfig, removeDofiles); 125 | } 126 | 127 | void RED4ext_Uninstall::Register() 128 | { 129 | RED4ext::CNamePool::Add("Uninstall"); 130 | RED4ext::CNamePool::Add("handle:Uninstall"); 131 | RED4ext::CRTTISystem::Get()->RegisterType(&cls); 132 | } 133 | 134 | void RED4ext_Uninstall::PostRegister() 135 | { 136 | auto func_IsAsiRemoved = RED4ext::CClassStaticFunction::Create(&cls, "IsAsiRemoved", "IsAsiRemoved", 137 | &red4ext_IsAsiRemoved, {.isNative = true, .isStatic = true}); 138 | func_IsAsiRemoved->SetReturnType("Bool"); 139 | cls.RegisterFunction(func_IsAsiRemoved); 140 | 141 | auto func_SetFilesToRemove = RED4ext::CClassStaticFunction::Create(&cls, "SetFilesToRemove", "SetFilesToRemove", 142 | &red4ext_SetFilesToRemove, {.isNative = true, .isStatic = true}); 143 | func_SetFilesToRemove->AddParam("Bool", "removeFiles"); 144 | func_SetFilesToRemove->AddParam("Bool", "removeConfig"); 145 | func_SetFilesToRemove->AddParam("Bool", "removeDofiles"); 146 | cls.RegisterFunction(func_SetFilesToRemove); 147 | } -------------------------------------------------------------------------------- /src/CETMM/EXT/Uninstall.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Uninstall : RED4ext::IScriptable 4 | { 5 | public: 6 | RED4ext::CClass *GetNativeType(); 7 | 8 | Uninstall() {}; 9 | void Initialize(); 10 | void Uninitialize(); 11 | const bool IsAsiRemoved() const; 12 | void SetFilesToRemove(bool aRemove, bool aConfig = false, bool aDofiles = false); 13 | 14 | private: 15 | bool m_asiExists {true}; 16 | bool m_removeFiles {false}; 17 | bool m_removeConfig {false}; 18 | bool m_removeDofiles {false}; 19 | }; 20 | 21 | namespace RED4ext_Uninstall 22 | { 23 | void Register(); 24 | void PostRegister(); 25 | } -------------------------------------------------------------------------------- /src/CETMM/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include 3 | 4 | #include "Logger.h" 5 | #include "Version.h" 6 | 7 | std::shared_ptr CreateLogger() 8 | { 9 | const std::string pattern = fmt::format("[%Y-%m-%d %T UTC%z] [{}] [%l] %v",CETMM_VERSION); 10 | const auto fileName = CETMM::GetPaths().CETMMRoot() / "cet_mod_manager_ext.log"; 11 | auto logger = spdlog::basic_logger_mt("CETMM", fileName.string()); 12 | logger->set_pattern(pattern); 13 | return logger; 14 | } 15 | -------------------------------------------------------------------------------- /src/CETMM/Logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | std::shared_ptr CreateLogger(); -------------------------------------------------------------------------------- /src/CETMM/Utilities.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "pch.h" 3 | #include "Utilities.h" 4 | 5 | 6 | // https://inversepalindrome.com/blog/how-to-create-a-random-string-in-cpp 7 | std::string Utilities::random_string(std::size_t aLength) 8 | { 9 | const std::string CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 10 | 11 | std::random_device random_device; 12 | std::mt19937 generator(random_device()); 13 | std::uniform_int_distribution<> distribution(0, CHARACTERS.size() - 1); 14 | 15 | std::string random_string; 16 | 17 | for (std::size_t i = 0; i < aLength; ++i) 18 | { 19 | random_string += CHARACTERS[distribution(generator)]; 20 | } 21 | 22 | return random_string; 23 | } -------------------------------------------------------------------------------- /src/CETMM/Utilities.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace Utilities { 4 | 5 | std::string random_string(std::size_t aLength); 6 | 7 | } -------------------------------------------------------------------------------- /src/CETMM/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "version.h" 3 | #include 4 | #include "EXT/TypeRegister.h" 5 | 6 | static void Initialize() 7 | { 8 | try 9 | { 10 | spdlog::set_default_logger(CreateLogger()); 11 | CETMM::Initialize(); 12 | } 13 | catch (...) 14 | {} 15 | } 16 | 17 | static void Shutdown() 18 | { 19 | CETMM::Shutdown(); 20 | } 21 | 22 | RED4ext::v0::SemVer CETMM_Version() 23 | { 24 | std::string version = CETMM_VERSION; 25 | std::regex rgx(R"((\d+)\.(\d+)\.(\d+)-*(\d+)*(?=-|$))"); 26 | std::smatch matches; 27 | 28 | if(std::regex_search(version, matches, rgx)) { 29 | uint8_t major = std::stoi(matches[1].str()); 30 | uint16_t minor = std::stoi(matches[2].str()); 31 | uint32_t patch = std::stoi(matches[3].str()); 32 | uint32_t prereleaseType = RED4EXT_V0_SEMVER_PRERELEASE_TYPE_NONE; 33 | uint32_t prereleaseNumber = 0; 34 | 35 | if (matches[4].length() != 0) { 36 | prereleaseType = RED4EXT_V0_SEMVER_PRERELEASE_TYPE_RC; 37 | prereleaseNumber = std::stoi(matches[4].str()); 38 | } 39 | return RED4EXT_SEMVER_EX(major, minor, patch, prereleaseType, prereleaseNumber); 40 | } else { 41 | return RED4EXT_SEMVER(1, 0, 0); 42 | } 43 | } 44 | 45 | RED4EXT_C_EXPORT void RED4EXT_CALL RegisterTypes() 46 | { 47 | TypeRegister::Register(); 48 | } 49 | 50 | RED4EXT_C_EXPORT void RED4EXT_CALL PostRegisterTypes() 51 | { 52 | TypeRegister::PostRegister(); 53 | } 54 | 55 | RED4EXT_C_EXPORT bool RED4EXT_CALL Main(RED4ext::PluginHandle aHandle, RED4ext::EMainReason aReason, 56 | const RED4ext::Sdk* aSdk) 57 | { 58 | RED4EXT_UNUSED_PARAMETER(aHandle); 59 | RED4EXT_UNUSED_PARAMETER(aSdk); 60 | 61 | switch (aReason) 62 | { 63 | case RED4ext::EMainReason::Load: 64 | { 65 | Initialize(); 66 | 67 | RED4ext::CRTTISystem::Get()->AddRegisterCallback(RegisterTypes); 68 | RED4ext::CRTTISystem::Get()->AddPostRegisterCallback(PostRegisterTypes); 69 | 70 | break; 71 | } 72 | case RED4ext::EMainReason::Unload: 73 | { 74 | Shutdown(); 75 | break; 76 | } 77 | } 78 | 79 | return true; 80 | } 81 | 82 | RED4EXT_C_EXPORT void RED4EXT_CALL Query(RED4ext::PluginInfo* aInfo) 83 | { 84 | aInfo->name = L"CET Mod Manager"; 85 | aInfo->author = L"Ming"; 86 | aInfo->version = CETMM_Version(); 87 | aInfo->runtime = RED4EXT_RUNTIME_INDEPENDENT; 88 | aInfo->sdk = RED4EXT_SDK_LATEST; 89 | } 90 | 91 | RED4EXT_C_EXPORT uint32_t RED4EXT_CALL Supports() 92 | { 93 | return RED4EXT_API_VERSION_LATEST; 94 | } -------------------------------------------------------------------------------- /src/CETMM/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "CETMM.h" 31 | #include "Logger.h" 32 | #include "Utilities.h" -------------------------------------------------------------------------------- /src/Common/Paths.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Paths.h" 3 | 4 | Paths::Paths() 5 | { 6 | TCHAR exePathBuf[MAX_PATH] = { 0 }; 7 | GetModuleFileName(GetModuleHandle(nullptr), exePathBuf, std::size(exePathBuf)); 8 | m_exe = exePathBuf; 9 | m_exeRoot = m_exe.parent_path(); 10 | m_gameRoot = m_exeRoot.parent_path().parent_path(); 11 | m_archives = m_gameRoot / "archive" / "pc" / "mod"; 12 | m_plugins = m_exeRoot / "plugins"; 13 | m_red4ext = m_gameRoot / "red4ext" / "plugins"; 14 | m_redscript = m_gameRoot / "r6" / "scripts"; 15 | m_cetmods = m_plugins / "cyber_engine_tweaks" / "mods"; 16 | m_cetconfig = m_plugins / "cyber_engine_tweaks" / "config.json"; 17 | m_cetmmRoot = m_cetmods / "cet_mod_manager"; 18 | m_config = m_cetmmRoot / "config.json"; 19 | m_authCode = m_cetmmRoot / "authCode.lua"; 20 | m_randNames = m_cetmmRoot / "coreFunc.lua"; 21 | 22 | #ifdef DEBUG 23 | spdlog::info("m_exe: {}", m_exe.string()); 24 | spdlog::info("m_exeRoot: {}", m_exeRoot.string()); 25 | spdlog::info("m_gameRoot: {}", m_gameRoot.string()); 26 | spdlog::info("m_archives: {}", m_archives.string()); 27 | spdlog::info("m_plugins: {}", m_plugins.string()); 28 | spdlog::info("m_red4ext: {}", m_red4ext.string()); 29 | spdlog::info("m_redscript: {}", m_redscript.string()); 30 | spdlog::info("m_cetmods: {}", m_cetmods.string()); 31 | spdlog::info("m_cetconfig: {}", m_cetconfig.string()); 32 | spdlog::info("m_cetmmRoot: {}", m_cetmmRoot.string()); 33 | spdlog::info("m_config: {}", m_config.string()); 34 | #endif // DEBUG 35 | } 36 | 37 | const std::filesystem::path& Paths::GameRoot() const 38 | { 39 | return m_gameRoot; 40 | } 41 | 42 | const std::filesystem::path& Paths::Archives() const 43 | { 44 | return m_archives; 45 | } 46 | 47 | const std::filesystem::path& Paths::Plugins() const 48 | { 49 | return m_plugins; 50 | } 51 | 52 | const std::filesystem::path& Paths::Red4Ext() const 53 | { 54 | return m_red4ext; 55 | } 56 | 57 | const std::filesystem::path& Paths::RedScript() const 58 | { 59 | return m_redscript; 60 | } 61 | 62 | const std::filesystem::path& Paths::CETMods() const 63 | { 64 | return m_cetmods; 65 | } 66 | 67 | const std::filesystem::path& Paths::CETConfig() const 68 | { 69 | return m_cetconfig; 70 | } 71 | 72 | const std::filesystem::path& Paths::CETMMRoot() const 73 | { 74 | return m_cetmmRoot; 75 | } 76 | 77 | const std::filesystem::path& Paths::Config() const 78 | { 79 | return m_config; 80 | } 81 | 82 | const std::filesystem::path& Paths::AuthCode() const 83 | { 84 | return m_authCode; 85 | } 86 | 87 | const std::filesystem::path& Paths::RandNames() const 88 | { 89 | return m_randNames; 90 | } 91 | 92 | const std::filesystem::path& Paths::EXE() const 93 | { 94 | return m_exe; 95 | } -------------------------------------------------------------------------------- /src/Common/Paths.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Paths 4 | { 5 | Paths(); 6 | const std::filesystem::path& GameRoot() const; 7 | const std::filesystem::path& Archives() const; 8 | const std::filesystem::path& Plugins() const; 9 | const std::filesystem::path& Red4Ext() const; 10 | const std::filesystem::path& RedScript() const; 11 | const std::filesystem::path& CETMods() const; 12 | const std::filesystem::path& CETConfig() const; 13 | const std::filesystem::path& CETMMRoot() const; 14 | const std::filesystem::path& Config() const; 15 | const std::filesystem::path& AuthCode() const; 16 | const std::filesystem::path& RandNames() const; 17 | const std::filesystem::path& EXE() const; 18 | 19 | std::filesystem::path m_exe; 20 | std::filesystem::path m_exeRoot; 21 | std::filesystem::path m_gameRoot; 22 | std::filesystem::path m_cetmmRoot; 23 | std::filesystem::path m_archives; 24 | std::filesystem::path m_plugins; 25 | std::filesystem::path m_red4ext; 26 | std::filesystem::path m_redscript; 27 | std::filesystem::path m_cetmods; 28 | std::filesystem::path m_cetconfig; 29 | std::filesystem::path m_config; 30 | std::filesystem::path m_authCode; 31 | std::filesystem::path m_randNames; 32 | }; 33 | -------------------------------------------------------------------------------- /src/Common/Version.h.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define CETMM_VERSION "${GIT_TAG}" -------------------------------------------------------------------------------- /src/Installer/Installer.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "Installer.h" 3 | 4 | void Installer::Initialize() 5 | { 6 | GetUpdate().UpdateModule(); 7 | } 8 | 9 | void Installer::Shutdown() 10 | { 11 | 12 | } 13 | 14 | Installer& Installer::Get() 15 | { 16 | static Installer instance; 17 | return instance; 18 | } 19 | 20 | const Paths& Installer::GetPaths() 21 | { 22 | return Get().m_paths; 23 | } 24 | 25 | Update& Installer::GetUpdate() 26 | { 27 | return Get().m_update; 28 | } -------------------------------------------------------------------------------- /src/Installer/Installer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Paths.h" 4 | #include "Update.h" 5 | 6 | class Installer 7 | { 8 | public: 9 | static void Initialize(); 10 | static void Shutdown(); 11 | static Installer& Get(); 12 | 13 | static const Paths& GetPaths(); 14 | static Update& GetUpdate(); 15 | 16 | Installer(const Installer&) = delete; 17 | Installer(Installer&&) = delete; 18 | Installer& operator=(const Installer&) = delete; 19 | Installer& operator=(Installer&&) = delete; 20 | 21 | private: 22 | Installer() {} 23 | ~Installer() {} 24 | 25 | Paths m_paths; 26 | Update m_update; 27 | }; -------------------------------------------------------------------------------- /src/Installer/Logger.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include 3 | 4 | #include "Logger.h" 5 | #include "Version.h" 6 | 7 | std::shared_ptr CreateLogger() 8 | { 9 | const std::string pattern = fmt::format("[%Y-%m-%d %T UTC%z] [{}] [%l] %v",CETMM_VERSION); 10 | const auto fileName = Installer::GetPaths().CETMMRoot() / "cet_mod_manager_asi.log"; 11 | auto logger = spdlog::basic_logger_mt("CETMM", fileName.string()); 12 | logger->set_pattern(pattern); 13 | return logger; 14 | } 15 | -------------------------------------------------------------------------------- /src/Installer/Logger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | std::shared_ptr CreateLogger(); -------------------------------------------------------------------------------- /src/Installer/Update.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | #include "Update.h" 4 | #include "embeds/lua/EmbedFileManager_LooseFiles.h" 5 | #include "embeds/lua/EmbedFileManager_Lua.h" 6 | #include "embeds/red4ext/EmbedFileManager_Red4ExtPlugin.h" 7 | 8 | void Update::LogVersion() 9 | { 10 | spdlog::info("CETMM version: {}", m_version); 11 | } 12 | 13 | void Update::UpdateModule() 14 | { 15 | std::filesystem::path scriptDir = Installer::GetPaths().CETMMRoot(); 16 | std::string installed_version = getModuleVersion(); 17 | // need to deal when red4ext plugin doesn't exist 18 | if (!std::filesystem::exists(scriptDir / "modules" / "version.lua")) 19 | { 20 | spdlog::info("Scripts doesn't exist, extracting scripts..", scriptDir.string()); 21 | removeOldModule(); 22 | extractModule(); 23 | } 24 | else if (installed_version != m_version) 25 | { 26 | spdlog::info("Old scripts version({}) found, updating scripts.", installed_version); 27 | removeOldModule(); 28 | extractModule(); 29 | } 30 | std::filesystem::create_directory(scriptDir / "dofiles"); 31 | } 32 | 33 | const std::string Update::GetVersion() const 34 | { 35 | return m_version; 36 | } 37 | 38 | std::string Update::getModuleVersion() 39 | { 40 | std::filesystem::path script_version_file = Installer::GetPaths().CETMMRoot() / "modules" / "version.lua"; 41 | std::string line; 42 | std::ifstream file (script_version_file); 43 | 44 | if (!file.is_open()) 45 | { 46 | spdlog::error("Couldn't open version.lua at: {}.", script_version_file.string()); 47 | return ""; 48 | } 49 | std::getline(file, line); 50 | file.close(); 51 | 52 | std::size_t pos1 = line.find("\""); 53 | std::size_t pos2 = line.find("\"", pos1 + 1); 54 | std::string version = line.substr(pos1 + 1, pos2 - pos1 - 1); 55 | return version; 56 | } 57 | 58 | void Update::extractModule() 59 | { 60 | spdlog::info("Extracting red4ext plugin.."); 61 | std::filesystem::path pluginDir = Installer::GetPaths().Red4Ext() / "cet_mod_manager"; 62 | bin2cppRed4ExtPlugin::FileManager& mgr_ext = bin2cppRed4ExtPlugin::FileManager::getInstance(); 63 | bool saved_ext = mgr_ext.saveFiles(pluginDir.string().c_str()); 64 | if (saved_ext) 65 | spdlog::info("Extracted Red4ext plugin file to \"{}\"", pluginDir.string()); 66 | else 67 | spdlog::error("Failed to Red4ext plugin file to \"{}\"", pluginDir.string()); 68 | 69 | spdlog::info("Extracting scripts.."); 70 | std::filesystem::path scriptDir = Installer::GetPaths().CETMMRoot(); 71 | bin2cppLooseFiles::FileManager& mgr_loose = bin2cppLooseFiles::FileManager::getInstance(); 72 | bool saved_loose = mgr_loose.saveFiles(scriptDir.string().c_str()); 73 | 74 | bin2cppLua::FileManager& mgr_lua = bin2cppLua::FileManager::getInstance(); 75 | bool saved_lua = mgr_lua.saveFiles(scriptDir.string().c_str()); 76 | if (saved_loose && saved_lua) 77 | { 78 | spdlog::info("Extracted script files to \"{}\"", scriptDir.string()); 79 | // setConfig(); // white update 80 | } 81 | else 82 | spdlog::error("Failed to extract script files to \"{}\"", scriptDir.string()); 83 | } 84 | 85 | void Update::removeOldModule() 86 | { 87 | spdlog::info("Removing old files.."); 88 | 89 | { 90 | std::filesystem::path pluginPath = Installer::GetPaths().Red4Ext() / "cet_mod_manager" / "cet_mod_manager.dll"; 91 | std::error_code ec; 92 | std::filesystem::remove(pluginPath, ec); 93 | if (ec) 94 | spdlog::error("Failed to remove: {}. Error: {}", pluginPath.string(), ec.message()); 95 | spdlog::info("Removed: {}", pluginPath.string()); 96 | } 97 | 98 | std::vector exclude_files = {"dofiles", "config.json", "cet_mod_manager.log", "cet_mod_manager_asi.log"}; 99 | for (auto const& dir_entry : std::filesystem::directory_iterator{Installer::GetPaths().CETMMRoot()}) 100 | { 101 | if (std::find(exclude_files.begin(), exclude_files.end(), dir_entry.path().filename()) == exclude_files.end()) 102 | { 103 | std::error_code ec; 104 | std::filesystem::remove_all(dir_entry.path(), ec); 105 | if (ec) 106 | spdlog::error("Failed to remove: {}. Error: {}", dir_entry.path().string(), ec.message()); 107 | spdlog::info("Removed: {}", dir_entry.path().string()); 108 | } 109 | } 110 | } 111 | 112 | void Update::setConfig() // white update 113 | { 114 | spdlog::info("Updating theme config.."); 115 | 116 | std::filesystem::path configPath = Installer::GetPaths().CETMMRoot() / "config.json"; 117 | 118 | std::fstream file; 119 | file.open(configPath, std::fstream::in | std::fstream::out); 120 | if (!file.is_open()) return; 121 | 122 | nlohmann::json cetmm_config = nlohmann::json::parse(file); 123 | std::filesystem::resize_file(configPath, 0); 124 | file.seekg(0); 125 | 126 | cetmm_config["theme"] = "white"; 127 | 128 | file << cetmm_config.dump() << std::endl; 129 | file.close(); 130 | } -------------------------------------------------------------------------------- /src/Installer/Update.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Version.h" 4 | 5 | class Update 6 | { 7 | public: 8 | void LogVersion(); 9 | void UpdateModule(); 10 | const std::string GetVersion() const; 11 | 12 | private: 13 | const std::string m_version = CETMM_VERSION; 14 | const std::vector m_ignore_list = {"config.json", "dofiles"}; 15 | 16 | std::string getModuleVersion(); 17 | void extractModule(); 18 | void removeOldModule(); 19 | void setConfig(); //white update 20 | }; -------------------------------------------------------------------------------- /src/Installer/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | HANDLE hMutexHandle = nullptr; 4 | 5 | static void Initialize() 6 | { 7 | try 8 | { 9 | //Single instance check 10 | hMutexHandle = CreateMutex(NULL, TRUE, L"CETMM_Installer"); 11 | if (GetLastError() == ERROR_ALREADY_EXISTS) 12 | { 13 | return; 14 | } 15 | 16 | spdlog::set_default_logger(CreateLogger()); 17 | spdlog::flush_on(spdlog::level::info); 18 | Installer::Initialize(); 19 | } 20 | catch (...) 21 | {} 22 | } 23 | 24 | static void Shutdown() 25 | { 26 | Installer::Shutdown(); 27 | spdlog::shutdown(); 28 | } 29 | 30 | BOOL APIENTRY DllMain( HMODULE hModule, 31 | DWORD ul_reason_for_call, 32 | LPVOID lpReserved 33 | ) 34 | { 35 | switch (ul_reason_for_call) 36 | { 37 | case DLL_PROCESS_ATTACH: 38 | Initialize(); 39 | break; 40 | case DLL_PROCESS_DETACH: 41 | Shutdown(); 42 | break; 43 | default: 44 | break; 45 | } 46 | return TRUE; 47 | } -------------------------------------------------------------------------------- /src/Installer/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "Installer.h" 23 | #include "Logger.h" -------------------------------------------------------------------------------- /vendor/bin2cpp/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Antoine Beauchamp 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 | -------------------------------------------------------------------------------- /vendor/bin2cpp/bin2cpp.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nats-ji/CET-Mod-Manager/7d85c841f5a199170ef972cec9b1aa2a2b062c35/vendor/bin2cpp/bin2cpp.exe -------------------------------------------------------------------------------- /xmake.lua: -------------------------------------------------------------------------------- 1 | set_languages("cxx20") 2 | set_arch("x64") 3 | add_rules("mode.debug", "mode.release") 4 | add_requires("spdlog 1.10.*", "nlohmann_json 3.11.*", "fmt 9.1.*") 5 | 6 | add_defines("RED4EXT_STATIC_LIB") 7 | 8 | target("RED4ext.SDK") 9 | set_default(false) 10 | set_kind("static") 11 | set_group("vendor") 12 | add_files("vendor/RED4ext.SDK/src/**.cpp") 13 | add_headerfiles("vendor/RED4ext.SDK/include/**.hpp") 14 | add_includedirs("vendor/RED4ext.SDK/include/", { public = true }) 15 | add_syslinks("User32") 16 | 17 | target("cet_mod_manager") 18 | set_default(false) 19 | set_kind("shared") 20 | set_filename("cet_mod_manager.dll") 21 | add_packages("spdlog", "nlohmann_json", "fmt") 22 | add_defines("UNICODE", "WIN32_LEAN_AND_MEAN") 23 | add_files("src/CETMM/**.cpp", "src/Common/**.cpp") 24 | add_headerfiles("src/CETMM/**.h", "src/Common/**.h") 25 | add_includedirs("src/CETMM/", "src/Common/") 26 | add_syslinks("Dwrite", "Shell32") 27 | add_deps("RED4ext.SDK") 28 | before_build(function () 29 | import("build") 30 | build.UpdateVersion() 31 | end) 32 | 33 | target("installer") 34 | set_kind("shared") 35 | set_filename("cet_mod_manager.asi") 36 | add_packages("spdlog", "nlohmann_json", "fmt") 37 | add_defines("UNICODE", "WIN32_LEAN_AND_MEAN") 38 | add_files("src/Installer/**.cpp", "src/Common/**.cpp") 39 | add_headerfiles("src/Installer/**.h", "src/Common/**.h") 40 | add_includedirs("src/Installer/", "src/Installer/embeds/lua/", "src/Installer/embeds/red4ext/", "src/Common/") 41 | add_syslinks("Shell32") 42 | on_package(function (target) 43 | import("build") 44 | build.Package(target) 45 | end) 46 | on_install(function () 47 | import("build") 48 | build.Install() 49 | end) 50 | after_clean(function () 51 | import("build") 52 | build.Clean() 53 | end) 54 | 55 | option("installpath") 56 | set_showmenu(true) 57 | set_description("Set the path to Cyberpunk 2077 root directory.", "e.g.", format("\t-xmake f --installpath=%s", [["C:\Program Files (x86)\Steam\steamapps\common\Cyberpunk 2077"]])) 58 | 59 | task("run") 60 | on_run(function () 61 | import("core.project.config") 62 | config.load() 63 | local install_path = config.get("installpath") 64 | print("Launching Cyberpunk 2077 ...") 65 | os.cd(path.join(install_path, "bin", "x64")) 66 | os.run("Cyberpunk2077.exe") 67 | end) 68 | set_menu { usage = "xmake run", description = "Launch Cyberpunk 2077"} 69 | 70 | task("embed") 71 | on_run(function () 72 | import("build") 73 | build.GenerateEmbeds() 74 | end) 75 | set_menu { usage = "xmake embed", description = "Generate embed files"} 76 | 77 | task("install-lua") 78 | on_run(function () 79 | import("build") 80 | build.InstallLua() 81 | end) 82 | set_menu { usage = "xmake install-lua", description = "Only Package and install CET Mod Manager Lua files"} 83 | 84 | task("install-ext") 85 | on_run(function () 86 | import("build") 87 | build.InstallExt() 88 | end) 89 | set_menu { usage = "xmake install-ext", description = "Only Package and install CET Mod Manager Red4ext plugin file"} 90 | 91 | task("build-all") 92 | on_run(function () 93 | import("build") 94 | build.BuildAll() 95 | end) 96 | set_menu { usage = "xmake build-all", description = "Build all targets."} 97 | 98 | task("update-ext") 99 | on_run(function () 100 | local rootDir = os.curdir() 101 | 102 | print("Pull RED4ext.SDK") 103 | os.cd("./vendor/RED4ext.SDK") 104 | os.execv("git", {"pull", "origin", "master"}) 105 | 106 | print("Commit changes") 107 | os.cd(rootDir) 108 | os.execv("git", {"add", "vendor/RED4ext.SDK"}) 109 | os.execv("git", {"commit", "-m", "Update RED4ext.SDK"}) 110 | end) 111 | set_menu { usage = "xmake update-ext", description = "Update RED4ext.SDK."} --------------------------------------------------------------------------------