├── .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 |
--------------------------------------------------------------------------------