├── .clang-format ├── .gitattributes ├── .github └── workflows │ ├── cmake-build.yml │ └── updateSDK.yml ├── .gitignore ├── .gitmodules ├── .idea └── cmake.xml ├── CMakeLists.txt ├── LINK.txt ├── README.md ├── changelog.md ├── create_release_note.py ├── fetchSDK.cmd ├── prepareLib.cmd └── src ├── BetterBDSMod.cpp ├── OptCommand.cpp ├── Plugin.cpp ├── config.json ├── dllmain.cpp ├── include ├── BetterBDSMod.h ├── Version.h ├── framework.h └── pch.h ├── opts ├── ActorOpt.cpp ├── EntitySystemOpt.cpp ├── HopperOpt.cpp ├── PistionOpt.cpp ├── RandomTickOpt.cpp └── RedstoneOpt.cpp ├── pch.cpp └── remotery ├── Remotery.c └── Remotery.h /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | BasedOnStyle: Google 3 | UseTab: Never 4 | IndentWidth: 4 5 | NamespaceIndentation: All 6 | ColumnLimit: 100 -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/workflows/cmake-build.yml: -------------------------------------------------------------------------------- 1 | name: Trapdoor Build 2 | on: [ push ] 3 | jobs: 4 | Build: 5 | runs-on: windows-latest 6 | steps: 7 | 8 | - name: checkout code 9 | uses: actions/checkout@v3 10 | 11 | - name: Pull submodule 12 | run: FetchSDK.cmd 13 | shell: cmd 14 | 15 | - name: Download Server 16 | run: | 17 | mkdir D:/BDS 18 | ServerLink=$(cat 'LINK.txt') 19 | curl -L -o D:/BDS/server.zip "$ServerLink" 20 | unzip D:/BDS/server.zip -d D:/BDS > /dev/null 21 | shell: bash 22 | 23 | - name: Build Bedrock Library 24 | run: | 25 | cd SDK/Tools 26 | LibraryBuilder.exe -o ..\Lib D:\BDS 27 | shell: cmd 28 | 29 | - name: Configure CMake 30 | run: cmake -B ${{github.workspace}}/build -DBETA=PFF -DDEV=OFF 31 | 32 | - name: Build 33 | run: cmake --build ${{github.workspace}}/build 34 | 35 | - name: Create Artifact 36 | run: | 37 | mkdir out 38 | mkdir out/plugins 39 | mkdir out/plugins/beopt 40 | cp ./build/Debug/beopt*.dll ./out/plugins/ 41 | cp ./build/Debug/beopt*.pdb ./out/plugins/ 42 | cp ./changelog.md ./out/ 43 | cp ./README.md ./out 44 | shell: bash 45 | 46 | - name: Upload Actions File 47 | uses: actions/upload-artifact@v1.0.0 48 | with: 49 | name: release 50 | path: ${{github.workspace}}/out 51 | 52 | #create release 53 | - name: Prepare Release 54 | run: | 55 | 7z a release.zip ${{github.workspace}}/out 56 | python create_release_note.py 57 | 58 | - name: Publish Release 59 | uses: softprops/action-gh-release@v1 60 | if: startsWith(github.ref, 'refs/tags/') 61 | with: 62 | body_path: ${{ github.workspace }}/release_note 63 | files: | 64 | release.zip 65 | env: 66 | GITHUB_REPOSITORY: hhhxiao/trapdoor-ll -------------------------------------------------------------------------------- /.github/workflows/updateSDK.yml: -------------------------------------------------------------------------------- 1 | name: Update SDK 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | workflow_dispatch: 7 | 8 | jobs: 9 | update: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | 14 | - name: Checkout 15 | uses: actions/checkout@v2.4.0 16 | 17 | - name: Update SDK 18 | run: git submodule update --init --recursive --remote 19 | 20 | - name: Push 21 | run: | 22 | git config --global user.name "github-actions[bot]" 23 | git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" 24 | git commit -am "fetch upstream SDK" || exit 0 25 | git push || exit 0 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vs/ 2 | **/x64/ 3 | **/*.user 4 | **/.vscode/ 5 | 6 | **/bedrock_server_api.lib 7 | **/bedrock_server_var.lib 8 | 9 | /.idea/* 10 | !/.idea/cmake.xml 11 | /cmake-build-* 12 | build/* 13 | /out/* 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "SDK"] 2 | path = SDK 3 | url = https://github.com/LiteLDev/SDK-cpp 4 | branch = main -------------------------------------------------------------------------------- /.idea/cmake.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | project(BedrockOptimizer) 3 | set(CMAKE_CXX_STANDARD 17) 4 | set(MOD_VERSION 0.4) 5 | set(TEST_NUMBER 12) 6 | set(GAME_VERSION 1.19.51.02) 7 | option(DEV "Build as developer version" ON) 8 | option(BETA "Build as beta version" OFF) 9 | add_definitions(-DMOD_VERSION="${MOD_VERSION}") 10 | add_definitions(-DMC_VERSION="${GAME_VERSION}") 11 | 12 | if (${DEV} STREQUAL "ON") 13 | add_definitions(-DDEV) 14 | message("Build a developer version") 15 | set(TARGET_NAME beopt-dev) 16 | else () 17 | message("Build a Player version") 18 | if (${BETA} STREQUAL "OFF") 19 | message("Build beta version") 20 | set(TARGET_NAME beopt-${MOD_VERSION}-${GAME_VERSION}-beta-${TEST_NUMBER}) 21 | else () 22 | message("build stable version") 23 | set(TARGET_NAME beopt-${MOD_VERSION}-${GAME_VERSION}) 24 | endif () 25 | endif () 26 | 27 | file( 28 | GLOB_RECURSE 29 | SRC_FILES_DIR 30 | ${PROJECT_SOURCE_DIR}/SDK/include/*.cpp 31 | ${PROJECT_SOURCE_DIR}/SDK/include/*.hpp 32 | ${PROJECT_SOURCE_DIR}/SDK/include/*.h 33 | src/dllmain.cpp 34 | src/pch.cpp 35 | src/Plugin.cpp 36 | src/OptCommand.cpp 37 | src/BetterBDSMod.cpp 38 | src/Config.cpp 39 | 40 | src/remotery/Remotery.c 41 | src/opts/RandomTickOpt.cpp 42 | src/opts/HopperOpt.cpp 43 | src/opts/ActorOpt.cpp 44 | src/opts/RedstoneOpt.cpp 45 | src/opts/EntitySystemOpt.cpp 46 | ) 47 | 48 | include_directories(SDK/include) 49 | include_directories(src/remotery) 50 | #include_directories(SDK/Header/third-party) 51 | include_directories(src/include) 52 | link_directories(.) 53 | 54 | add_definitions(-D"NDEBUG" -D"TEMPLATE_EXPORTS" -D"WIN32_LEAN_AND_MEAN" -D"_CRT_SECURE_NO_WARNINGS" -D"_WINDOWS" 55 | -D"_USRDLL" -D"_AMD64_" -D"NOMINMAX" -D"_WINDLL" -D"_UNICODE" -D"UNICODE") 56 | 57 | add_compile_options( 58 | /utf-8 59 | /permissive- /GS /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /sdl /Zc:inline /fp:precise /errorReport:prompt /WX- 60 | /Zc:forScope /Gd /Oi /MD /std:c++17 /FC /EHsc /nologo /diagnostics:column 61 | ) 62 | 63 | add_link_options( 64 | /DELAYLOAD:bedrock_server.dll 65 | /MANIFEST /LTCG:incremental /NXCOMPAT /DEBUG /DLL /MACHINE:X64 /OPT:REF /INCREMENTAL:NO /SUBSYSTEM:WINDOWS 66 | /MANIFESTUAC:NO /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1 67 | ) 68 | 69 | add_library(${TARGET_NAME} SHARED ${SRC_FILES_DIR}) 70 | 71 | add_custom_command(TARGET ${TARGET_NAME} PRE_BUILD 72 | COMMAND cmd /c ${PROJECT_SOURCE_DIR}/prepareLib.cmd ${PROJECT_SOURCE_DIR} 73 | COMMENT "Preparing Library" 74 | ) 75 | -------------------------------------------------------------------------------- /LINK.txt: -------------------------------------------------------------------------------- 1 | https://minecraft.azureedge.net/bin-win/bedrock-server-1.19.50.02.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BedrockOptimizer (temporary name) 2 | 3 | BedrockOptimizer ia a BDS mod based on LiteLoaderBDS, which works to reduce mspt without modify vanilla features. 4 | 5 | :warning: **This is just an early demo, there are may exist many imperfections, please use it with caution.** 6 | 7 | # others 8 | 9 | Try my another DBS mod [Trapdoor](https://github.com/hhhxiao/trapdoor-ll/) 10 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | ### v0.2.7 2 | 3 | **注意这是个早期版本,难免出现bug,请谨慎使用** 4 | 5 | #### 依赖和版本支持 6 | 7 | - 需要LiteLoader 2.9.0 或以上版本 8 | - 理论上支持1.19.51.02及以上版本 9 | 10 | #### 更新日志 11 | 12 | - 支持1.19.51.02 13 | 14 | 15 | ### v0.2.6 16 | 17 | **注意这是个早期版本,难免出现bug,请谨慎使用** 18 | 19 | #### 依赖和版本支持 20 | 21 | - 需要LiteLoader 2.7.2 或以上版本 22 | - 理论上支持1.19.30.04及以上版本 23 | 24 | #### 更新日志 25 | 26 | - 支持1.19.30.04和1.19.31.01 27 | 28 | ### v0.2.5 29 | 30 | **注意这是个早期版本,难免出现bug,请谨慎使用** 31 | 32 | #### 依赖和版本支持 33 | 34 | - 需要LiteLoader 2.6.1 或以上版本 35 | - 理论上支持1.19.22.01及以上版本 36 | 37 | #### 更新日志 38 | 39 | - 修复红石优化导致的一个闪退bug (#4) 40 | 41 | ### v0.2 42 | 43 | **注意这是个早期版本,难免出现bug,请谨慎使用** 44 | 45 | #### 依赖和版本支持 46 | 47 | - 需要LiteLoader 2.5.0 或以上版本 48 | - 理论上支持1.19.20.02及以上版本 49 | 50 | #### 更新日志 51 | 52 | - 修复漏斗无法吸收上方矿车内物品的bug 53 | - 优化容器满箱检测性能 54 | -------------------------------------------------------------------------------- /create_release_note.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | total = '' 3 | with open('changelog.md', encoding='utf-8') as f: 4 | total = f.readlines() 5 | content = '' 6 | index = 0 7 | for x in total: 8 | x = x.strip() 9 | if len(x) != 0: 10 | tokens = x.split(' ') 11 | if tokens[0] == '###': 12 | index += 1 13 | if index == 2: 14 | break 15 | content += x + '\n' 16 | with open('release_note', "w", encoding="utf-8") as f: 17 | f.write(content) 18 | -------------------------------------------------------------------------------- /fetchSDK.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal enabledelayedexpansion 3 | 4 | rem Process System Proxy 5 | for /f "tokens=3* delims= " %%i in ('Reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnable') do ( 6 | if %%i==0x1 ( 7 | echo [INFO] System Proxy enabled. Adapting Settings... 8 | for /f "tokens=3* delims= " %%a in ('Reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyServer') do set PROXY_ADDR=%%a 9 | set http_proxy=http://!PROXY_ADDR! 10 | set https_proxy=http://!PROXY_ADDR! 11 | echo [INFO] System Proxy enabled. Adapting Settings finished. 12 | echo. 13 | ) 14 | ) 15 | 16 | git submodule update --init --recursive 17 | 18 | echo. 19 | echo [INFO] Upgrading LiteLoaderSDK from GitHub finished. 20 | 21 | pause -------------------------------------------------------------------------------- /prepareLib.cmd: -------------------------------------------------------------------------------- 1 | if not exist %1\SDK\Lib\bedrock_server_api.lib goto process 2 | if not exist %1\SDK\Lib\bedrock_server_var.lib goto process 3 | goto end 4 | 5 | :process 6 | cd /d %1\SDK\Tools\ 7 | LibraryBuilder.exe -o ..\Lib\ 8 | :end 9 | -------------------------------------------------------------------------------- /src/BetterBDSMod.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2022/7/14. 3 | // 4 | 5 | #include "BetterBDSMod.h" 6 | 7 | #include 8 | 9 | #include "Nlohmann/json.hpp" 10 | namespace trapdoor { 11 | 12 | namespace { 13 | void tryCreateConfig() { 14 | namespace fs = std::filesystem; 15 | if (!fs::exists("./plugins/beopt")) { 16 | trapdoor::logger().warn( 17 | "Can not find config file, Automatically generating configuration files"); 18 | fs::create_directory("./plugins/beopt"); 19 | const std::string cfg = R"( 20 | { 21 | "random-tick": true, 22 | "actor-push": true, 23 | "component-remove": true, 24 | "hopper": false 25 | } 26 | )"; 27 | std::ofstream f("./plugins/beopt/config.json"); 28 | f << cfg; 29 | f.close(); 30 | } 31 | } 32 | } // namespace 33 | 34 | Logger& logger() { 35 | static Logger logger("BedrockOptimizer"); 36 | return logger; 37 | } 38 | 39 | void init() { 40 | logger().consoleLevel = 8; 41 | registerOptCommand(1); 42 | tryCreateConfig(); 43 | trapdoor::mod().readConfig(); 44 | } 45 | 46 | BetterBDSMod& mod() { 47 | static BetterBDSMod mod; 48 | return mod; 49 | } 50 | 51 | void BetterBDSMod::readConfig() { 52 | nlohmann::json config; 53 | const std::string path = "./plugins/beopt/config.json"; 54 | try { 55 | std::ifstream i(path); 56 | i >> config; 57 | this->randomTick = config["random-tick"].get(); 58 | this->actorPush = config["actor-push"].get(); 59 | this->hopper = config["hopper"].get(); 60 | this->componentRemove = config["component-remove"].get(); 61 | 62 | trapdoor::logger().info("Read getConfig file {} successfully", path); 63 | } catch (std::exception&) { 64 | trapdoor::logger().error( 65 | "Can't read configuration file: {},Opts will be disable, use [opt] command to " 66 | "enable them", 67 | path); 68 | } 69 | this->dumpConfig(); 70 | } 71 | 72 | void BetterBDSMod::dumpConfig() const { 73 | trapdoor::logger().info("[Random tick]: {}", this->randomTick); 74 | trapdoor::logger().info("[Actor push]: {}", this->actorPush); 75 | trapdoor::logger().info("[Component Remove]: {}", this->componentRemove); 76 | trapdoor::logger().info("[Hopper]: {}", this->hopper); 77 | } 78 | } // namespace trapdoor 79 | -------------------------------------------------------------------------------- /src/OptCommand.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2022/7/14. 3 | // 4 | 5 | #include "BetterBDSMod.h" 6 | #include "llapi/DynamicCommandAPI.h" 7 | 8 | namespace trapdoor { 9 | 10 | void setValue(const std::string &name, bool &item, bool val, CommandOutput &output) { 11 | // trapdoor::logger().debug("QAQ"); 12 | item = val; 13 | auto msg = "Set " + name + " to " + std::to_string(item); 14 | output.success(msg); 15 | } 16 | 17 | void queryValue(const std::string &name, bool item, CommandOutput &output) { 18 | auto msg = name + " is set to " + std::to_string(item); 19 | output.success(msg); 20 | } 21 | 22 | void registerOptCommand(int level) { 23 | using ParamType = DynamicCommand::ParameterType; 24 | auto command = DynamicCommand::createCommand("opt", "opt options", 25 | static_cast(level)); 26 | 27 | auto &redstoneEnum = command->setEnum("redstone", {"compremove"}); 28 | command->mandatory("opt", ParamType::Enum, redstoneEnum, 29 | CommandParameterOption::EnumAutocompleteExpansion); 30 | 31 | auto &actorEnum = command->setEnum("actor", {"actorpush"}); 32 | command->mandatory("opt", ParamType::Enum, actorEnum, 33 | CommandParameterOption::EnumAutocompleteExpansion); 34 | 35 | auto &hopperEnum = command->setEnum("hopper", {"hopper"}); 36 | command->mandatory("opt", ParamType::Enum, hopperEnum, 37 | CommandParameterOption::EnumAutocompleteExpansion); 38 | 39 | auto &randomTickEnum = command->setEnum("randomtick", {"randomtick"}); 40 | command->mandatory("opt", ParamType::Enum, randomTickEnum, 41 | CommandParameterOption::EnumAutocompleteExpansion); 42 | 43 | command->optional("onoroff", ParamType::Bool); 44 | command->addOverload({redstoneEnum, "onoroff"}); 45 | command->addOverload({actorEnum, "onoroff"}); 46 | command->addOverload({hopperEnum, "onoroff"}); 47 | command->addOverload({randomTickEnum, "onoroff"}); 48 | 49 | auto cb = [](DynamicCommand const &command, CommandOrigin const &origin, 50 | CommandOutput &output, 51 | std::unordered_map &results) { 52 | bool query = !results["onoroff"].isSet; 53 | auto opt = !query && results["onoroff"].get(); 54 | switch (do_hash(results["opt"].getRaw().c_str())) { 55 | case do_hash("compremove"): 56 | if (query) { 57 | queryValue("componentRemove", trapdoor::mod().componentRemove, output); 58 | } else { 59 | setValue("componentRemove", trapdoor::mod().componentRemove, opt, output); 60 | } 61 | break; 62 | case do_hash("actorpush"): 63 | if (query) { 64 | queryValue("actorpush", trapdoor::mod().actorPush, output); 65 | } else { 66 | setValue("actorpush", trapdoor::mod().actorPush, opt, output); 67 | } 68 | break; 69 | case do_hash("hopper"): 70 | if (query) { 71 | queryValue("hopper", trapdoor::mod().hopper, output); 72 | } else { 73 | setValue("hopper", trapdoor::mod().hopper, opt, output); 74 | } 75 | break; 76 | case do_hash("randomtick"): 77 | if (query) { 78 | queryValue("randomtick", trapdoor::mod().randomTick, output); 79 | } else { 80 | setValue("randomtick", trapdoor::mod().randomTick, opt, output); 81 | } 82 | break; 83 | } 84 | }; 85 | 86 | command->setCallback(cb); 87 | DynamicCommand::setup(std::move(command)); 88 | } 89 | // namespace tr 90 | } // namespace trapdoor -------------------------------------------------------------------------------- /src/Plugin.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "BetterBDSMod.h" 3 | #include "Remotery.h" 4 | #include "Version.h" 5 | #include "pch.h" 6 | inline void CheckProtocolVersion() { 7 | #ifdef TARGET_BDS_PROTOCOL_VERSION 8 | auto currentProtocol = LL::getServerProtocolVersion(); 9 | if (TARGET_BDS_PROTOCOL_VERSION != currentProtocol) { 10 | logger.warn("Protocol version not match, target version: {}, current version: {}.", 11 | TARGET_BDS_PROTOCOL_VERSION, currentProtocol); 12 | logger.warn( 13 | "This will most likely crash the server, please use the Plugin that matches the BDS " 14 | "version!"); 15 | } 16 | #endif // TARGET_BDS_PROTOCOL_VERSION 17 | } 18 | 19 | void initRMT() { 20 | Remotery* rmt; 21 | rmt_CreateGlobalInstance(&rmt); 22 | } 23 | 24 | void PluginInit() { 25 | initRMT(); 26 | CheckProtocolVersion(); 27 | trapdoor::init(); 28 | } 29 | -------------------------------------------------------------------------------- /src/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "random-tick": true, 3 | "actor-push": true, 4 | "component-remove": true, 5 | "hopper": false 6 | } -------------------------------------------------------------------------------- /src/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : 定义 DLL 应用程序的入口点。 2 | #include "pch.h" 3 | #include 4 | #include "Version.h" 5 | #pragma comment(lib, "../SDK/Lib/bedrock_server_api.lib") 6 | #pragma comment(lib, "../SDK/Lib/bedrock_server_var.lib") 7 | #pragma comment(lib, "../SDK/Lib/SymDBHelper.lib") 8 | #pragma comment(lib, "../SDK/Lib/LiteLoader.lib") 9 | 10 | BOOL APIENTRY DllMain( HMODULE hModule, 11 | DWORD ul_reason_for_call, 12 | LPVOID lpReserved 13 | ) 14 | { 15 | switch (ul_reason_for_call) 16 | { 17 | case DLL_PROCESS_ATTACH: 18 | ll::registerPlugin( 19 | PLUGIN_NAME, 20 | PLUGIN_INTRODUCTION, 21 | ll::Version(PLUGIN_VERSION_MAJOR, PLUGIN_VERSION_MINOR, PLUGIN_VERSION_REVISION, PLUGIN_LLVERSION_STATUS), 22 | std::map{ 23 | {"Author", PLUGIN_AUTHOR}, 24 | } 25 | ); 26 | break; 27 | case DLL_THREAD_ATTACH: 28 | case DLL_THREAD_DETACH: 29 | case DLL_PROCESS_DETACH: 30 | break; 31 | } 32 | return TRUE; 33 | } 34 | 35 | void PluginInit(); 36 | 37 | extern "C" { 38 | // Do something after all the plugins loaded 39 | _declspec(dllexport) void onPostInit() { 40 | std::ios::sync_with_stdio(false); 41 | PluginInit(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/include/BetterBDSMod.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2022/7/14. 3 | // 4 | 5 | #ifndef BETTERBDS_BETTERBDSMOD_H 6 | #define BETTERBDS_BETTERBDSMOD_H 7 | #include "llapi/LoggerAPI.h" 8 | 9 | namespace trapdoor { 10 | 11 | void registerOptCommand(int level); 12 | 13 | class BetterBDSMod { 14 | public: 15 | bool componentRemove = false; 16 | bool actorPush = false; 17 | bool hopper = false; 18 | bool randomTick = false; 19 | void readConfig(); 20 | void dumpConfig() const; 21 | }; 22 | 23 | BetterBDSMod &mod(); 24 | Logger &logger(); 25 | void init(); 26 | } // namespace trapdoor 27 | #endif // BETTERBDS_BETTERBDSMOD_H -------------------------------------------------------------------------------- /src/include/Version.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define PLUGIN_VERSION_DEV 0 4 | #define PLUGIN_VERSION_BETA 1 5 | #define PLUGIN_VERSION_RELEASE 2 6 | 7 | // Plugin Information, used in dllmain.cpp for register plugin 8 | #define PLUGIN_NAME "BetterBDS" 9 | #define PLUGIN_INTRODUCTION "Optimize BDS code to reduce mspt" 10 | #define PLUGIN_AUTHOR "hhhxiao" 11 | #define PLUGIN_VERSION_MAJOR 0 12 | #define PLUGIN_VERSION_MINOR 2 13 | #define PLUGIN_VERSION_REVISION 6 14 | #define PLUGIN_VERSION_BUILD 0 15 | #define PLUGIN_VERSION_STATUS PLUGIN_VERSION_DEV 16 | 17 | //#define TARGET_BDS_PROTOCOL_VERSION 503 18 | // used by github actions(TODO) 19 | //#define TARGET_BDS_VERSION 1.18.30.04 20 | 21 | // File Version Information, used in Resource.rc 22 | #define __TO_VERSION_STRING(ver) #ver 23 | #define TO_VERSION_STRING(ver) __TO_VERSION_STRING(ver) 24 | 25 | #if PLUGIN_VERSION_STATUS == PLUGIN_VERSION_BETA 26 | #define PLUGIN_FILE_VERSION_FLAG VS_FF_DEBUG 27 | #define PLUGIN_LLVERSION_STATUS LL::Version::Beta 28 | #define PLUGIN_FILE_VERSION_STRING \ 29 | TO_VERSION_STRING(PLUGIN_VERSION_MAJOR.PLUGIN_VERSION_MINOR.PLUGIN_VERSION_REVISION \ 30 | .PLUGIN_VERSION_ACTIONS BETA) 31 | #elif PLUGIN_VERSION_STATUS == PLUGIN_VERSION_DEV 32 | #define PLUGIN_FILE_VERSION_FLAG VS_FF_DEBUG 33 | #define PLUGIN_LLVERSION_STATUS ll::Version::Dev 34 | #define PLUGIN_FILE_VERSION_STRING \ 35 | TO_VERSION_STRING(PLUGIN_VERSION_MAJOR.PLUGIN_VERSION_MINOR.PLUGIN_VERSION_REVISION \ 36 | .PLUGIN_VERSION_ACTIONS DEV) 37 | #else 38 | #define PLUGIN_FILE_VERSION_FLAG 0x0L 39 | #define PLUGIN_LLVERSION_STATUS LL::Version::Release 40 | #define PLUGIN_FILE_VERSION_STRING \ 41 | TO_VERSION_STRING( \ 42 | PLUGIN_VERSION_MAJOR.PLUGIN_VERSION_MINOR.PLUGIN_VERSION_REVISION.PLUGIN_VERSION_ACTIONS) 43 | #endif 44 | 45 | #define FILE_VERSION_BLOCK_HEADER 0x04004B0L 46 | #define FILE_VERSION_COMPANY_NAME PLUGIN_AUTHOR 47 | #define FILE_VERSION_LEGAL_COPYRIGHT "Copyright (C) 2022" 48 | #define FILE_VERSION_FILE_DESCRIPTION PLUGIN_INTRODUCTION 49 | #define FILE_VERSION_FILE_VERSION_STRING PLUGIN_FILE_VERSION_STRING 50 | #define FILE_VERSION_INTERNAL_NAME PLUGIN_NAME 51 | #define FILE_VERSION_ORIGINAL_FILENAME PLUGIN_NAME ".dll" 52 | #define FILE_VERSION_PRODUCT_NAME FILE_VERSION_INTERNAL_NAME 53 | #define FILE_VERSION_PRODUCT_VERSION_STRING PLUGIN_FILE_VERSION_STRING 54 | #define FILE_VERSION_FILE_VERSION \ 55 | PLUGIN_VERSION_MAJOR, PLUGIN_VERSION_MINOR, PLUGIN_VERSION_REVISION, PLUGIN_VERSION_BUILD 56 | #define FILE_VERSION_PRODUCT_VERSION FILE_VERSION_FILE_VERSION 57 | -------------------------------------------------------------------------------- /src/include/framework.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容 4 | // Windows 头文件 5 | #include 6 | -------------------------------------------------------------------------------- /src/include/pch.h: -------------------------------------------------------------------------------- 1 | // pch.h: 这是预编译标头文件。 2 | // 下方列出的文件仅编译一次,提高了将来生成的生成性能。 3 | // 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。 4 | // 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。 5 | // 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。 6 | 7 | #ifndef PCH_H 8 | #define PCH_H 9 | 10 | // 添加要在此处预编译的标头 11 | #include 12 | #include 13 | 14 | #endif //PCH_H -------------------------------------------------------------------------------- /src/opts/ActorOpt.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2022/7/17. 3 | // 4 | #include 5 | 6 | #include "BetterBDSMod.h" 7 | #include "llapi/HookAPI.h" 8 | #include "Remotery.h" 9 | 10 | THook(void, "?push@PushableComponent@@QEAAXAEAVActor@@AEBVVec3@@@Z", void *comp, void *a1, 11 | const Vec3 &v) { 12 | if (!trapdoor::mod().actorPush) { 13 | original(comp, a1, v); 14 | return; 15 | } 16 | if (v != Vec3::ZERO) { 17 | original(comp, a1, v); 18 | } 19 | } 20 | 21 | // THook(__int64, "_ZN5Actor4tickER11BlockSource", Actor *self, BlockSource *a2) { 22 | // return original(self, a2); 23 | // } 24 | 25 | // THook(void, "?tick@Actor@@QEAA_NAEAVBlockSource@@@Z", Actor *actor, void *bs) { 26 | // rmt_ScopedCPUSample(ActorTick, 0); 27 | // original(actor, bs); 28 | // } 29 | // 30 | // THook(void, "?tick@ActorLegacyTickSystem@@UEAAXAEAVEntityRegistry@@@Z", void *self, void *a) { 31 | // rmt_ScopedCPUSample(ActorLegacySystem, 0); 32 | // original(self, a); 33 | // } 34 | // 35 | // THook(void, 36 | // "?tick@PredictedMovementComponent@@QEAAXAEBV?$time_point@Usteady_clock@chrono@std@@V?$" 37 | // "duration@_JU?$ratio@$00$0DLJKMKAA@@std@@@23@@chrono@std@@@Z", 38 | // void *s, void *a) { 39 | // rmt_ScopedCPUSample(PredictedMovementComponentTick, 0); 40 | // original(s, a); 41 | // } 42 | // THook(void, "?refreshComponents@Actor@@QEAAXXZ", void *s) { 43 | // rmt_ScopedCPUSample(ActorRefreshComponents, 0); 44 | // original(s); 45 | // } 46 | 47 | // THook(void, "?updateTickingData@Actor@@QEAAXXZ", void *s) { 48 | // rmt_ScopedCPUSample(ActorupdateTickingData, 0); 49 | // original(s); 50 | // } 51 | // THook(void, "?baseTick@Mob@@UEAAXXZ", void *s) { 52 | // rmt_ScopedCPUSample(MobBaseTick, 0); 53 | // original(s); 54 | //} 55 | // THook(void, "?aiStep@Mob@@UEAAXXZ", void *s) { 56 | // rmt_ScopedCPUSample(AI, 0); 57 | // original(s); 58 | //} 59 | // THook(void, "?_aiStep@Mob@@SAXAEAUIMobMovementProxy@@@Z", void *s, void *p) { 60 | // rmt_ScopedCPUSample(InnerAI, 0); 61 | // original(s, p); 62 | //} 63 | // THook(void, "?normalTick@Mob@@UEAAXXZ", void *s) { 64 | // rmt_ScopedCPUSample(MobNormalTick, 0); 65 | // original(s); 66 | //} 67 | 68 | // THook(void, "?_updateMobTravel@Mob@@SAXAEAUIMobMovementProxy@@@Z", void *self, void *p) { 69 | // rmt_ScopedCPUSample(UpdateMobTravel, 0); 70 | // original(self, p); 71 | // } 72 | 73 | // THook(void, "?normalTick@Actor@@UEAAXXZ", void *s) { 74 | // rmt_ScopedCPUSample(ActorNormalTick, 0); 75 | // original(s); 76 | // } 77 | // 78 | // THook(void, "?baseTick@Actor@@UEAAXXZ", void *s) { 79 | // rmt_ScopedCPUSample(ActorBaseTick, 0); 80 | // original(s); 81 | // } 82 | // THook(void, "?pushActors@Mob@@UEAAXXZ", void *s) { 83 | // rmt_ScopedCPUSample(MobPushActors, 0); 84 | // original(s); 85 | // } 86 | 87 | // THook(bool, "?canExistWhenDisallowMob@Mob@@UEBA_NXZ", void *s) { 88 | // rmt_ScopedCPUSample(MobPushActors, 0); 89 | // return original(s); 90 | // } 91 | 92 | // THook(int, "?update@CompassSpriteCalculator@@QEAAHAEAVActor@@_N@Z", void *s, void *a1, void *a2) 93 | // { 94 | // rmt_ScopedCPUSample(CompassSpriteUpdate, 0); 95 | // auto v = original(s, a1, a2); 96 | // return v; 97 | // } 98 | // THook(int, "?update@ClockSpriteCalculator@@QEAAHAEAVActor@@_N@Z", void *s, void *a1, void *a2) { 99 | // rmt_ScopedCPUSample(CompassSpriteUpdate, 0); 100 | // auto v = original(s, a1, a2); 101 | // return v; 102 | // } 103 | // THook(int, "?canBeginOrContinueClimbingLadder@Actor@@SA_NAEBUIActorMovementProxy@@@Z", void *s, 104 | // void *a1) { 105 | // rmt_ScopedCPUSample(ClimbingLadder, 0); 106 | // auto v = original(s, a1); 107 | // return v; 108 | // } 109 | // THook(void *, 110 | // "?fetchEntities@BlockSource@@UEAA?AV?$span@V?$not_null@PEAVActor@@@gsl@@$0?0@gsl@@" 111 | // "W4ActorType@@AEBVAABB@@PEBVActor@@@Z", 112 | // void *bs, int64_t type, void *a, void *b) { 113 | // rmt_ScopedCPUSample(FetchEntities, 0); 114 | // return original(bs, type, a, b); 115 | // } 116 | 117 | // THook(void *, "?getGameRules@Level@@UEAAAEAVGameRules@@XZ", void *l) { 118 | // rmt_ScopedCPUSample(LevelGetGameRule, 0); 119 | // return original(l); 120 | // } 121 | // THook(void, "?_playMovementSound@Actor@@IEAAX_N@", void *actor, bool c) { 122 | // if (!trapdoor::mod().componentRemove) { 123 | // original(actor, c); 124 | // } 125 | 126 | // } -------------------------------------------------------------------------------- /src/opts/EntitySystemOpt.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2022/7/25. 3 | // 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "llapi/HookAPI.h" 11 | using std::chrono::duration; 12 | using std::chrono::duration_cast; 13 | using std::chrono::high_resolution_clock; 14 | using std::chrono::milliseconds; 15 | 16 | // FILE *profile = nullptr; 17 | // #include 18 | // 19 | // THook(void, 20 | // "?_tickLevelChunksAroundActor@LevelChunkTickingSystem@@CAXAEAVActor@@AEAVBlockSource@@" 21 | // "AEAVLoadedChunksComponent@@@Z", 22 | // Actor *actor, void *region, void *loadedChunksComponent) { 23 | // // trapdoor::logger().debug("{} {} {}", actor == nullptr, region == nullptr, 24 | // // loadedChunksComponent == nullptr); 25 | // // if (actor) { 26 | // // trapdoor::logger().debug("actor type is {}", actor->getTypeName()); 27 | // // } 28 | // // 29 | // 30 | // // trapdoor::logger().debug("Around actor {}", region); 31 | // original(actor, region, loadedChunksComponent); 32 | // } 33 | // 34 | //// MCAPI class BlockPos const getTopRainBlockPos(class ChunkBlockPos const &); 35 | // 36 | // THook(BlockPos, "?getTopRainBlockPos@LevelChunk@@QEAA?BVBlockPos@@AEBVChunkBlockPos@@@Z", 37 | // void *chunk, const ChunkBlockPos &cp) { 38 | // auto r = original(chunk, cp); 39 | // printf("%d %d %d\n", r.x, r.y, r.z); 40 | // return r; 41 | //} 42 | -------------------------------------------------------------------------------- /src/opts/HopperOpt.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2022/8/8. 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "BetterBDSMod.h" 16 | #include "llapi/HookAPI.h" 17 | 18 | struct HopperCache { 19 | uint8_t valid : 8; 20 | uint8_t empty : 4; 21 | uint8_t full : 4; 22 | }; 23 | 24 | struct THopper { 25 | int mCooldownTime = -1; 26 | bool mTransferedFromChestMinecart = false; 27 | bool mIsEntity = false; 28 | HopperCache cache{}; 29 | int mMoveItemSpeed = 4; 30 | }; 31 | 32 | static_assert(sizeof(HopperCache) == 2); 33 | static_assert(sizeof(THopper) == 12); 34 | 35 | namespace { 36 | 37 | void refreshHopperCache(Container &cont, THopper *hopper) { 38 | uint8_t emptySlot = 0; 39 | uint8_t fullSlot = 0; 40 | for (int i = 0; i < 5; i++) { 41 | auto &item = cont.getItem(i); 42 | if (item.getId() == 0) { 43 | emptySlot++; 44 | } else if (item.getCount() >= item.getMaxStackSize()) { 45 | fullSlot++; 46 | } 47 | } 48 | hopper->cache.empty = emptySlot; 49 | hopper->cache.full = fullSlot; 50 | } 51 | 52 | bool tryPullInItemsFromWorld(Hopper *hopper, BlockSource &bs, Container &cont, 53 | const Vec3 &vec) { 54 | auto *itemActor = hopper->_getItemAt(bs, vec + Vec3(0.0f, 0.625f, 0.0f)); 55 | return itemActor && hopper->_addItem(cont, *itemActor); 56 | } 57 | 58 | bool HopperAction(Hopper *self, const HopperCache &cache, bool canPushItems, BlockSource &bs, 59 | Container &cont, const Vec3 &v, bool above, int face) { 60 | auto changed = false; 61 | auto th = reinterpret_cast(self); 62 | // 有物品且对着容器就往下送物品 63 | if (canPushItems && cache.empty < 5) { 64 | changed = self->_pushOutItems(bs, cont, v, face); 65 | } 66 | 67 | th->mTransferedFromChestMinecart = false; 68 | // 漏斗是满的的就直接返回 69 | if (cache.full == 5) { 70 | return changed; 71 | } 72 | 73 | auto c1 = self->_tryPullInItemsFromAboveContainer(bs, cont, v); 74 | auto c2 = !above && tryPullInItemsFromWorld(self, bs, cont, v); 75 | return c1 || c2 || changed; 76 | } 77 | } // namespace 78 | 79 | THook(void, "?setItem@HopperBlockActor@@UEAAXHAEBVItemStack@@@Z", void *self, unsigned int index, 80 | ItemStackBase *itemStack) { 81 | auto &ba = dAccess(self); 82 | auto &hp = dAccess(&ba); 83 | reinterpret_cast(&hp)->cache.valid = 0; 84 | original(self, index, itemStack); 85 | } 86 | 87 | THook(bool, "?_tryMoveItems@Hopper@@IEAA_NAEAVBlockSource@@AEAVContainer@@AEBVVec3@@H_N@Z", 88 | Hopper *self, BlockSource &bs, Container &fromContainer, Vec3 const &v, int attachedFace, 89 | bool canPushItems) { 90 | auto *tHopper = reinterpret_cast(self); 91 | // 漏斗矿车直接返回 92 | if (tHopper->mIsEntity) return original(self, bs, fromContainer, v, attachedFace, canPushItems); 93 | 94 | auto hma = trapdoor::mod().hopper; 95 | if (!hma) { 96 | return original(self, bs, fromContainer, v, attachedFace, canPushItems); 97 | } 98 | 99 | auto pos = v.toBlockPos(); 100 | auto aboveBlockPos = pos + BlockPos(0, 1, 0); 101 | auto &aboveBlock = bs.getBlock(aboveBlockPos); 102 | bool aboveIsContainer = aboveBlock.isContainerBlock(); 103 | bool change = false; 104 | if (!tHopper->cache.valid) { 105 | refreshHopperCache(fromContainer, tHopper); 106 | tHopper->cache.valid = true; 107 | } 108 | change = HopperAction(self, tHopper->cache, canPushItems, bs, fromContainer, v, 109 | aboveIsContainer, attachedFace); 110 | if (change) { 111 | tHopper->mCooldownTime = tHopper->mMoveItemSpeed; 112 | } 113 | return change; 114 | } 115 | 116 | // Container 117 | 118 | THook(bool, "?_isFullContainer@Hopper@@IEAA_NAEAVContainer@@H@Z", Hopper *hopper, 119 | Container &self, int face) { 120 | auto hma = trapdoor::mod().hopper; 121 | if (!hma) { 122 | return original(hopper, self, face); 123 | } 124 | 125 | auto &cache = dAccess(&self); 126 | if (cache.size() == 4 && cache[2] == 1) { // full cache有效 127 | return cache[3] != 0; 128 | } else { // cache失效, 刷新cache 129 | auto full = original(hopper, self, face); 130 | if (cache.size() != 4) cache = std::string(4, 0); // 创建cache 131 | cache[2] = 1; 132 | cache[3] = full ? 1 : 0; 133 | return full; 134 | } 135 | } 136 | 137 | THook(bool, "?_isEmptyContainer@Hopper@@IEAA_NAEAVContainer@@H@Z", Hopper *self, Container &c) { 138 | auto hma = trapdoor::mod().hopper; 139 | if (!hma) { 140 | return original(self, c); 141 | } 142 | return c.isEmpty(); 143 | } 144 | 145 | THook(bool, "?isEmpty@Container@@UEBA_NXZ", Container *self) { 146 | auto hma = trapdoor::mod().hopper; 147 | if (!hma) { 148 | return original(self); 149 | } 150 | 151 | auto &cache = dAccess(self); 152 | if (cache.size() == 4 && cache[0] == 1) { // cache有效 153 | return cache[1] != 0; 154 | } else { // cache失效, 刷新cache 155 | auto isEmpty = original(self); 156 | if (cache.size() != 4) cache = std::string(4, 0); // 刷新cache 157 | cache[0] = 1; 158 | cache[1] = isEmpty ? 1 : 0; 159 | return isEmpty; 160 | } 161 | } 162 | 163 | THook(void, "?setContainerChanged@Container@@UEAAXH@Z", Container *self, unsigned int a2) { 164 | // 让cache失效 165 | auto hma = trapdoor::mod().hopper; 166 | if (!hma) { 167 | original(self, a2); 168 | return; 169 | } 170 | // 0 empty valid 171 | // 1 empty 172 | // 2 full valid 173 | // 3 full 174 | 175 | auto &cache = dAccess(self); 176 | if (cache.size() != 4) cache = std::string(4, 0); // 创建cache 177 | cache[0] = cache[2] = 0; // 设置失效 178 | original(self, a2); 179 | } -------------------------------------------------------------------------------- /src/opts/PistionOpt.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2022/8/27. 3 | // 4 | -------------------------------------------------------------------------------- /src/opts/RandomTickOpt.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2022/8/16. 3 | // 4 | #include 5 | 6 | #include "BetterBDSMod.h" 7 | #include "llapi/HookAPI.h" 8 | 9 | // THook(uint64_t, "?getHighestNonAirSubChunkIndex@LevelChunk@@QEBAFXZ", void *chunk) { 10 | // // auto r = original(chunk); 11 | // // trapdoor::logger().debug("res is {}", r); 12 | // // return r; 13 | // if (trapdoor::mod().actorPush) { 14 | // return 3; 15 | // } else { 16 | // return original(chunk); 17 | // } 18 | // } 19 | 20 | THook(bool, "?shouldRandomTick@Block@@QEBA_NXZ", Block *block) { 21 | if (!trapdoor::mod().randomTick) { 22 | return original(block); 23 | } 24 | 25 | auto id = block->getId(); 26 | /* 27 | * -378 => minecraft:deepslate 28 | * 0 => minecraft:air 29 | * 1 => minecraft:stone 30 | * 3 => minecraft:dirt 31 | * 9 => minecraft:water 32 | * 87 => minecraft:netherrack 33 | * 34 | */ 35 | 36 | if (id == -378 || id == 0 || id == 1 || id == 3 || id == 9 || id == 87) return false; 37 | return original(block); 38 | } 39 | -------------------------------------------------------------------------------- /src/opts/RedstoneOpt.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2022/7/14. 3 | // 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "BetterBDSMod.h" 13 | #include "llapi/Global.h" 14 | #include "Remotery.h" 15 | 16 | struct ComponentItem { 17 | BaseCircuitComponent *mComponent = nullptr; // 0 * 4 - 1 * 4 18 | int mDampening = 0; // 2 * 4 19 | BlockPos mPos; // 3 * 4 - 5 * 4 20 | unsigned char facing{}; // 6 * 4 21 | bool mDirectlyPowered = false; // 6* 4 22 | int mData = 0; // 7*4 23 | }; 24 | 25 | std::vector getBlockPosNeighbors(const BlockPos &p) { 26 | return {{p.x + 1, p.y, p.z}, {p.x - 1, p.y, p.z}, {p.x, p.y + 1, p.z}, 27 | {p.x, p.y - 1, p.z}, {p.x, p.y, p.z + 1}, {p.x, p.y, p.z - 1}}; 28 | } 29 | 30 | BlockPos toChunkPos(const BlockPos &p) { 31 | auto cx = p.x < 0 ? p.x - 15 : p.x; 32 | auto cz = p.z < 0 ? p.z - 15 : p.z; 33 | return {cx / 16 * 16, 0, cz / 16 * 16}; 34 | } 35 | 36 | /*Don't torch it*/ 37 | 38 | struct PendingEntry { 39 | BaseCircuitComponent *mRawComponentPtr; 40 | std::unique_ptr mComponent; 41 | BlockPos mPos; 42 | }; 43 | 44 | namespace std { 45 | template <> 46 | struct hash { 47 | std::size_t operator()(PendingEntry const &ent) const noexcept { 48 | return hash()(ent.mPos); 49 | } 50 | }; 51 | } // namespace std 52 | /* 53 | *Core data structure 54 | */ 55 | struct TCircuitSceneGraph { 56 | std::unordered_map> mAllComponents; 57 | std::vector mActiveComponents; 58 | std::unordered_map> mActiveComponentsPerChunk; 59 | std::unordered_map> mPowerAssociationMap; 60 | std::unordered_map mPendingAdds; 61 | std::unordered_map mPendingUpdates; 62 | std::unordered_map> mComponentsToReEvaluate; 63 | std::vector mPendingRemoves; 64 | }; 65 | 66 | static_assert(sizeof(ComponentItem) == 32); 67 | 68 | THook(void, "?removeComponent@CircuitSceneGraph@@AEAAXAEBVBlockPos@@@Z", void *g, 69 | const BlockPos &p) { 70 | if (trapdoor::mod().componentRemove) { 71 | return; 72 | } 73 | original(g, p); 74 | } 75 | 76 | void optPendingRemoves(CircuitSceneGraph *graph) { 77 | // rmt_ScopedCPUSample(PendingRemoveAll, 0); 78 | auto *g = reinterpret_cast(graph); 79 | std::unordered_set activeToRemove; 80 | for (auto &e : g->mPendingRemoves) { 81 | // rmt_ScopedCPUSample(RemoveOne, 0); 82 | auto pos = e.mPos; 83 | // 从全局元件表表内删除 84 | auto componentGroupIter = g->mAllComponents.find(pos); 85 | if (componentGroupIter == g->mAllComponents.end()) continue; 86 | 87 | auto toRemove = std::move(componentGroupIter->second); 88 | auto targetComp = toRemove.get(); 89 | g->mAllComponents.erase(pos); 90 | 91 | if ((int)targetComp->getCircuitComponentType() != 0x40000) { 92 | // reinterpret_cast(&g->mActiveComponents) 93 | // ->removeSource(pos, targetComp); 94 | activeToRemove.insert(pos); 95 | g->mPowerAssociationMap.erase(pos); 96 | } 97 | 98 | { 99 | // rmt_ScopedCPUSample(RemoveChunkMap, 0); 100 | auto chunkPos = toChunkPos(pos); 101 | auto iter2 = g->mActiveComponentsPerChunk.find(chunkPos); 102 | 103 | // 从活跃区块表中中移除 104 | if (iter2 != g->mActiveComponentsPerChunk.end()) { 105 | auto &list = iter2->second; 106 | reinterpret_cast(&list)->removeSource(pos, targetComp); 107 | } 108 | } 109 | 110 | auto &mSourceList = dAccess, 8>(targetComp); 111 | for (auto &src : mSourceList) { 112 | graph->scheduleRelationshipUpdate(src.mPos, src.mComponent); 113 | } 114 | 115 | { 116 | // rmt_ScopedCPUSample(TraverseAllComp, 0); 117 | auto typeGroup = (int)targetComp->getCircuitComponentGroupType(); 118 | for (auto &allComp : g->mAllComponents) { 119 | if (typeGroup == 0x20000) { 120 | continue; 121 | } 122 | 123 | auto allPos = allComp.first; 124 | auto dis = abs(allPos.x - pos.x) + abs(allPos.y - pos.y) + abs(allPos.z - pos.z); 125 | if (dis > 16) continue; 126 | auto updateComponent = allComp.second.get(); 127 | 128 | // 不是消费者才尝试移除 129 | // 这里可以对中继器和比较器做一些特判,不是这些原件可以吧remove source挪动到后面 130 | // 中继器的不能挪到后面是因为中继器的这个函数还会移除侧边原件,这些原件不是信号源 131 | // 暂时先这么写,有空再优化 132 | updateComponent->removeSource(pos, targetComp); 133 | auto &ss = dAccess, 8>(updateComponent); 134 | auto ssit = ss.begin(); 135 | size_t res = 0; 136 | while (ssit != ss.end()) { 137 | if (ssit->mPos == pos || ssit->mComponent == targetComp) { 138 | graph->scheduleRelationshipUpdate(allComp.first, updateComponent); 139 | ss.erase(ssit); 140 | ++res; 141 | } else { 142 | ++ssit; 143 | } 144 | } 145 | // if (res != 0) { 146 | // updateComponent->removeSource(pos, targetComp); 147 | // } 148 | } 149 | } 150 | 151 | auto neighbors = getBlockPosNeighbors(pos); 152 | for (auto &p : neighbors) { 153 | auto updateComponent = graph->getBaseComponent(p); 154 | if (updateComponent) { 155 | graph->scheduleRelationshipUpdate(p, updateComponent); 156 | auto &sl = dAccess, 8>(updateComponent); 157 | for (auto &item : sl) { 158 | auto sourcePower = graph->getBaseComponent(item.mPos); 159 | graph->scheduleRelationshipUpdate(item.mPos, sourcePower); 160 | } 161 | } 162 | } 163 | 164 | g->mPendingUpdates.erase(pos); 165 | toRemove.reset(nullptr); 166 | } 167 | 168 | if (g->mPendingRemoves.empty()) { 169 | return; 170 | } 171 | std::vector newActiveList; 172 | for (auto &item : g->mActiveComponents) { 173 | if (!activeToRemove.count(item.mPos)) { 174 | newActiveList.push_back(item); 175 | } 176 | } 177 | 178 | g->mActiveComponents = newActiveList; 179 | g->mPendingRemoves.clear(); 180 | } 181 | 182 | THook(void, "?update@CircuitSceneGraph@@QEAAXPEAVBlockSource@@@Z", CircuitSceneGraph *self, 183 | void *bs) { 184 | if (trapdoor::mod().componentRemove) { 185 | optPendingRemoves(self); 186 | } 187 | original(self, bs); 188 | } 189 | 190 | // THook(void, "?evaluateComponents@CircuitSystem@@AEAAX_N@Z", void *c, bool t) { 191 | // if (t) { 192 | // rmt_ScopedCPUSample(Evaluate_True, 0); 193 | // original(c, t); 194 | // } else { 195 | // rmt_ScopedCPUSample(Evaluate_False, 0); 196 | // original(c, t); 197 | // } 198 | // } -------------------------------------------------------------------------------- /src/pch.cpp: -------------------------------------------------------------------------------- 1 | // pch.cpp: 与预编译标头对应的源文件 2 | 3 | #include "pch.h" 4 | 5 | // 当使用预编译的头时,需要使用此源文件,编译才能成功。 6 | -------------------------------------------------------------------------------- /src/remotery/Remotery.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* 4 | Copyright 2014-2018 Celtoys Ltd 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | /* 20 | 21 | Compiling 22 | --------- 23 | 24 | * Windows (MSVC) - add lib/Remotery.c and lib/Remotery.h to your program. Set include 25 | directories to add Remotery/lib path. The required library ws2_32.lib should be picked 26 | up through the use of the #pragma comment(lib, "ws2_32.lib") directive in Remotery.c. 27 | 28 | * Mac OS X (XCode) - simply add lib/Remotery.c and lib/Remotery.h to your program. 29 | 30 | * Linux (GCC) - add the source in lib folder. Compilation of the code requires -pthreads for 31 | library linkage. For example to compile the same run: cc lib/Remotery.c sample/sample.c 32 | -I lib -pthread -lm 33 | 34 | You can define some extra macros to modify what features are compiled into Remotery. These are 35 | documented just below this comment. 36 | 37 | */ 38 | #include 39 | #include 40 | 41 | #ifndef RMT_INCLUDED_H 42 | #define RMT_INCLUDED_H 43 | 44 | // Set to 0 to not include any bits of Remotery in your build 45 | #ifndef RMT_ENABLED 46 | #define RMT_ENABLED 0 47 | #endif 48 | 49 | // Help performance of the server sending data to the client by marking this machine as 50 | // little-endian 51 | #ifndef RMT_ASSUME_LITTLE_ENDIAN 52 | #define RMT_ASSUME_LITTLE_ENDIAN 0 53 | #endif 54 | 55 | // Used by the Celtoys TinyCRT library (not released yet) 56 | #ifndef RMT_USE_TINYCRT 57 | #define RMT_USE_TINYCRT 0 58 | #endif 59 | 60 | // Assuming CUDA headers/libs are setup, allow CUDA profiling 61 | #ifndef RMT_USE_CUDA 62 | #define RMT_USE_CUDA 0 63 | #endif 64 | 65 | // Assuming Direct3D 11 headers/libs are setup, allow D3D11 profiling 66 | #ifndef RMT_USE_D3D11 67 | #define RMT_USE_D3D11 0 68 | #endif 69 | 70 | // Allow OpenGL profiling 71 | #ifndef RMT_USE_OPENGL 72 | #define RMT_USE_OPENGL 0 73 | #endif 74 | 75 | // Allow Metal profiling 76 | #ifndef RMT_USE_METAL 77 | #define RMT_USE_METAL 0 78 | #endif 79 | 80 | // Initially use POSIX thread names to name threads instead of Thread0, 1, ... 81 | #ifndef RMT_USE_POSIX_THREADNAMES 82 | #define RMT_USE_POSIX_THREADNAMES 0 83 | #endif 84 | 85 | // How many times we spin data back and forth between CPU & GPU 86 | // to calculate average RTT (Roundtrip Time). Cannot be 0. 87 | // Affects OpenGL & D3D11 88 | #ifndef RMT_GPU_CPU_SYNC_NUM_ITERATIONS 89 | #define RMT_GPU_CPU_SYNC_NUM_ITERATIONS 16 90 | #endif 91 | 92 | // Time in seconds between each resync to compensate for drifting between GPU & CPU timers, 93 | // effects of power saving, etc. Resyncs can cause stutter, lag spikes, stalls. 94 | // Set to 0 for never. 95 | // Affects OpenGL & D3D11 96 | #ifndef RMT_GPU_CPU_SYNC_SECONDS 97 | #define RMT_GPU_CPU_SYNC_SECONDS 30 98 | #endif 99 | 100 | // Whether we should automatically resync if we detect a timer disjoint (e.g. 101 | // changed from AC power to battery, GPU is overheating, or throttling up/down 102 | // due to laptop savings events). Set it to 0 to avoid resync in such events. 103 | // Useful if for some odd reason a driver reports a lot of disjoints. 104 | // Affects D3D11 105 | #ifndef RMT_D3D11_RESYNC_ON_DISJOINT 106 | #define RMT_D3D11_RESYNC_ON_DISJOINT 1 107 | #endif 108 | 109 | /* 110 | ------------------------------------------------------------------------------------------------------------------------ 111 | ------------------------------------------------------------------------------------------------------------------------ 112 | Compiler/Platform Detection and Preprocessor Utilities 113 | ------------------------------------------------------------------------------------------------------------------------ 114 | ------------------------------------------------------------------------------------------------------------------------ 115 | */ 116 | 117 | // Platform identification 118 | #if defined(_WINDOWS) || defined(_WIN32) 119 | #define RMT_PLATFORM_WINDOWS 120 | #elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) 121 | #define RMT_PLATFORM_LINUX 122 | #define RMT_PLATFORM_POSIX 123 | #elif defined(__APPLE__) 124 | #define RMT_PLATFORM_MACOS 125 | #define RMT_PLATFORM_POSIX 126 | #endif 127 | 128 | // Architecture identification 129 | #ifdef RMT_PLATFORM_WINDOWS 130 | #ifdef _M_AMD64 131 | #define RMT_ARCH_64BIT 132 | #else 133 | #define RMT_ARCH_32BIT 134 | #endif 135 | #endif 136 | 137 | #ifdef RMT_DLL 138 | #if defined(RMT_PLATFORM_WINDOWS) 139 | #if defined(RMT_IMPL) 140 | #define RMT_API __declspec(dllexport) 141 | #else 142 | #define RMT_API __declspec(dllimport) 143 | #endif 144 | #elif defined(RMT_PLATFORM_POSIX) 145 | #if defined(RMT_IMPL) 146 | #define RMT_API __attribute__((visibility("default"))) 147 | #else 148 | #define RMT_API 149 | #endif 150 | #endif 151 | #else 152 | #define RMT_API 153 | #endif 154 | 155 | // Allows macros to be written that can work around the inability to do: #define(x) #ifdef x 156 | // with the C preprocessor. 157 | #if RMT_ENABLED 158 | #define IFDEF_RMT_ENABLED(t, f) t 159 | #else 160 | #define IFDEF_RMT_ENABLED(t, f) f 161 | #endif 162 | #if RMT_ENABLED && RMT_USE_CUDA 163 | #define IFDEF_RMT_USE_CUDA(t, f) t 164 | #else 165 | #define IFDEF_RMT_USE_CUDA(t, f) f 166 | #endif 167 | #if RMT_ENABLED && RMT_USE_D3D11 168 | #define IFDEF_RMT_USE_D3D11(t, f) t 169 | #else 170 | #define IFDEF_RMT_USE_D3D11(t, f) f 171 | #endif 172 | #if RMT_ENABLED && RMT_USE_OPENGL 173 | #define IFDEF_RMT_USE_OPENGL(t, f) t 174 | #else 175 | #define IFDEF_RMT_USE_OPENGL(t, f) f 176 | #endif 177 | #if RMT_ENABLED && RMT_USE_METAL 178 | #define IFDEF_RMT_USE_METAL(t, f) t 179 | #else 180 | #define IFDEF_RMT_USE_METAL(t, f) f 181 | #endif 182 | 183 | // Public interface is written in terms of these macros to easily enable/disable itself 184 | #define RMT_OPTIONAL(macro, x) IFDEF_##macro(x, ) 185 | #define RMT_OPTIONAL_RET(macro, x, y) IFDEF_##macro(x, (y)) 186 | 187 | /* 188 | ------------------------------------------------------------------------------------------------------------------------ 189 | ------------------------------------------------------------------------------------------------------------------------ 190 | Types 191 | ------------------------------------------------------------------------------------------------------------------------ 192 | ------------------------------------------------------------------------------------------------------------------------ 193 | */ 194 | 195 | // Boolean 196 | typedef unsigned int rmtBool; 197 | #define RMT_TRUE ((rmtBool)1) 198 | #define RMT_FALSE ((rmtBool)0) 199 | 200 | // Unsigned integer types 201 | typedef unsigned char rmtU8; 202 | typedef unsigned short rmtU16; 203 | typedef unsigned int rmtU32; 204 | typedef unsigned long long rmtU64; 205 | 206 | // Signed integer types 207 | typedef char rmtS8; 208 | typedef short rmtS16; 209 | typedef int rmtS32; 210 | typedef long long rmtS64; 211 | 212 | // Const, null-terminated string pointer 213 | typedef const char* rmtPStr; 214 | 215 | // Opaque pointer for a sample graph tree 216 | typedef struct Msg_SampleTree rmtSampleTree; 217 | 218 | // Opaque pointer to a node in the sample graph tree 219 | typedef struct Sample rmtSample; 220 | 221 | // Handle to the main remotery instance 222 | typedef struct Remotery Remotery; 223 | 224 | // All possible error codes 225 | // clang-format off 226 | typedef enum rmtError 227 | { 228 | RMT_ERROR_NONE, 229 | RMT_ERROR_RECURSIVE_SAMPLE, // Not an error but an internal message to calling code 230 | RMT_ERROR_UNKNOWN, // An error with a message yet to be defined, only for internal error handling 231 | 232 | // System errors 233 | RMT_ERROR_MALLOC_FAIL, // Malloc call within remotery failed 234 | RMT_ERROR_TLS_ALLOC_FAIL, // Attempt to allocate thread local storage failed 235 | RMT_ERROR_VIRTUAL_MEMORY_BUFFER_FAIL, // Failed to create a virtual memory mirror buffer 236 | RMT_ERROR_CREATE_THREAD_FAIL, // Failed to create a thread for the server 237 | RMT_ERROR_OPEN_THREAD_HANDLE_FAIL, // Failed to open a thread handle, given a thread id 238 | 239 | // Network TCP/IP socket errors 240 | RMT_ERROR_SOCKET_INIT_NETWORK_FAIL, // Network initialisation failure (e.g. on Win32, WSAStartup fails) 241 | RMT_ERROR_SOCKET_CREATE_FAIL, // Can't create a socket for connection to the remote viewer 242 | RMT_ERROR_SOCKET_BIND_FAIL, // Can't bind a socket for the server 243 | RMT_ERROR_SOCKET_LISTEN_FAIL, // Created server socket failed to enter a listen state 244 | RMT_ERROR_SOCKET_SET_NON_BLOCKING_FAIL, // Created server socket failed to switch to a non-blocking state 245 | RMT_ERROR_SOCKET_INVALID_POLL, // Poll attempt on an invalid socket 246 | RMT_ERROR_SOCKET_SELECT_FAIL, // Server failed to call select on socket 247 | RMT_ERROR_SOCKET_POLL_ERRORS, // Poll notified that the socket has errors 248 | RMT_ERROR_SOCKET_ACCEPT_FAIL, // Server failed to accept connection from client 249 | RMT_ERROR_SOCKET_SEND_TIMEOUT, // Timed out trying to send data 250 | RMT_ERROR_SOCKET_SEND_FAIL, // Unrecoverable error occured while client/server tried to send data 251 | RMT_ERROR_SOCKET_RECV_NO_DATA, // No data available when attempting a receive 252 | RMT_ERROR_SOCKET_RECV_TIMEOUT, // Timed out trying to receive data 253 | RMT_ERROR_SOCKET_RECV_FAILED, // Unrecoverable error occured while client/server tried to receive data 254 | 255 | // WebSocket errors 256 | RMT_ERROR_WEBSOCKET_HANDSHAKE_NOT_GET, // WebSocket server handshake failed, not HTTP GET 257 | RMT_ERROR_WEBSOCKET_HANDSHAKE_NO_VERSION, // WebSocket server handshake failed, can't locate WebSocket version 258 | RMT_ERROR_WEBSOCKET_HANDSHAKE_BAD_VERSION, // WebSocket server handshake failed, unsupported WebSocket version 259 | RMT_ERROR_WEBSOCKET_HANDSHAKE_NO_HOST, // WebSocket server handshake failed, can't locate host 260 | RMT_ERROR_WEBSOCKET_HANDSHAKE_BAD_HOST, // WebSocket server handshake failed, host is not allowed to connect 261 | RMT_ERROR_WEBSOCKET_HANDSHAKE_NO_KEY, // WebSocket server handshake failed, can't locate WebSocket key 262 | RMT_ERROR_WEBSOCKET_HANDSHAKE_BAD_KEY, // WebSocket server handshake failed, WebSocket key is ill-formed 263 | RMT_ERROR_WEBSOCKET_HANDSHAKE_STRING_FAIL, // WebSocket server handshake failed, internal error, bad string code 264 | RMT_ERROR_WEBSOCKET_DISCONNECTED, // WebSocket server received a disconnect request and closed the socket 265 | RMT_ERROR_WEBSOCKET_BAD_FRAME_HEADER, // Couldn't parse WebSocket frame header 266 | RMT_ERROR_WEBSOCKET_BAD_FRAME_HEADER_SIZE, // Partially received wide frame header size 267 | RMT_ERROR_WEBSOCKET_BAD_FRAME_HEADER_MASK, // Partially received frame header data mask 268 | RMT_ERROR_WEBSOCKET_RECEIVE_TIMEOUT, // Timeout receiving frame header 269 | 270 | RMT_ERROR_REMOTERY_NOT_CREATED, // Remotery object has not been created 271 | RMT_ERROR_SEND_ON_INCOMPLETE_PROFILE, // An attempt was made to send an incomplete profile tree to the client 272 | 273 | // CUDA error messages 274 | RMT_ERROR_CUDA_DEINITIALIZED, // This indicates that the CUDA driver is in the process of shutting down 275 | RMT_ERROR_CUDA_NOT_INITIALIZED, // This indicates that the CUDA driver has not been initialized with cuInit() or that initialization has failed 276 | RMT_ERROR_CUDA_INVALID_CONTEXT, // This most frequently indicates that there is no context bound to the current thread 277 | RMT_ERROR_CUDA_INVALID_VALUE, // This indicates that one or more of the parameters passed to the API call is not within an acceptable range of values 278 | RMT_ERROR_CUDA_INVALID_HANDLE, // This indicates that a resource handle passed to the API call was not valid 279 | RMT_ERROR_CUDA_OUT_OF_MEMORY, // The API call failed because it was unable to allocate enough memory to perform the requested operation 280 | RMT_ERROR_ERROR_NOT_READY, // This indicates that a resource handle passed to the API call was not valid 281 | 282 | // Direct3D 11 error messages 283 | RMT_ERROR_D3D11_FAILED_TO_CREATE_QUERY, // Failed to create query for sample 284 | 285 | // OpenGL error messages 286 | RMT_ERROR_OPENGL_ERROR, // Generic OpenGL error, no need to expose detail since app will need an OpenGL error callback registered 287 | 288 | RMT_ERROR_CUDA_UNKNOWN, 289 | } rmtError; 290 | // clang-format on 291 | 292 | typedef enum rmtSampleFlags { 293 | // Default behaviour 294 | RMTSF_None = 0, 295 | 296 | // Search parent for same-named samples and merge timing instead of adding a new sample 297 | RMTSF_Aggregate = 1, 298 | 299 | // Merge sample with parent if it's the same sample 300 | RMTSF_Recursive = 2, 301 | 302 | // Set this flag on any of your root samples so that Remotery will assert if it ends up *not* 303 | // being the root sample. This will quickly allow you to detect Begin/End mismatches causing a 304 | // sample tree imbalance. 305 | RMTSF_Root = 4, 306 | } rmtSampleFlags; 307 | 308 | typedef enum rmtSampleType { 309 | RMT_SampleType_CPU, 310 | RMT_SampleType_CUDA, 311 | RMT_SampleType_D3D11, 312 | RMT_SampleType_OpenGL, 313 | RMT_SampleType_Metal, 314 | RMT_SampleType_Count, 315 | } rmtSampleType; 316 | 317 | // Struct to hold iterator info 318 | typedef struct rmtSampleIterator { 319 | // public 320 | rmtSample* sample; 321 | // private 322 | rmtSample* initial; 323 | } rmtSampleIterator; 324 | 325 | /* 326 | ------------------------------------------------------------------------------------------------------------------------ 327 | ------------------------------------------------------------------------------------------------------------------------ 328 | Public Interface 329 | ------------------------------------------------------------------------------------------------------------------------ 330 | ------------------------------------------------------------------------------------------------------------------------ 331 | */ 332 | 333 | // Can call remotery functions on a null pointer 334 | // TODO: Can embed extern "C" in these macros? 335 | 336 | #define rmt_Settings() RMT_OPTIONAL_RET(RMT_ENABLED, _rmt_Settings(), NULL) 337 | 338 | #define rmt_CreateGlobalInstance(rmt) \ 339 | RMT_OPTIONAL_RET(RMT_ENABLED, _rmt_CreateGlobalInstance(rmt), RMT_ERROR_NONE) 340 | 341 | #define rmt_DestroyGlobalInstance(rmt) RMT_OPTIONAL(RMT_ENABLED, _rmt_DestroyGlobalInstance(rmt)) 342 | 343 | #define rmt_SetGlobalInstance(rmt) RMT_OPTIONAL(RMT_ENABLED, _rmt_SetGlobalInstance(rmt)) 344 | 345 | #define rmt_GetGlobalInstance() RMT_OPTIONAL_RET(RMT_ENABLED, _rmt_GetGlobalInstance(), NULL) 346 | 347 | #define rmt_SetCurrentThreadName(rmt) RMT_OPTIONAL(RMT_ENABLED, _rmt_SetCurrentThreadName(rmt)) 348 | 349 | #define rmt_LogText(text) RMT_OPTIONAL(RMT_ENABLED, _rmt_LogText(text)) 350 | 351 | #define rmt_BeginCPUSample(name, flags) \ 352 | RMT_OPTIONAL(RMT_ENABLED, { \ 353 | static rmtU32 rmt_sample_hash_##name = 0; \ 354 | _rmt_BeginCPUSample(#name, flags, &rmt_sample_hash_##name); \ 355 | }) 356 | 357 | #define rmt_BeginCPUSampleDynamic(namestr, flags) \ 358 | RMT_OPTIONAL(RMT_ENABLED, _rmt_BeginCPUSample(namestr, flags, NULL)) 359 | 360 | #define rmt_EndCPUSample() RMT_OPTIONAL(RMT_ENABLED, _rmt_EndCPUSample()) 361 | 362 | #define rmt_IterateChildren(iter, sample) \ 363 | RMT_OPTIONAL(RMT_ENABLED, _rmt_IterateChildren(iter, sample)) 364 | 365 | #define rmt_IterateNext(iter) RMT_OPTIONAL_RET(RMT_ENABLED, _rmt_IterateNext(iter), RMT_FALSE) 366 | 367 | #define rmt_SampleTreeGetThreadName(sample_tree) \ 368 | RMT_OPTIONAL_RET(RMT_ENABLED, _rmt_SampleTreeGetThreadName(sample_tree), NULL) 369 | 370 | #define rmt_SampleTreeGetRootSample(sample_tree) \ 371 | RMT_OPTIONAL_RET(RMT_ENABLED, _rmt_SampleTreeGetRootSample(sample_tree), NULL) 372 | 373 | // Should only called from within the sample tree callback, 374 | // when the internal string lookup table is valid (i.e. on the main Remotery thread) 375 | #define rmt_SampleGetName(sample) RMT_OPTIONAL_RET(RMT_ENABLED, _rmt_SampleGetName(sample), NULL) 376 | 377 | #define rmt_SampleGetNameHash(sample) \ 378 | RMT_OPTIONAL_RET(RMT_ENABLED, _rmt_SampleGetNameHash(sample), 0U) 379 | 380 | #define rmt_SampleGetCallCount(sample) \ 381 | RMT_OPTIONAL_RET(RMT_ENABLED, _rmt_SampleGetCallCount(sample), 0U) 382 | 383 | #define rmt_SampleGetStart(sample) RMT_OPTIONAL_RET(RMT_ENABLED, _rmt_SampleGetStart(sample), 0LLU) 384 | 385 | #define rmt_SampleGetTime(sample) RMT_OPTIONAL_RET(RMT_ENABLED, _rmt_SampleGetTime(sample), 0LLU) 386 | 387 | #define rmt_SampleGetSelfTime(sample) \ 388 | RMT_OPTIONAL_RET(RMT_ENABLED, _rmt_SampleGetSelfTime(sample), 0LLU) 389 | 390 | #define rmt_SampleGetColour(sample, r, g, b) \ 391 | RMT_OPTIONAL(RMT_ENABLED, _rmt_SampleGetColour(sample, r, g, b)) 392 | 393 | #define rmt_SampleGetType(sample) \ 394 | RMT_OPTIONAL_RET(RMT_ENABLED, _rmt_SampleGetType(sample), RMT_SampleType_Count) 395 | 396 | // Callback function pointer types 397 | typedef void* (*rmtMallocPtr)(void* mm_context, rmtU32 size); 398 | typedef void* (*rmtReallocPtr)(void* mm_context, void* ptr, rmtU32 size); 399 | typedef void (*rmtFreePtr)(void* mm_context, void* ptr); 400 | typedef void (*rmtInputHandlerPtr)(const char* text, void* context); 401 | typedef void (*rmtSampleTreeHandlerPtr)(void* cbk_context, rmtSampleTree* sample_tree); 402 | 403 | // Struture to fill in to modify Remotery default settings 404 | typedef struct rmtSettings { 405 | // Which port to listen for incoming connections on 406 | rmtU16 port; 407 | 408 | // When this server exits it can leave the port open in TIME_WAIT state for a while. This forces 409 | // subsequent server bind attempts to fail when restarting. If you find restarts fail repeatedly 410 | // with bind attempts, set this to true to forcibly reuse the open port. 411 | rmtBool reuse_open_port; 412 | 413 | // Only allow connections on localhost? 414 | // For dev builds you may want to access your game from other devices but if 415 | // you distribute a game to your players with Remotery active, probably best 416 | // to limit connections to localhost. 417 | rmtBool limit_connections_to_localhost; 418 | 419 | // Whether to enable runtime thread sampling that discovers which processors a thread is running 420 | // on. This will suspend and resume threads from outside repeatdly and inject code into each 421 | // thread that automatically instruments the processor. 422 | // Default: Enabled 423 | rmtBool enableThreadSampler; 424 | 425 | // How long to sleep between server updates, hopefully trying to give 426 | // a little CPU back to other threads. 427 | rmtU32 msSleepBetweenServerUpdates; 428 | 429 | // Size of the internal message queues Remotery uses 430 | // Will be rounded to page granularity of 64k 431 | rmtU32 messageQueueSizeInBytes; 432 | 433 | // If the user continuously pushes to the message queue, the server network 434 | // code won't get a chance to update unless there's an upper-limit on how 435 | // many messages can be consumed per loop. 436 | rmtU32 maxNbMessagesPerUpdate; 437 | 438 | // Callback pointers for memory allocation 439 | rmtMallocPtr malloc; 440 | rmtReallocPtr realloc; 441 | rmtFreePtr free; 442 | void* mm_context; 443 | 444 | // Callback pointer for receiving input from the Remotery console 445 | rmtInputHandlerPtr input_handler; 446 | 447 | // Callback pointer for traversing the sample tree graph 448 | rmtSampleTreeHandlerPtr sampletree_handler; 449 | void* sampletree_context; 450 | 451 | // Context pointer that gets sent to Remotery console callback function 452 | void* input_handler_context; 453 | 454 | rmtPStr logPath; 455 | } rmtSettings; 456 | 457 | // Structure to fill in when binding CUDA to Remotery 458 | typedef struct rmtCUDABind { 459 | // The main context that all driver functions apply before each call 460 | void* context; 461 | 462 | // Driver API function pointers that need to be pointed to 463 | // Untyped so that the CUDA headers are not required in this file 464 | // NOTE: These are named differently to the CUDA functions because the CUDA API has a habit of 465 | // using macros to point function calls to different versions, e.g. cuEventDestroy is a macro 466 | // for cuEventDestroy_v2. 467 | void* CtxSetCurrent; 468 | void* CtxGetCurrent; 469 | void* EventCreate; 470 | void* EventDestroy; 471 | void* EventRecord; 472 | void* EventQuery; 473 | void* EventElapsedTime; 474 | 475 | } rmtCUDABind; 476 | 477 | // Call once after you've initialised CUDA to bind it to Remotery 478 | #define rmt_BindCUDA(bind) RMT_OPTIONAL(RMT_USE_CUDA, _rmt_BindCUDA(bind)) 479 | 480 | // Mark the beginning of a CUDA sample on the specified asynchronous stream 481 | #define rmt_BeginCUDASample(name, stream) \ 482 | RMT_OPTIONAL(RMT_USE_CUDA, { \ 483 | static rmtU32 rmt_sample_hash_##name = 0; \ 484 | _rmt_BeginCUDASample(#name, &rmt_sample_hash_##name, stream); \ 485 | }) 486 | 487 | // Mark the end of a CUDA sample on the specified asynchronous stream 488 | #define rmt_EndCUDASample(stream) RMT_OPTIONAL(RMT_USE_CUDA, _rmt_EndCUDASample(stream)) 489 | 490 | #define rmt_BindD3D11(device, context) RMT_OPTIONAL(RMT_USE_D3D11, _rmt_BindD3D11(device, context)) 491 | 492 | #define rmt_UnbindD3D11() RMT_OPTIONAL(RMT_USE_D3D11, _rmt_UnbindD3D11()) 493 | 494 | #define rmt_BeginD3D11Sample(name) \ 495 | RMT_OPTIONAL(RMT_USE_D3D11, { \ 496 | static rmtU32 rmt_sample_hash_##name = 0; \ 497 | _rmt_BeginD3D11Sample(#name, &rmt_sample_hash_##name); \ 498 | }) 499 | 500 | #define rmt_BeginD3D11SampleDynamic(namestr) \ 501 | RMT_OPTIONAL(RMT_USE_D3D11, _rmt_BeginD3D11Sample(namestr, NULL)) 502 | 503 | #define rmt_EndD3D11Sample() RMT_OPTIONAL(RMT_USE_D3D11, _rmt_EndD3D11Sample()) 504 | 505 | #define rmt_BindOpenGL() RMT_OPTIONAL(RMT_USE_OPENGL, _rmt_BindOpenGL()) 506 | 507 | #define rmt_UnbindOpenGL() RMT_OPTIONAL(RMT_USE_OPENGL, _rmt_UnbindOpenGL()) 508 | 509 | #define rmt_BeginOpenGLSample(name) \ 510 | RMT_OPTIONAL(RMT_USE_OPENGL, { \ 511 | static rmtU32 rmt_sample_hash_##name = 0; \ 512 | _rmt_BeginOpenGLSample(#name, &rmt_sample_hash_##name); \ 513 | }) 514 | 515 | #define rmt_BeginOpenGLSampleDynamic(namestr) \ 516 | RMT_OPTIONAL(RMT_USE_OPENGL, _rmt_BeginOpenGLSample(namestr, NULL)) 517 | 518 | #define rmt_EndOpenGLSample() RMT_OPTIONAL(RMT_USE_OPENGL, _rmt_EndOpenGLSample()) 519 | 520 | #define rmt_BindMetal(command_buffer) RMT_OPTIONAL(RMT_USE_METAL, _rmt_BindMetal(command_buffer)); 521 | 522 | #define rmt_UnbindMetal() RMT_OPTIONAL(RMT_USE_METAL, _rmt_UnbindMetal()); 523 | 524 | #define rmt_BeginMetalSample(name) \ 525 | RMT_OPTIONAL(RMT_USE_METAL, { \ 526 | static rmtU32 rmt_sample_hash_##name = 0; \ 527 | _rmt_BeginMetalSample(#name, &rmt_sample_hash_##name); \ 528 | }) 529 | 530 | #define rmt_BeginMetalSampleDynamic(namestr) \ 531 | RMT_OPTIONAL(RMT_USE_METAL, _rmt_BeginMetalSample(namestr, NULL)) 532 | 533 | #define rmt_EndMetalSample() RMT_OPTIONAL(RMT_USE_METAL, _rmt_EndMetalSample()) 534 | 535 | /* 536 | ------------------------------------------------------------------------------------------------------------------------ 537 | ------------------------------------------------------------------------------------------------------------------------ 538 | C++ Public Interface Extensions 539 | ------------------------------------------------------------------------------------------------------------------------ 540 | ------------------------------------------------------------------------------------------------------------------------ 541 | */ 542 | 543 | #ifdef __cplusplus 544 | 545 | #if RMT_ENABLED 546 | 547 | // Types that end samples in their destructors 548 | extern "C" RMT_API void _rmt_EndCPUSample(void); 549 | struct rmt_EndCPUSampleOnScopeExit { 550 | ~rmt_EndCPUSampleOnScopeExit() { _rmt_EndCPUSample(); } 551 | }; 552 | #if RMT_USE_CUDA 553 | extern "C" RMT_API void _rmt_EndCUDASample(void* stream); 554 | struct rmt_EndCUDASampleOnScopeExit { 555 | rmt_EndCUDASampleOnScopeExit(void* stream) : stream(stream) {} 556 | ~rmt_EndCUDASampleOnScopeExit() { _rmt_EndCUDASample(stream); } 557 | void* stream; 558 | }; 559 | #endif 560 | #if RMT_USE_D3D11 561 | extern "C" RMT_API void _rmt_EndD3D11Sample(void); 562 | struct rmt_EndD3D11SampleOnScopeExit { 563 | ~rmt_EndD3D11SampleOnScopeExit() { _rmt_EndD3D11Sample(); } 564 | }; 565 | #endif 566 | 567 | #if RMT_USE_OPENGL 568 | extern "C" RMT_API void _rmt_EndOpenGLSample(void); 569 | struct rmt_EndOpenGLSampleOnScopeExit { 570 | ~rmt_EndOpenGLSampleOnScopeExit() { _rmt_EndOpenGLSample(); } 571 | }; 572 | #endif 573 | 574 | #if RMT_USE_METAL 575 | extern "C" RMT_API void _rmt_EndMetalSample(void); 576 | struct rmt_EndMetalSampleOnScopeExit { 577 | ~rmt_EndMetalSampleOnScopeExit() { _rmt_EndMetalSample(); } 578 | }; 579 | #endif 580 | 581 | #endif 582 | 583 | // Pairs a call to rmt_BeginSample with its call to rmt_EndSample when leaving scope 584 | #define rmt_ScopedCPUSample(name, flags) \ 585 | RMT_OPTIONAL(RMT_ENABLED, rmt_BeginCPUSample(name, flags)); \ 586 | RMT_OPTIONAL(RMT_ENABLED, rmt_EndCPUSampleOnScopeExit rmt_ScopedCPUSample##name); 587 | #define rmt_ScopedCUDASample(name, stream) \ 588 | RMT_OPTIONAL(RMT_USE_CUDA, rmt_BeginCUDASample(name, stream)); \ 589 | RMT_OPTIONAL(RMT_USE_CUDA, rmt_EndCUDASampleOnScopeExit rmt_ScopedCUDASample##name(stream)); 590 | #define rmt_ScopedD3D11Sample(name) \ 591 | RMT_OPTIONAL(RMT_USE_D3D11, rmt_BeginD3D11Sample(name)); \ 592 | RMT_OPTIONAL(RMT_USE_D3D11, rmt_EndD3D11SampleOnScopeExit rmt_ScopedD3D11Sample##name); 593 | #define rmt_ScopedOpenGLSample(name) \ 594 | RMT_OPTIONAL(RMT_USE_OPENGL, rmt_BeginOpenGLSample(name)); \ 595 | RMT_OPTIONAL(RMT_USE_OPENGL, rmt_EndOpenGLSampleOnScopeExit rmt_ScopedOpenGLSample##name); 596 | #define rmt_ScopedMetalSample(name) \ 597 | RMT_OPTIONAL(RMT_USE_METAL, rmt_BeginMetalSample(name)); \ 598 | RMT_OPTIONAL(RMT_USE_METAL, rmt_EndMetalSampleOnScopeExit rmt_ScopedMetalSample##name); 599 | 600 | #endif 601 | 602 | /* 603 | ------------------------------------------------------------------------------------------------------------------------ 604 | ------------------------------------------------------------------------------------------------------------------------ 605 | Private Interface - don't directly call these 606 | ------------------------------------------------------------------------------------------------------------------------ 607 | ------------------------------------------------------------------------------------------------------------------------ 608 | */ 609 | 610 | #if RMT_ENABLED 611 | 612 | #ifdef __cplusplus 613 | extern "C" { 614 | #endif 615 | 616 | RMT_API rmtSettings* _rmt_Settings(void); 617 | RMT_API enum rmtError _rmt_CreateGlobalInstance(Remotery** remotery); 618 | RMT_API void _rmt_DestroyGlobalInstance(Remotery* remotery); 619 | RMT_API void _rmt_SetGlobalInstance(Remotery* remotery); 620 | RMT_API Remotery* _rmt_GetGlobalInstance(void); 621 | RMT_API void _rmt_SetCurrentThreadName(rmtPStr thread_name); 622 | RMT_API void _rmt_LogText(rmtPStr text); 623 | RMT_API void _rmt_BeginCPUSample(rmtPStr name, rmtU32 flags, rmtU32* hash_cache); 624 | RMT_API void _rmt_EndCPUSample(void); 625 | 626 | #if RMT_USE_CUDA 627 | RMT_API void _rmt_BindCUDA(const rmtCUDABind* bind); 628 | RMT_API void _rmt_BeginCUDASample(rmtPStr name, rmtU32* hash_cache, void* stream); 629 | RMT_API void _rmt_EndCUDASample(void* stream); 630 | #endif 631 | 632 | #if RMT_USE_D3D11 633 | RMT_API void _rmt_BindD3D11(void* device, void* context); 634 | RMT_API void _rmt_UnbindD3D11(void); 635 | RMT_API void _rmt_BeginD3D11Sample(rmtPStr name, rmtU32* hash_cache); 636 | RMT_API void _rmt_EndD3D11Sample(void); 637 | #endif 638 | 639 | #if RMT_USE_OPENGL 640 | RMT_API void _rmt_BindOpenGL(); 641 | RMT_API void _rmt_UnbindOpenGL(void); 642 | RMT_API void _rmt_BeginOpenGLSample(rmtPStr name, rmtU32* hash_cache); 643 | RMT_API void _rmt_EndOpenGLSample(void); 644 | #endif 645 | 646 | #if RMT_USE_METAL 647 | RMT_API void _rmt_BeginMetalSample(rmtPStr name, rmtU32* hash_cache); 648 | RMT_API void _rmt_EndMetalSample(void); 649 | #endif 650 | 651 | // Iterator 652 | RMT_API void _rmt_IterateChildren(rmtSampleIterator* iter, rmtSample* sample); 653 | RMT_API rmtBool _rmt_IterateNext(rmtSampleIterator* iter); 654 | 655 | // SampleTree accessors 656 | RMT_API const char* _rmt_SampleTreeGetThreadName(rmtSampleTree* sample_tree); 657 | RMT_API rmtSample* _rmt_SampleTreeGetRootSample(rmtSampleTree* sample_tree); 658 | 659 | // Sample accessors 660 | RMT_API const char* _rmt_SampleGetName(rmtSample* sample); 661 | RMT_API rmtU32 _rmt_SampleGetNameHash(rmtSample* sample); 662 | RMT_API rmtU32 _rmt_SampleGetCallCount(rmtSample* sample); 663 | RMT_API rmtU64 _rmt_SampleGetStart(rmtSample* sample); 664 | RMT_API rmtU64 _rmt_SampleGetTime(rmtSample* sample); 665 | RMT_API rmtU64 _rmt_SampleGetSelfTime(rmtSample* sample); 666 | RMT_API void _rmt_SampleGetColour(rmtSample* sample, rmtU8* r, rmtU8* g, rmtU8* b); 667 | RMT_API rmtSampleType _rmt_SampleGetType(rmtSample* sample); 668 | 669 | #ifdef __cplusplus 670 | } 671 | #endif 672 | 673 | #if RMT_USE_METAL 674 | #ifdef __OBJC__ 675 | RMT_API void _rmt_BindMetal(id command_buffer); 676 | RMT_API void _rmt_UnbindMetal(); 677 | #endif 678 | #endif 679 | 680 | #endif // RMT_ENABLED 681 | 682 | #endif 683 | --------------------------------------------------------------------------------