├── .gitattributes ├── .github └── workflows │ ├── build-template.yml │ └── updateSDK.yml ├── .gitignore ├── .gitmodules ├── .idea └── cmake.xml ├── CMakeLists.txt ├── GOHelper ├── .idea │ ├── .gitignore │ ├── .name │ ├── GOHelper.iml │ ├── modules.xml │ └── vcs.xml ├── go.mod ├── go.sum ├── json.go └── png.go ├── README.md ├── Template.sln ├── Template ├── GoLang.hpp ├── Plugin.cpp ├── Resource.rc ├── Setting.cpp ├── Setting.h ├── Template.vcxproj ├── Template.vcxproj.filters ├── Version.h ├── dllmain.cpp ├── framework.h ├── godef.h └── resource.h ├── build.bat ├── fetchSDK.cmd └── prepareLib.cmd /.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/build-template.yml: -------------------------------------------------------------------------------- 1 | name: Build Plugin(Publish if tag) 2 | 3 | on: [push] 4 | 5 | env: 6 | PLUGIN_NAME: CustomMapX 7 | SOLUTION_FILE_PATH: ./Template.sln 8 | VERSION_FILE_PATH: Template/Version.h 9 | BUILD_CONFIGURATION: Release 10 | Platform: X64 11 | SDK_DIR: ./SDK 12 | BDS_VERSION: 1.19.30.04 13 | 14 | jobs: 15 | build: 16 | runs-on: windows-latest 17 | 18 | steps: 19 | - uses: actions/checkout@v2 20 | with: 21 | submodules: 'true' 22 | 23 | # - name: Get information from Version.h file (TODO) 24 | # working-directory: ${{env.GITHUB_WORKSPACE}} 25 | # id: ver 26 | # run: | 27 | # pwd 28 | # shell: bash 29 | 30 | - name: Download Server 31 | working-directory: ${{env.GITHUB_WORKSPACE}} 32 | run: | 33 | mkdir -p ${{ env.SDK_DIR }}/Tools/Server 34 | # ServerLink=$(cat 'Scripts/LINK.txt') 35 | ServerLink=https://minecraft.azureedge.net/bin-win/bedrock-server-${{ env.BDS_VERSION }}.zip 36 | curl -L -o ${{ env.SDK_DIR }}/Tools/Server/server.zip "$ServerLink" 37 | unzip ${{ env.SDK_DIR }}/Tools/Server/server.zip -d ${{ env.SDK_DIR }}/Tools/Server/ > /dev/null 38 | shell: bash 39 | 40 | - name: Build Library 41 | working-directory: ${{env.GITHUB_WORKSPACE}} 42 | run: | 43 | cd ${{ env.SDK_DIR }}\Tools 44 | LibraryBuilder.exe -o ..\Lib .\Server 45 | shell: cmd 46 | 47 | - name: Add MSBuild to PATH 48 | uses: microsoft/setup-msbuild@v1 49 | 50 | - name: Change PLUGIN_VERSION_STATUS_BETA 51 | working-directory: ${{env.GITHUB_WORKSPACE}} 52 | if: false == startsWith(github.ref, 'refs/tags/') 53 | run: | 54 | sed -r -i 's/#define\s+PLUGIN_VERSION_STATUS\s+PLUGIN_VERSION_\w+/#define PLUGIN_VERSION_STATUS PLUGIN_VERSION_BETA/' ${{env.VERSION_FILE_PATH}} 55 | sed -r -i 's/#define\s+PLUGIN_VERSION_BUILD\s+.*/#define PLUGIN_VERSION_BUILD ${{ github.run_number }}\r/' ${{env.VERSION_FILE_PATH}} 56 | shell: bash 57 | 58 | - name: Change PLUGIN_VERSION_STATUS_RELEASE 59 | working-directory: ${{env.GITHUB_WORKSPACE}} 60 | if: startsWith(github.ref, 'refs/tags/') 61 | run: | 62 | sed -r -i 's/#define\s+PLUGIN_VERSION_STATUS\s+PLUGIN_VERSION_\w+/#define PLUGIN_VERSION_STATUS PLUGIN_VERSION_RELEASE/' ${{env.VERSION_FILE_PATH}} 63 | sed -r -i 's/#define\s+PLUGIN_VERSION_BUILD\s+.*/#define PLUGIN_VERSION_BUILD ${{ github.run_number }}\r/' ${{env.VERSION_FILE_PATH}} 64 | shell: bash 65 | 66 | - name: Build 67 | working-directory: ${{env.GITHUB_WORKSPACE}} 68 | id: build 69 | run: | 70 | MSBuild.exe ${{env.SOLUTION_FILE_PATH}} -property:Configuration=${{env.BUILD_CONFIGURATION}} 71 | ./build.bat 72 | shell: bash 73 | 74 | - name: copy dll and pdb files 75 | working-directory: ${{env.GITHUB_WORKSPACE}} 76 | run: | 77 | mkdir output/ 78 | mkdir output/${{env.PLUGIN_NAME}}/ 79 | cp -f x64/Release/*.dll output/${{env.PLUGIN_NAME}}/ 80 | mkdir output/${{env.PLUGIN_NAME}}/lib/ 81 | cp -f GOHelper/*.dll output/${{env.PLUGIN_NAME}}/lib/ 82 | mkdir output/PDB/ 83 | cp -f x64/Release/*.pdb output/PDB/ 84 | # mkdir output/${{env.PLUGIN_NAME}}/${{env.PLUGIN_NAME}}/ 85 | # cp -r Data/* output/${{env.PLUGIN_NAME}}/${{env.PLUGIN_NAME}}/ 86 | shell: bash 87 | 88 | - name: Pack Release 89 | working-directory: ${{env.GITHUB_WORKSPACE}} 90 | if: startsWith(github.ref, 'refs/tags/') 91 | run: | 92 | Compress-Archive -Path output\${{env.PLUGIN_NAME}}\ ${{env.PLUGIN_NAME}}.zip 93 | Compress-Archive -Path output\PDB\ PDB.zip 94 | 95 | - name: Prepare for creating Release 96 | working-directory: ${{env.GITHUB_WORKSPACE}} 97 | id: rel 98 | if: startsWith(github.ref, 'refs/tags/') 99 | run: | 100 | echo ::set-output name=tag::${GITHUB_REF#refs/tags/*} 101 | mv ${{env.PLUGIN_NAME}}.zip ${{env.PLUGIN_NAME}}-${GITHUB_REF#refs/tags/*}.zip 102 | mv PDB.zip PDB-${GITHUB_REF#refs/tags/*}.zip 103 | shell: bash 104 | 105 | - name: Upload PLUGIN 106 | uses: actions/upload-artifact@v2 107 | with: 108 | name: ${{env.PLUGIN_NAME}}-actions-${{ github.run_number }} 109 | path: ${{ github.workspace }}\output\${{env.PLUGIN_NAME}} 110 | 111 | - name: Upload PDB 112 | uses: actions/upload-artifact@v2 113 | with: 114 | name: PDB-actions-${{ github.run_number }} 115 | path: ${{ github.workspace }}\output\PDB 116 | 117 | 118 | - name: Create New Release 119 | uses: softprops/action-gh-release@v1 120 | if: startsWith(github.ref, 'refs/tags/') 121 | with: 122 | # body_path: ${{ github.workspace }}\CHANGELOG.txt 123 | files: | 124 | ${{ github.workspace }}\${{env.PLUGIN_NAME}}-${{ steps.rel.outputs.tag }}.zip 125 | ${{ github.workspace }}\PDB-${{ steps.rel.outputs.tag }}.zip 126 | env: 127 | GITHUB_REPOSITORY: ${{env.GITHUB_ACTION_REPOSITORY}} 128 | 129 | -------------------------------------------------------------------------------- /.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 | GOHelper/MAP_Golang_Module.dll 15 | GOHelper/MAP_Golang_Module.h 16 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "SDK"] 2 | path = SDK 3 | url = https://github.com/LiteLDev/LiteLoaderSDK 4 | branch = main 5 | -------------------------------------------------------------------------------- /.idea/cmake.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.21) 2 | project(TemplatePlugin) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_BUILD_TYPE Release) 6 | 7 | file(GLOB_RECURSE SRC_FILES_DIR 8 | ${PROJECT_SOURCE_DIR}/SDK/include/*.cpp 9 | ${PROJECT_SOURCE_DIR}/SDK/include/*.hpp 10 | ${PROJECT_SOURCE_DIR}/SDK/include/*.h 11 | ${PROJECT_SOURCE_DIR}/Template/*.cpp 12 | ${PROJECT_SOURCE_DIR}/Template/*.hpp 13 | ${PROJECT_SOURCE_DIR}/Template/*.h 14 | ) 15 | 16 | include_directories(SDK/include) 17 | include_directories(SDK/include/third-party) 18 | include_directories(Template) 19 | 20 | link_directories(.) 21 | 22 | add_definitions(-D"NDEBUG" -D"TEMPLATE_EXPORTS" -D"WIN32_LEAN_AND_MEAN" -D"_CRT_SECURE_NO_WARNINGS" -D"_WINDOWS" 23 | -D"_USRDLL" -D"_AMD64_" -D"NOMINMAX" -D"_WINDLL" -D"_UNICODE" -D"UNICODE") 24 | 25 | add_compile_options( 26 | /permissive- /GS /GL /W3 /Gy /Zc:wchar_t /Zi /Gm- /sdl /Zc:inline /fp:precise /errorReport:prompt /WX- 27 | /Zc:forScope /Gd /Oi /MD /std:c++17 /FC /EHsc /nologo /diagnostics:column 28 | ) 29 | 30 | add_link_options( 31 | /MANIFEST /LTCG:incremental /NXCOMPAT /DEBUG /DLL /MACHINE:X64 /OPT:REF /INCREMENTAL:NO /SUBSYSTEM:WINDOWS 32 | /MANIFESTUAC:NO /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /DELAYLOAD:"bedrock_server.dll" /TLBID:1 33 | ) 34 | 35 | add_library(TemplatePlugin SHARED ${SRC_FILES_DIR}) 36 | 37 | add_custom_command(TARGET TemplatePlugin PRE_BUILD 38 | COMMAND cmd /c ${PROJECT_SOURCE_DIR}/prepareLib.cmd ${PROJECT_SOURCE_DIR} 39 | COMMENT "Preparing Library" 40 | ) 41 | -------------------------------------------------------------------------------- /GOHelper/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # 默认忽略的文件 2 | /shelf/ 3 | /workspace.xml 4 | # 基于编辑器的 HTTP 客户端请求 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /GOHelper/.idea/.name: -------------------------------------------------------------------------------- 1 | png.go -------------------------------------------------------------------------------- /GOHelper/.idea/GOHelper.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /GOHelper/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /GOHelper/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /GOHelper/go.mod: -------------------------------------------------------------------------------- 1 | module GOHelper 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/df-mc/dragonfly v0.6.0 7 | github.com/shamsher31/goimgtype v1.0.0 8 | ) 9 | 10 | require github.com/shamsher31/goimgext v1.0.0 // indirect 11 | -------------------------------------------------------------------------------- /GOHelper/go.sum: -------------------------------------------------------------------------------- 1 | github.com/df-mc/dragonfly v0.6.0 h1:rqdIKtyK/y6byQwp9qtE6G++FPIEMWHQTWtuQW8e1Zk= 2 | github.com/df-mc/dragonfly v0.6.0/go.mod h1:Z41+mculxbyubTw4pU0spDUuvuLb9pSar2VQWQgp/jI= 3 | github.com/shamsher31/goimgext v1.0.0 h1:wFKf9GeeE0Xr6UQtliaPgYYgTju2izobM7XpCEgUCC8= 4 | github.com/shamsher31/goimgext v1.0.0/go.mod h1:rYLKgXuTGBIaH49z+jUVSWz7gUWIZmqvYUsdvJbNNOc= 5 | github.com/shamsher31/goimgtype v1.0.0 h1:7nmPz5GEb01sjFUojCbZJcBI68A8tmLXoCFbb5I34u4= 6 | github.com/shamsher31/goimgtype v1.0.0/go.mod h1:OZm3NZQDbK0ezlk9IV5oq3cWQwjF1oVSxKNx19bkf64= 7 | -------------------------------------------------------------------------------- /GOHelper/json.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type RootEntity struct { 4 | DownloadImg DownloadImgEntity `json:"DownloadImg"` 5 | ImgSize ImgSizeEntity `json:"ImgSize"` 6 | LocalImg LocalImgEntity `json:"LocalImg"` 7 | MemberRateLimit int64 `json:"MemberRateLimit"` 8 | } 9 | 10 | type DownloadImgEntity struct { 11 | AllowMember bool `json:"Allow-Member"` 12 | } 13 | 14 | type ImgSizeEntity struct { 15 | MaxFileSize int64 `json:"maxFileSize"` 16 | MaxHeight int64 `json:"maxHeight"` 17 | MaxWidth int64 `json:"maxWidth"` 18 | } 19 | 20 | type LocalImgEntity struct { 21 | AllowMember bool `json:"Allow-Member"` 22 | } 23 | -------------------------------------------------------------------------------- /GOHelper/png.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/binary" 5 | "encoding/json" 6 | "image" 7 | "image/jpeg" 8 | "image/png" 9 | "net/url" 10 | "os" 11 | "strconv" 12 | ) 13 | 14 | /* 15 | #include 16 | #include 17 | typedef struct { 18 | void* data; 19 | long long len; 20 | long long cap; 21 | } CgoSlice; 22 | #cgo LDFLAGS: -Wl,--allow-multiple-definition 23 | */ 24 | import "C" 25 | import ( 26 | "bytes" 27 | imgext "github.com/shamsher31/goimgext" 28 | _ "image/gif" 29 | "io" 30 | "io/ioutil" 31 | "net/http" 32 | "strings" 33 | ) 34 | 35 | //export png2PixelArr 36 | func png2PixelArr(paths string) C.CgoSlice { 37 | image.RegisterFormat("png", "png", png.Decode, png.DecodeConfig) 38 | image.RegisterFormat("jpeg", "jpeg", jpeg.Decode, jpeg.DecodeConfig) 39 | rr, err := os.Open(paths) 40 | if err != nil { 41 | var ret C.CgoSlice 42 | ret.data = nil 43 | ret.len = C.longlong(-1) 44 | ret.cap = C.longlong(0) 45 | return ret 46 | } 47 | defer rr.Close() 48 | img, _, err := image.Decode(rr) 49 | if err != nil { 50 | var ret C.CgoSlice 51 | ret.data = nil 52 | ret.len = C.longlong(-2) 53 | ret.cap = C.longlong(0) 54 | return ret 55 | } 56 | w, h := img.Bounds().Dx(), img.Bounds().Dy() 57 | data := make([]byte, 0, w*h*4) 58 | for y := 0; y < h; y++ { 59 | for x := 0; x < w; x++ { 60 | r, g, b, a := img.At(x, y).RGBA() 61 | data = append(data, byte(r>>8), byte(g>>8), byte(b>>8), byte(a>>8)) 62 | } 63 | } 64 | out := []byte(strconv.Itoa(w)) 65 | out = append(out, []byte{'\n'}...) 66 | out = append(out, strconv.Itoa(h)...) 67 | out = append(out, []byte{'\n'}...) 68 | out = append(out, data...) 69 | 70 | var ret C.CgoSlice 71 | ret.data = C.CBytes(out) 72 | ret.len = C.longlong(len(out)) 73 | ret.cap = C.longlong(len(out)) 74 | 75 | return ret 76 | } 77 | 78 | func IntToBytes(n int) []byte { 79 | x := int32(n) 80 | bytesBuffer := bytes.NewBuffer([]byte{}) 81 | binary.Write(bytesBuffer, binary.BigEndian, x) 82 | return bytesBuffer.Bytes() 83 | } 84 | 85 | func isURL(urls string) bool { 86 | _, err := url.ParseRequestURI(urls) 87 | if err != nil { 88 | return false 89 | } 90 | return true 91 | } 92 | 93 | func ReadConfig() (int64, int64, int64) { 94 | data, err := ioutil.ReadFile("plugins\\CustomMapX\\config.json") 95 | if err != nil { 96 | return 0, 0, 0 97 | } 98 | var root RootEntity 99 | err = json.Unmarshal(data, &root) 100 | if err != nil { 101 | return 0, 0, 0 102 | } 103 | return root.ImgSize.MaxWidth, root.ImgSize.MaxHeight, root.ImgSize.MaxFileSize 104 | } 105 | 106 | //export getUrlPngData 107 | func getUrlPngData(url string) C.CgoSlice { 108 | image.RegisterFormat("png", "png", png.Decode, png.DecodeConfig) 109 | image.RegisterFormat("jpeg", "jpeg", jpeg.Decode, jpeg.DecodeConfig) 110 | if isURL(url) { 111 | header, err := http.Head(url) 112 | if err != nil { 113 | var ret C.CgoSlice 114 | ret.data = nil 115 | ret.len = C.longlong(-4) 116 | ret.cap = C.longlong(0) 117 | return ret 118 | } 119 | maxw, maxh, maxsize := ReadConfig() 120 | length := float64(header.ContentLength) / 1024 / 1024 121 | if length > float64(maxsize) { 122 | var ret C.CgoSlice 123 | ret.data = nil 124 | ret.len = C.longlong(-6) 125 | ret.cap = C.longlong(0) 126 | return ret 127 | } 128 | if length != 0 { 129 | resp, err := http.Get(url) 130 | defer resp.Body.Close() 131 | if err != nil { 132 | var ret C.CgoSlice 133 | ret.data = nil 134 | ret.len = C.longlong(-1) 135 | ret.cap = C.longlong(0) 136 | return ret 137 | } 138 | allbody, err := ioutil.ReadAll(resp.Body) 139 | if err != nil { 140 | var ret C.CgoSlice 141 | ret.data = nil 142 | ret.len = C.longlong(-1) 143 | ret.cap = C.longlong(0) 144 | return ret 145 | } 146 | imgtype := GetImageType(ioutil.NopCloser(bytes.NewReader(allbody))) 147 | if imgtype != "" { 148 | if err != nil { 149 | var ret C.CgoSlice 150 | ret.data = nil 151 | ret.len = C.longlong(-3) 152 | ret.cap = C.longlong(0) 153 | return ret 154 | } 155 | img, _, err := image.Decode(ioutil.NopCloser(bytes.NewReader(allbody))) 156 | if err != nil { 157 | var ret C.CgoSlice 158 | ret.data = nil 159 | ret.len = C.longlong(-5) 160 | ret.cap = C.longlong(0) 161 | return ret 162 | } 163 | w, h := img.Bounds().Dx(), img.Bounds().Dy() 164 | if int64(w) > maxw || int64(h) > maxh { 165 | var ret C.CgoSlice 166 | ret.data = nil 167 | ret.len = C.longlong(-2) 168 | ret.cap = C.longlong(0) 169 | return ret 170 | } 171 | data := make([]byte, 0, w*h*4) 172 | for y := 0; y < h; y++ { 173 | for x := 0; x < w; x++ { 174 | r, g, b, a := img.At(x, y).RGBA() 175 | data = append(data, byte(r>>8), byte(g>>8), byte(b>>8), byte(a>>8)) 176 | } 177 | } 178 | out := []byte(strconv.Itoa(w)) 179 | out = append(out, []byte{'\n'}...) 180 | out = append(out, strconv.Itoa(h)...) 181 | out = append(out, []byte{'\n'}...) 182 | out = append(out, data...) 183 | 184 | var ret C.CgoSlice 185 | ret.data = C.CBytes(out) 186 | ret.len = C.longlong(len(out)) 187 | ret.cap = C.longlong(len(out)) 188 | 189 | return ret 190 | } 191 | } 192 | } 193 | var ret C.CgoSlice 194 | ret.data = nil 195 | ret.len = C.longlong(-1) 196 | ret.cap = C.longlong(0) 197 | return ret 198 | } 199 | 200 | func GetImageType(reader io.ReadCloser) string { 201 | buff := make([]byte, 512) 202 | _, err := reader.Read(buff) 203 | if err != nil { 204 | return "" 205 | } 206 | filetype := http.DetectContentType(buff) 207 | ext := imgext.Get() 208 | for i := 0; i < len(ext); i++ { 209 | if strings.Contains(ext[i], filetype[6:len(filetype)]) { 210 | return filetype 211 | } 212 | } 213 | return "" 214 | } 215 | 216 | func main() { 217 | 218 | } 219 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CustomMapX 2 | 3 | `CustomMapX` A plugin for customizing map images. 4 | 5 | ### How to use? 6 | - You need to put your picture into `plugins\CustomMapX\picture` 7 | - Then type `/map add ` in the server 8 | 9 | - If you add images after the server has been start, you will need `/map reload`, to refresh the image list. 10 | 11 | - You can get help with `/map help` 12 | 13 | show 14 | 15 | ### ⚠️ Warning 16 | 17 | Please do not reproduce without permission, integration! This may keep it from ever being updated 18 | 19 | #### Extra Restrictions & Exceptions 20 | 21 | You can't distribute, integrate, etc. without my authorized permission 22 | -------------------------------------------------------------------------------- /Template.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Template", "Template\Template.vcxproj", "{ABEB5558-C92F-473E-8BDF-90F58BD3811C}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Release|x64 = Release|x64 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {ABEB5558-C92F-473E-8BDF-90F58BD3811C}.Release|x64.ActiveCfg = Release|x64 14 | {ABEB5558-C92F-473E-8BDF-90F58BD3811C}.Release|x64.Build.0 = Release|x64 15 | EndGlobalSection 16 | GlobalSection(SolutionProperties) = preSolution 17 | HideSolutionNode = FALSE 18 | EndGlobalSection 19 | GlobalSection(ExtensibilityGlobals) = postSolution 20 | SolutionGuid = {9F46E45F-CD85-4250-93FD-0DD973FB8ECF} 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /Template/GoLang.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "godef.h" 3 | 4 | namespace GolangFunc { 5 | namespace FuncDef { 6 | typedef GoSlice (*png2PixelArr)(GoString); 7 | typedef GoSlice(*getUrlPngData)(GoString); 8 | } // namespace FuncDef 9 | FuncDef::png2PixelArr png2PixelArr; 10 | FuncDef::getUrlPngData getUrlPngData; 11 | } // namespace GolangFunc -------------------------------------------------------------------------------- /Template/Plugin.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "Version.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include "Setting.h" 24 | std::unordered_map tempList; 25 | 26 | int MapIndex; 27 | 28 | Logger logger(PLUGIN_NAME); 29 | 30 | inline void getAllFiles(std::string strPath, std::vector& vecFiles) 31 | { 32 | char cEnd = *strPath.rbegin(); 33 | if (cEnd == '\\' || cEnd == '/') 34 | { 35 | strPath = strPath.substr(0, strPath.length() - 1); 36 | } 37 | if (strPath.empty() || strPath == (".") || strPath == ("..")) 38 | return; 39 | std::error_code ec; 40 | std::filesystem::path fsPath(strPath); 41 | if (!std::filesystem::exists(strPath, ec)) { 42 | return; 43 | } 44 | for (auto& itr : std::filesystem::directory_iterator(fsPath)) 45 | { 46 | if (std::filesystem::is_directory(itr.status())) 47 | { 48 | getAllFiles(UTF82String(itr.path().u8string()), vecFiles); 49 | } 50 | else 51 | { 52 | vecFiles.push_back(UTF82String(itr.path().filename().u8string())); 53 | } 54 | } 55 | } 56 | 57 | time_t getTimeStamp() 58 | { 59 | std::chrono::time_point tp = std::chrono::time_point_cast(std::chrono::system_clock::now()); 60 | auto tmp = std::chrono::duration_cast(tp.time_since_epoch()); 61 | std::time_t timestamp = tmp.count(); 62 | return timestamp; 63 | } 64 | time_t getTimeStamp2() 65 | { 66 | std::chrono::time_point tp = std::chrono::time_point_cast(std::chrono::system_clock::now()); 67 | auto tmp = std::chrono::duration_cast(tp.time_since_epoch()); 68 | std::time_t timestamp = tmp.count(); 69 | return timestamp; 70 | } 71 | 72 | 73 | std::mutex mtx; 74 | #include 75 | std::tuple, unsigned, unsigned,string> isChange = std::make_tuple(false, std::vector(), 0, 0,""); 76 | 77 | 78 | namespace mce{ 79 | 80 | class Blob { 81 | public: 82 | void* unk0; 83 | std::unique_ptr buffer; 84 | size_t length = 0; 85 | 86 | 87 | inline Blob() {} 88 | inline Blob(Blob&& rhs) : buffer(std::move(rhs.buffer)), length(rhs.length) { rhs.length = 0; } 89 | inline Blob(size_t input_length) : buffer(std::make_unique(input_length)), length(input_length) {} 90 | inline Blob(unsigned char const* input, size_t input_length) : Blob(input_length) { 91 | memcpy(buffer.get(), input, input_length); 92 | } 93 | 94 | inline Blob& operator=(Blob&& rhs) { 95 | if (&rhs != this) { 96 | buffer = std::move(rhs.buffer); 97 | length = rhs.length; 98 | rhs.length = 0; 99 | } 100 | return *this; 101 | } 102 | 103 | inline Blob clone() const { return { data(), size() }; } 104 | 105 | inline unsigned char* begin() { return buffer.get(); } 106 | inline unsigned char* end() { return buffer.get() + length; } 107 | inline unsigned char const* cbegin() const { return buffer.get(); } 108 | inline unsigned char const* cend() const { return buffer.get() + length; } 109 | 110 | inline unsigned char* data() { return buffer.get(); } 111 | inline unsigned char const* data() const { return buffer.get(); } 112 | 113 | inline bool empty() const { return length == 0; } 114 | inline size_t size() const { return length; } 115 | 116 | inline auto getSpan() const { return gsl::make_span(data(), size()); } 117 | 118 | }; 119 | 120 | static_assert(sizeof(Blob) == 24); 121 | 122 | enum class ImageFormat { 123 | NONE = 0, 124 | RGB = 1, 125 | RGBA = 2 126 | }; 127 | 128 | enum class ImageUsage : int8_t { 129 | unknown = 0, 130 | sRGB = 1, 131 | data = 2 132 | }; 133 | 134 | inline unsigned numChannels(ImageFormat format) { 135 | switch (format) { 136 | case ImageFormat::RGB: return 3; 137 | case ImageFormat::RGBA: return 4; 138 | default: return 0; 139 | } 140 | } 141 | 142 | class Image { 143 | inline Image(ImageFormat format, unsigned width, unsigned height, ImageUsage usage, Blob&& data) 144 | : format(format), width(width), height(height), usage(usage), data(std::move(data)) {} 145 | 146 | public: 147 | ImageFormat format{}; // 0x0 148 | unsigned width{}, height{}; // 0x4, 0x8 149 | ImageUsage usage{}; // 0xC 150 | Blob data; // 0x10 151 | 152 | inline Image(Blob&& data) : data(std::move(data)) {} 153 | inline Image(unsigned width, unsigned height, ImageFormat format, ImageUsage usage) 154 | : format(format), width(width), height(height), usage(usage) {} 155 | inline Image() {} 156 | 157 | inline Image& operator=(Image&& rhs) { 158 | format = rhs.format; 159 | width = rhs.width; 160 | height = rhs.height; 161 | usage = rhs.usage; 162 | data = std::move(rhs.data); 163 | return *this; 164 | } 165 | 166 | inline Image clone() const { return { format, width, height, usage, data.clone() }; } 167 | 168 | inline void copyRawImage(Blob const& blob) { data = blob.clone(); } 169 | 170 | inline bool isEmpty() const { return data.empty(); } 171 | 172 | inline void resizeImageBytesToFitImageDescription() { data = Blob{ width * height * numChannels(format) }; } 173 | 174 | inline void setImageDescription(unsigned width, unsigned height, ImageFormat format, ImageUsage usage) { 175 | this->width = width; 176 | this->height = height; 177 | this->format = format; 178 | this->usage = usage; 179 | } 180 | 181 | inline void setRawImage(Blob&& buffer) { data = std::move(buffer); } 182 | 183 | Image(const Image& a1) { 184 | format = a1.format; 185 | width = a1.width; 186 | height = a1.height; 187 | usage = a1.usage; 188 | data = a1.data.clone(); 189 | } 190 | }; 191 | 192 | static_assert(offsetof(Image, data) == 0x10); 193 | static_assert(offsetof(Image, format) == 0x0); 194 | static_assert(offsetof(Image, usage) == 0xC); 195 | static_assert(sizeof(Image) == 40); 196 | 197 | 198 | }; // namespace mce 199 | 200 | class Image2D { 201 | public: 202 | vector rawColor; 203 | 204 | unsigned width = 0, height = 0; 205 | 206 | Image2D(unsigned w, unsigned h, vector c) : width(w), height(h), rawColor(c) {}; 207 | }; 208 | extern HMODULE DllMainPtr; 209 | //#include"MemoryModule.h" 210 | #include "GoLang.hpp" 211 | void golang() { 212 | //HRSRC DLL = ::FindResource(DllMainPtr, MAKEINTRESOURCE(4), L"DLL"); 213 | //DWORD ResSize = ::SizeofResource(DllMainPtr, DLL); 214 | //HGLOBAL ResData = ::LoadResource(DllMainPtr, DLL); 215 | //void* ResDataRef = ::LockResource(ResData); 216 | //HMEMORYMODULE lib = MemoryLoadLibrary(ResDataRef, ResSize); 217 | //if (lib) { 218 | // GolangFunc::png2PixelArr = (GolangFunc::FuncDef::png2PixelArr)MemoryGetProcAddress(lib, "png2PixelArr"); 219 | // GolangFunc::getUrlPngData = (GolangFunc::FuncDef::getUrlPngData)MemoryGetProcAddress(lib, "getUrlPngData"); 220 | //} 221 | //else { 222 | // Logger("CustomNpcModule").warn("Failed to load MAP_SubModule"); 223 | //} 224 | 225 | if (std::filesystem::exists("plugins/lib/MAP_Golang_Module.dll")) { 226 | auto lib = LoadLibrary(L"plugins/lib/MAP_Golang_Module.dll"); 227 | if (lib) { 228 | GolangFunc::png2PixelArr = (GolangFunc::FuncDef::png2PixelArr)GetProcAddress(lib, "png2PixelArr"); 229 | GolangFunc::getUrlPngData = (GolangFunc::FuncDef::getUrlPngData)GetProcAddress(lib, "getUrlPngData"); 230 | } 231 | else { 232 | logger.error("Failed to load MAP_SubModule"); 233 | } 234 | } 235 | else { 236 | logger.error("Failed to load MAP_SubModule"); 237 | } 238 | } 239 | namespace Helper { 240 | vector split(char* a1) { 241 | vector result; 242 | char* a2 = a1; 243 | int a3 = 0; 244 | while (*a2) { 245 | if (a3 < 2) { 246 | if (*a2 == '\n') { 247 | *a2 = 0; 248 | a3++; 249 | result.push_back(a1); 250 | a1 = a2 + 1; 251 | } 252 | } 253 | a2++; 254 | } 255 | result.push_back(a1); 256 | return result; 257 | } 258 | 259 | const std::tuple, unsigned, unsigned> Png2Pix(string path,ServerPlayer* pl) { 260 | GoString paths{ path.c_str(),(int64_t)path.size() }; 261 | auto imagedata = GolangFunc::png2PixelArr(paths); 262 | auto data = imagedata.data(); 263 | if (pl) { 264 | switch (imagedata.length()) 265 | { 266 | case -1: { 267 | pl->sendText("§l§6[CustomMapX] §cImage does not exist!"); 268 | return std::make_tuple(std::vector(), 0, 0); 269 | } 270 | case -2: { 271 | pl->sendText("§l§6[CustomMapX] §cImage decoding failure!"); 272 | return std::make_tuple(std::vector(), 0, 0); 273 | } 274 | } 275 | } 276 | if (imagedata.length() != 0 && data != nullptr) { 277 | auto out = split(data); 278 | if (out.size() == 3) { 279 | int w = atoi(out[0]); 280 | int h = atoi(out[1]); 281 | std::vector image; 282 | image.resize(w * h * 4); 283 | memcpy(image.data(), (void*)out[2], w * h * 4); 284 | if (!pl->isOP()) 285 | tempList[pl->getRealName()] = getTimeStamp(); 286 | return std::make_tuple(image, w, h); 287 | } 288 | } 289 | return std::make_tuple(std::vector(), 0, 0); 290 | } 291 | 292 | void Url2Pix(string url,string plname) { 293 | try { 294 | GoString urls{ url.c_str(),(int64_t)url.size() }; 295 | auto imagedata = GolangFunc::getUrlPngData(urls); 296 | auto data = imagedata.data(); 297 | auto pl = Global->getPlayer(plname); 298 | if (pl) { 299 | switch (imagedata.length()) 300 | { 301 | case -1: { 302 | pl->sendText("§l§6[CustomMapX] §cURL is not legal!"); 303 | return; 304 | } 305 | case -2: { 306 | pl->sendText("§l§6[CustomMapX] §cImage out of size!"); 307 | return; 308 | } 309 | case -3: { 310 | pl->sendText("§l§6[CustomMapX] §cURL is not a Image!"); 311 | return; 312 | } 313 | case -4: { 314 | pl->sendText("§l§6[CustomMapX] §cURL Access failure!"); 315 | return; 316 | } 317 | case -5: { 318 | pl->sendText("§l§6[CustomMapX] §cImage decoding failure!"); 319 | } 320 | case -6: { 321 | pl->sendText("§l§6[CustomMapX] §cImage exceeds maximum allowed size!"); 322 | } 323 | } 324 | } 325 | if (imagedata.length() > 0 && data != nullptr) { 326 | auto out = split(data); 327 | if (out.size() == 3) { 328 | int w = atoi(out[0]); 329 | int h = atoi(out[1]); 330 | std::vector image; 331 | image.resize(w * h * 4); 332 | memcpy(image.data(), (void*)out[2], w * h * 4); 333 | isChange = std::make_tuple(true, image, w, h, plname); 334 | if(!pl->isOP()) 335 | tempList[plname] = getTimeStamp(); 336 | return; 337 | } 338 | } 339 | isChange = std::make_tuple(false, std::vector(), 0, 0, ""); 340 | if (pl) { 341 | pl->sendText("§l§6[CustomMapX] §cAdd Map Error!"); 342 | } 343 | return; 344 | } 345 | catch (...) { 346 | auto pl = Global->getPlayer(plname); 347 | if (pl) { 348 | isChange = std::make_tuple(false, std::vector(), 0, 0, ""); 349 | pl->sendText("§l§6[CustomMapX] §cAdd Map Error!"); 350 | } 351 | } 352 | } 353 | 354 | vector CuttingImages(std::vector image, int width, int height) { 355 | vector images; 356 | auto wcut = width / 128; 357 | auto hcut = height / 128; 358 | if (width % 128 != 0) { 359 | wcut++; 360 | } 361 | 362 | if (height % 128 != 0) { 363 | hcut++; 364 | } 365 | for (auto h = 0; h < hcut; h++) { 366 | for (auto w = 0; w < wcut; w++) { 367 | vector img; 368 | for (auto a = h * 128; a < h * 128 + 128; a++) { 369 | for (auto b = w * 128; b < w * 128 + 128; b++) { 370 | if (a * width + b < image.size() && b * height + a < image.size()) { 371 | img.push_back(image[a * width + b]); 372 | } 373 | else { 374 | img.push_back(mce::Color(0xff, 0xff, 0xff, 0)); 375 | } 376 | } 377 | } 378 | images.push_back(Image2D(128, 128, img)); 379 | } 380 | } 381 | return images; 382 | } 383 | 384 | void createImg(std::vector data, unsigned w, unsigned h, ServerPlayer* sp, string picfile) { 385 | if (data.size() == 0) return; 386 | vector Colorlist; 387 | for (int y = 0; y < h; y++) 388 | { 389 | for (int x = 0; x < w; x++) 390 | { 391 | mce::Color img((float)data[(y * w + x) * 4 + 0] / 255, (float)data[(y * w + x) * 4 + 1] / 255, (float)data[(y * w + x) * 4 + 2] / 255, (float)data[(y * w + x) * 4 + 3] / 255); 392 | Colorlist.push_back(img); 393 | } 394 | } 395 | auto datalist = Helper::CuttingImages(Colorlist, w, h); 396 | int xtemp = 0; 397 | int ytemp = 0; 398 | for (auto data : datalist) { 399 | auto mapitem = ItemStack::create("minecraft:filled_map"); 400 | //auto MapIndex = sp->getMapIndex(); 401 | //sp->setMapIndex(MapIndex + 1); 402 | MapIndex++; 403 | MapItem::setMapNameIndex(*mapitem, MapIndex); 404 | auto& mapdate = Global->_createMapSavedData(MapIndex); 405 | mapdate.setLocked(); 406 | for (int x = 0; x < 128; x++) { 407 | for (int y = 0; y < 128; y++) { 408 | mapdate.setPixel(data.rawColor[y + x * 128].toABGR(), y, x); 409 | } 410 | } 411 | mapdate.save(*Global); 412 | MapItem::setItemInstanceInfo(*mapitem, mapdate); 413 | auto sizetest = sqrt(datalist.size()); 414 | mapitem->setCustomName(picfile + "-" + std::to_string(xtemp) + "_" + std::to_string(ytemp)); 415 | Spawner* sps = &Global->getSpawner(); 416 | ItemActor* ac = sps->spawnItem(sp->getRegion(), *mapitem, nullptr, sp->getPos(), 0); 417 | delete mapitem; 418 | ytemp++; 419 | if (ytemp == sizetest) { 420 | xtemp++; 421 | ytemp = 0; 422 | } 423 | } 424 | sp->sendText("§l§6[CustomMapX] §aAdd Map Success!(" + std::to_string(datalist.size()) + ")"); 425 | } 426 | 427 | string rand_str(const int len) 428 | { 429 | string str; 430 | char c; 431 | int idx; 432 | for (idx = 0; idx < len; idx++) 433 | { 434 | c = 'a' + rand() % 26; 435 | str.push_back(c); 436 | } 437 | return str; 438 | } 439 | } 440 | 441 | void Change() { 442 | Schedule::repeat([] { 443 | auto [isChnage, data, w,h,plname] = isChange; 444 | if (isChnage) { 445 | isChange = std::make_tuple(false, std::vector(), 0, 0,""); 446 | auto sp = Global->getPlayer(plname); 447 | if (sp->isPlayer()) { 448 | Helper::createImg(data, w, h, (ServerPlayer*)sp, Helper::rand_str(5)); 449 | } 450 | } 451 | }, 20); 452 | } 453 | 454 | 455 | void RegCommand() 456 | { 457 | using ParamType = DynamicCommand::ParameterType; 458 | 459 | vector out; 460 | getAllFiles(".\\plugins\\CustomMapX\\picture", out); 461 | 462 | auto command = DynamicCommand::createCommand("map", "CustomMapX", CommandPermissionLevel::Any); 463 | auto& MapReloadEnum = command->setEnum("MapReloadEnum", { "reload" }); 464 | auto& MaphelpEnum = command->setEnum("MaphelpEnum", {"help" }); 465 | auto& MapAddEnum = command->setEnum("MapAddEnum", { "add"}); 466 | auto& MapUrlEnum = command->setEnum("MapUrlEnum", { "download" }); 467 | 468 | command->mandatory("MapsEnum", ParamType::Enum, MaphelpEnum, CommandParameterOption::EnumAutocompleteExpansion); 469 | command->mandatory("MapsEnum", ParamType::Enum, MapAddEnum, CommandParameterOption::EnumAutocompleteExpansion); 470 | command->mandatory("MapsEnum", ParamType::Enum, MapUrlEnum, CommandParameterOption::EnumAutocompleteExpansion); 471 | command->mandatory("MapsEnum", ParamType::Enum, MapReloadEnum, CommandParameterOption::EnumAutocompleteExpansion); 472 | command->mandatory("MapSoftEnum", ParamType::SoftEnum, command->setSoftEnum("MapENameList", out)); 473 | command->mandatory("UrlStr", ParamType::String); 474 | 475 | command->addOverload({ MapAddEnum,"MapSoftEnum"}); 476 | command->addOverload({ MaphelpEnum }); 477 | command->addOverload({ MapReloadEnum }); 478 | command->addOverload({ MapUrlEnum, "UrlStr"}); 479 | 480 | command->setCallback([](DynamicCommand const& command, CommandOrigin const& origin, CommandOutput& output, std::unordered_map& results) { 481 | auto action = results["MapsEnum"].get(); 482 | string str = ""; 483 | ServerPlayer* sp = origin.getPlayer(); 484 | switch (do_hash(action.c_str())) 485 | { 486 | case do_hash("add"): { 487 | if (sp) { 488 | if (tempList.find(sp->getRealName()) == tempList.end()) { 489 | if (sp->isOP() || Settings::LocalImg::allowmember) { 490 | auto picfile = results["MapSoftEnum"].get(); 491 | if (!picfile.empty()) { 492 | auto [data, w, h] = Helper::Png2Pix(".\\plugins\\CustomMapX\\picture\\" + picfile, sp); 493 | Helper::createImg(data, w, h, sp, picfile); 494 | } 495 | } 496 | else { 497 | sp->sendText("§l§6[CustomMapX] §cYou are not allowed to add img map!"); 498 | } 499 | } 500 | else { 501 | sp->sendText("§l§6[CustomMapX] §cFrequent operation, please try again later!\n§gRemaining time:" + std::to_string(Settings::memberRateLimit - ((getTimeStamp() - tempList[sp->getRealName()]) / 1000)) + "s"); 502 | } 503 | } 504 | break; 505 | } 506 | case do_hash("download"): { 507 | if (sp) { 508 | if (tempList.find(sp->getRealName()) == tempList.end()) { 509 | if (sp->isOP() || Settings::DownloadImg::allowmember) { 510 | auto url = results["UrlStr"].getRaw(); 511 | std::thread th(Helper::Url2Pix, url, sp->getRealName()); 512 | th.detach(); 513 | output.success("§l§6[CustomMapX] §aGenerating, please wait!"); 514 | } 515 | else { 516 | sp->sendText("§l§6[CustomMapX] §cYou are not allowed to download img map!"); 517 | } 518 | } 519 | else { 520 | sp->sendText("§l§6[CustomMapX] §cFrequent operation, please try again later!\n§gRemaining time:" + std::to_string(Settings::memberRateLimit - ((getTimeStamp() - tempList[sp->getRealName()]) / 1000)) + "s"); 521 | } 522 | } 523 | break; 524 | } 525 | case do_hash("reload"): { 526 | if ((int)origin.getPermissionsLevel() > 0) { 527 | vector out; 528 | getAllFiles(".\\plugins\\CustomMapX\\picture", out); 529 | command.getInstance()->addSoftEnumValues("MapENameList", out); 530 | Settings::LoadConfigFromJson(JsonFile); 531 | output.success("§l§6[CustomMapX] §aReload Success!"); 532 | } 533 | break; 534 | } 535 | case do_hash("help"): { 536 | output.success( 537 | "§l§e>§6CustomMapX§e<\n" 538 | "§b/map add §a §gAdd maps\n" 539 | "§b/map download §a §gDownload maps\n" 540 | "§b/map reload §gRefresh picture path\n" 541 | "§b/map help\n" 542 | "§l§e>§6CustomMapX§e<"); 543 | break; 544 | } 545 | default: 546 | break; 547 | } 548 | }); 549 | DynamicCommand::setup(std::move(command)); 550 | } 551 | 552 | void Sche() { 553 | Schedule::repeat([] { 554 | if (tempList.size() > 0) { 555 | auto nowtime = getTimeStamp(); 556 | for (auto& [name, time] : tempList) { 557 | if (nowtime - time > Settings::memberRateLimit * 1000) { 558 | tempList.erase(name); 559 | } 560 | } 561 | } 562 | }, 20); 563 | } 564 | 565 | 566 | void loadCfg() { 567 | //config 568 | if (!std::filesystem::exists("plugins/CustomMapX")) 569 | std::filesystem::create_directories("plugins/CustomMapX"); 570 | if (std::filesystem::exists(JsonFile)) { 571 | try { 572 | Settings::LoadConfigFromJson(JsonFile); 573 | } 574 | catch (std::exception& e) { 575 | logger.error("Config File isInvalid, Err {}", e.what()); 576 | //Sleep(1000 * 100); 577 | exit(1); 578 | } 579 | catch (...) { 580 | logger.error("Config File isInvalid"); 581 | //Sleep(1000 * 100); 582 | exit(1); 583 | } 584 | } 585 | else { 586 | logger.info("Config with default values created"); 587 | Settings::WriteDefaultConfig(JsonFile); 588 | } 589 | } 590 | 591 | 592 | void PluginInit() 593 | { 594 | srand(NULL); 595 | MapIndex = getTimeStamp2()/rand()* getTimeStamp2(); 596 | loadCfg(); 597 | golang(); 598 | Logger().info(" ___ _ _____ __ "); 599 | Logger().info(" / __\\/\\/\\ /_\\ / _ \\ \\/ / "); 600 | Logger().info(" / / / \\ //_\\\\ / /_)/\\ / \033[38;5;221mVersion:{}", PLUGIN_VERSION_STRING); 601 | Logger().info("/ /__/ /\\/\\ \\/ _ \\/ ___/ / \\ \033[38;5;218mGithub:{}", "https://github.com/dreamguxiang/CustomMapX"); 602 | Logger().info("\\____|/ \\/\\_/ \\_/\\/ /_/\\_\\ "); 603 | Logger().info(""); 604 | if (!std::filesystem::exists("plugins/CustomMapX")) 605 | std::filesystem::create_directories("plugins/CustomMapX"); 606 | if (!std::filesystem::exists("plugins/CustomMapX/picture")) 607 | std::filesystem::create_directories("plugins/CustomMapX/picture"); 608 | RegCommand(); 609 | Event::ServerStartedEvent::subscribe([] (const Event::ServerStartedEvent& ev) { 610 | Change(); 611 | Sche(); 612 | return true; 613 | }); 614 | } 615 | 616 | inline vector split(string a1,char a) { 617 | vector out; 618 | std::stringstream ss(a1); 619 | string temp; 620 | while (getline(ss, temp, a)) { 621 | out.push_back(temp); 622 | } 623 | return out; 624 | } 625 | 626 | 627 | bool isNextImage1(string name,string newname) { 628 | 629 | auto oldoutlist = split(name,'-'); 630 | auto newoutlist = split(newname, '-'); 631 | if (oldoutlist.empty() || newoutlist.empty()) return false; 632 | if (newname.find(oldoutlist[0]) != newname.npos) { 633 | auto oldnumlist = split(oldoutlist[1], '_'); 634 | auto newnumlist = split(newoutlist[1], '_'); 635 | 636 | auto oldfir = atoi(oldnumlist[0].c_str()); 637 | auto oldsec = atoi(oldnumlist[1].c_str()); 638 | 639 | auto newfir = atoi(newnumlist[0].c_str()); 640 | auto newsec = atoi(newnumlist[1].c_str()); 641 | if (oldsec + 1 == newsec) { 642 | if (oldfir == newfir) { 643 | return true; 644 | } 645 | } 646 | } 647 | return false; 648 | } 649 | 650 | bool isNextImage2(string name, string newname) { 651 | 652 | auto oldoutlist = split(name, '-'); 653 | auto newoutlist = split(newname, '-'); 654 | if (oldoutlist.empty() || newoutlist.empty()) return false; 655 | if (newname.find(oldoutlist[0]) != newname.npos) { 656 | auto oldnumlist = split(oldoutlist[1], '_'); 657 | auto newnumlist = split(newoutlist[1], '_'); 658 | 659 | auto oldfir = atoi(oldnumlist[0].c_str()); 660 | auto oldsec = atoi(oldnumlist[1].c_str()); 661 | 662 | auto newfir = atoi(newnumlist[0].c_str()); 663 | auto newsec = atoi(newnumlist[1].c_str()); 664 | if(oldfir+1 == newfir) { 665 | if (newsec == 0) { 666 | return true; 667 | } 668 | } 669 | } 670 | return false; 671 | } 672 | 673 | bool UseItemSupply(Player* sp, ItemStackBase& item, string itemname, short aux) { 674 | auto& plinv = sp->getSupplies(); 675 | auto slotnum = dAccess(&plinv); 676 | auto& uid = sp->getUniqueID(); 677 | if (item.getCount() == 0) { 678 | auto& inv = sp->getInventory(); 679 | bool isgive = 0; 680 | for (int i = 0; i <= inv.getSize(); i++) { 681 | auto& item = inv.getItem(i); 682 | if (!item.isNull()) { 683 | if (item.getItem()->getSerializedName() == "minecraft:filled_map") { 684 | if (i == slotnum) continue; 685 | bool isgive = 0; 686 | if (isNextImage1(itemname, item.getCustomName())) { 687 | isgive = 1; 688 | } 689 | if (isgive) { 690 | auto snbt = const_cast(&item)->getNbt()->toBinaryNBT(); 691 | Schedule::delay([snbt, uid, slotnum, i] { 692 | auto newitem = ItemStack::create(CompoundTag::fromBinaryNBT(snbt)); 693 | auto sp = Global->getPlayer(uid); 694 | if (sp) { 695 | if (sp->getHandSlot()->isNull()) { 696 | auto& inv = sp->getInventory(); 697 | inv.setItem(i, ItemStack::EMPTY_ITEM); 698 | auto& plinv = sp->getSupplies(); 699 | inv.setItem(slotnum, *newitem); 700 | sp->refreshInventory(); 701 | } 702 | } 703 | delete newitem; 704 | }, 1); 705 | } 706 | 707 | } 708 | } 709 | } 710 | Schedule::delay([isgive, uid, slotnum, itemname] { 711 | auto sp = Global->getPlayer(uid); 712 | auto& inv = sp->getInventory(); 713 | if (!isgive) { 714 | for (int i = 0; i <= inv.getSize(); i++) { 715 | auto& item = inv.getItem(i); 716 | if (!item.isNull()) { 717 | if (item.getItem()->getSerializedName() == "minecraft:filled_map") { 718 | 719 | if (i == slotnum) continue; 720 | bool isgive2 = 0; 721 | if (isNextImage2(itemname, item.getCustomName())) { 722 | isgive2 = 1; 723 | } 724 | if (isgive2) { 725 | auto snbt = const_cast(&item)->getNbt()->toBinaryNBT(); 726 | auto& uid = sp->getUniqueID(); 727 | Schedule::delay([snbt, uid, slotnum, i] { 728 | auto newitem = ItemStack::create(CompoundTag::fromBinaryNBT(snbt)); 729 | auto sp = Global->getPlayer(uid); 730 | if (sp) { 731 | if (sp->getHandSlot()->isNull()) { 732 | auto& inv = sp->getInventory(); 733 | inv.setItem(i, ItemStack::EMPTY_ITEM); 734 | auto& plinv = sp->getSupplies(); 735 | inv.setItem(slotnum, *newitem); 736 | sp->refreshInventory(); 737 | } 738 | } 739 | delete newitem; 740 | }, 1); 741 | } 742 | 743 | } 744 | } 745 | } 746 | } 747 | },1); 748 | } 749 | } 750 | 751 | 752 | TInstanceHook(void, "?useItem@Player@@UEAAXAEAVItemStackBase@@W4ItemUseMethod@@_N@Z", Player, ItemStackBase& item, int a2, bool a3) 753 | { 754 | auto itemname = item.getCustomName(); 755 | auto itemname2 = item.getItem()->getSerializedName(); 756 | auto aux = item.getAuxValue(); 757 | original(this, item, a2, a3); 758 | try { 759 | if (itemname2 == "minecraft:filled_map") { 760 | UseItemSupply(this, item, itemname, aux); 761 | } 762 | } 763 | catch (...) { 764 | return; 765 | } 766 | } 767 | 768 | -------------------------------------------------------------------------------- /Template/Resource.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dreamguxiang/CustomMapX/3b1a585adb6786e0c0b136e6861c3a962f050b05/Template/Resource.rc -------------------------------------------------------------------------------- /Template/Setting.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define JSON2(key1,key2,val) \ 5 | if (json.find(key1) != json.end()) { \ 6 | if (json.at(key1).find(key2) != json.at(key1).end()) {\ 7 | const nlohmann::json& out2 = json.at(key1).at(key2); \ 8 | out2.get_to(val);}} \ 9 | 10 | #define JSON1(key,val) \ 11 | if (json.find(key) != json.end()) { \ 12 | const nlohmann::json& out = json.at(key); \ 13 | out.get_to(val);} \ 14 | 15 | namespace Settings { 16 | 17 | int memberRateLimit = 60; 18 | namespace DownloadImg { 19 | bool allowmember = false; 20 | } 21 | namespace LocalImg { 22 | bool allowmember = false; 23 | } 24 | namespace ImgSize { 25 | int maxWidth = 1408; 26 | int maxHeight = 1408; 27 | int maxFileSize = 15; 28 | } 29 | 30 | nlohmann::json globaljson() { 31 | nlohmann::json json; 32 | json["MemberRateLimit"] = memberRateLimit; 33 | json["DownloadImg"]["Allow-Member"] = DownloadImg::allowmember; 34 | json["LocalImg"]["Allow-Member"] = LocalImg::allowmember; 35 | json["ImgSize"]["maxWidth"] = ImgSize::maxWidth; 36 | json["ImgSize"]["maxHeight"] = ImgSize::maxHeight; 37 | json["ImgSize"]["maxFileSize"] = ImgSize::maxFileSize; 38 | return json; 39 | } 40 | 41 | void initjson(nlohmann::json json) { 42 | JSON1("MemberRateLimit", memberRateLimit); 43 | JSON2("DownloadImg", "Allow-Member", DownloadImg::allowmember); 44 | JSON2("LocalImg", "Allow-Member", LocalImg::allowmember); 45 | JSON2("ImgSize", "maxWidth", ImgSize::maxWidth); 46 | JSON2("ImgSize", "maxHeight", ImgSize::maxHeight); 47 | JSON2("ImgSize", "maxFileSize", ImgSize::maxFileSize); 48 | } 49 | 50 | void WriteDefaultConfig(const std::string& fileName) { 51 | std::ofstream file(fileName); 52 | if (!file.is_open()) { 53 | Logger("CustomMapX").error("Can't open file ",fileName); 54 | return; 55 | } 56 | auto json = globaljson(); 57 | file << json.dump(4); 58 | file.close(); 59 | } 60 | 61 | void LoadConfigFromJson(const std::string& fileName) { 62 | std::ifstream file(fileName); 63 | if (!file.is_open()) { 64 | Logger("CustomMapX").error("Can't open file ", fileName); 65 | return; 66 | } 67 | nlohmann::json json; 68 | file >> json; 69 | file.close(); 70 | initjson(json); 71 | WriteDefaultConfig(fileName); 72 | } 73 | 74 | void reloadJson(const std::string& fileName) { 75 | std::ofstream file(fileName); 76 | if (file) 77 | { 78 | file << globaljson().dump(4); 79 | } 80 | else 81 | { 82 | Logger("CustomMapX").error("Configuration File Creation failed!"); 83 | } 84 | file.close(); 85 | } 86 | } // namespace Settings 87 | 88 | 89 | -------------------------------------------------------------------------------- /Template/Setting.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "llapi/Global.h" 3 | #include 4 | 5 | 6 | namespace Settings { 7 | extern int memberRateLimit; 8 | namespace DownloadImg { 9 | extern bool allowmember; 10 | } 11 | namespace LocalImg { 12 | extern bool allowmember; 13 | } 14 | 15 | 16 | nlohmann::json globaljson(); 17 | void initjson(nlohmann::json json); 18 | void WriteDefaultConfig(const std::string& fileName); 19 | void LoadConfigFromJson(const std::string& fileName); 20 | void reloadJson(const std::string& fileName); 21 | } -------------------------------------------------------------------------------- /Template/Template.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Release 6 | x64 7 | 8 | 9 | 10 | 16.0 11 | Win32Proj 12 | {abeb5558-c92f-473e-8bdf-90f58bd3811c} 13 | Template 14 | 10.0 15 | CustomMapX 16 | 17 | 18 | 19 | DynamicLibrary 20 | false 21 | v143 22 | true 23 | Unicode 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | false 36 | $(SolutionDir)SDK/include;$(SolutionDir)SDK\include/llapi;$(VC_IncludePath);$(WindowsSDK_IncludePath) 37 | 38 | 39 | 40 | TurnOffAllWarnings 41 | true 42 | true 43 | true 44 | true 45 | Use 46 | pch.h 47 | stdcpp20 48 | NDEBUG;TEMPLATE_EXPORTS;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_WARNINGS;_WINDOWS;_USRDLL;_AMD64_;NOMINMAX;%(PreprocessorDefinitions) 49 | /utf-8 %(AdditionalOptions) 50 | $(SolutionDir)SDK\Header\third-party;$(SolutionDir)SDK\Header;$(VC_IncludePath);$(WindowsSDK_IncludePath);%(AdditionalIncludeDirectories) 51 | true 52 | Async 53 | 54 | 55 | Windows 56 | true 57 | true 58 | true 59 | false 60 | bedrock_server.dll 61 | 62 | 63 | if not exist "$(SolutionDir)SDK\Lib\bedrock_server_api.lib" goto process 64 | if not exist "$(SolutionDir)SDK\Lib\bedrock_server_api.lib" goto process 65 | goto end 66 | 67 | :process 68 | cd /d "$(SolutionDir)\SDK\Tools\" 69 | if exist "$(LocalDebuggerWorkingDirectory)\bedrock_server.pdb" ( 70 | LibraryBuilder.exe -o ..\Lib\ "$(LocalDebuggerWorkingDirectory)" 71 | ) else ( 72 | LibraryBuilder.exe -o ..\Lib\ 73 | ) 74 | 75 | :end 76 | 77 | 78 | 79 | if exist "$(LocalDebuggerWorkingDirectory)\plugins\" ( 80 | copy /Y "$(TargetPath)" "$(LocalDebuggerWorkingDirectory)\plugins\" 81 | ) 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | NotUsing 95 | 96 | 97 | NotUsing 98 | 99 | 100 | NotUsing 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /Template/Template.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 6 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 7 | 8 | 9 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 10 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header 20 | 21 | 22 | Source 23 | 24 | 25 | Resourse 26 | 27 | 28 | Header 29 | 30 | 31 | Header 32 | 33 | 34 | Header 35 | 36 | 37 | 38 | 39 | Source 40 | 41 | 42 | Source 43 | 44 | 45 | Source 46 | 47 | 48 | 49 | 50 | Resourse 51 | 52 | 53 | -------------------------------------------------------------------------------- /Template/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 | #define JsonFile "plugins/CustomMapX/config.json" 7 | // Plugin Information, used in dllmain.cpp for register plugin 8 | #define PLUGIN_NAME "CustomMapX" 9 | #define PLUGIN_INTRODUCTION "A Custom Map Plugins" 10 | #define PLUGIN_AUTHOR "QingYu" 11 | #define PLUGIN_VERSION_MAJOR 1 12 | #define PLUGIN_VERSION_MINOR 1 13 | #define PLUGIN_VERSION_REVISION 3 14 | #define PLUGIN_VERSION_BUILD 0 15 | #define PLUGIN_VERSION_STATUS PLUGIN_VERSION_DEV 16 | #define PLUGIN_VERSION_STRING TO_VERSION_STRING(PLUGIN_VERSION_MAJOR.PLUGIN_VERSION_MINOR.PLUGIN_VERSION_REVISION) 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 TO_VERSION_STRING(PLUGIN_VERSION_MAJOR.PLUGIN_VERSION_MINOR.PLUGIN_VERSION_REVISION.PLUGIN_VERSION_ACTIONS BETA) 29 | #elif PLUGIN_VERSION_STATUS == PLUGIN_VERSION_DEV 30 | #define PLUGIN_FILE_VERSION_FLAG VS_FF_DEBUG 31 | #define PLUGIN_LLVERSION_STATUS ll::Version::Dev 32 | #define PLUGIN_FILE_VERSION_STRING TO_VERSION_STRING(PLUGIN_VERSION_MAJOR.PLUGIN_VERSION_MINOR.PLUGIN_VERSION_REVISION.PLUGIN_VERSION_ACTIONS DEV) 33 | #else 34 | #define PLUGIN_FILE_VERSION_FLAG 0x0L 35 | #define PLUGIN_LLVERSION_STATUS LL::Version::Release 36 | #define PLUGIN_FILE_VERSION_STRING TO_VERSION_STRING(PLUGIN_VERSION_MAJOR.PLUGIN_VERSION_MINOR.PLUGIN_VERSION_REVISION.PLUGIN_VERSION_ACTIONS) 37 | #endif 38 | 39 | #define FILE_VERSION_BLOCK_HEADER 0x04004B0L 40 | #define FILE_VERSION_COMPANY_NAME PLUGIN_AUTHOR 41 | #define FILE_VERSION_LEGAL_COPYRIGHT "Copyright (C) 2022" 42 | #define FILE_VERSION_FILE_DESCRIPTION PLUGIN_INTRODUCTION 43 | #define FILE_VERSION_FILE_VERSION_STRING PLUGIN_FILE_VERSION_STRING 44 | #define FILE_VERSION_INTERNAL_NAME PLUGIN_NAME 45 | #define FILE_VERSION_ORIGINAL_FILENAME PLUGIN_NAME ".dll" 46 | #define FILE_VERSION_PRODUCT_NAME FILE_VERSION_INTERNAL_NAME 47 | #define FILE_VERSION_PRODUCT_VERSION_STRING PLUGIN_FILE_VERSION_STRING 48 | #define FILE_VERSION_FILE_VERSION PLUGIN_VERSION_MAJOR, PLUGIN_VERSION_MINOR, PLUGIN_VERSION_REVISION, PLUGIN_VERSION_BUILD 49 | #define FILE_VERSION_PRODUCT_VERSION FILE_VERSION_FILE_VERSION 50 | -------------------------------------------------------------------------------- /Template/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : 定义 DLL 应用程序的入口点。 2 | #include 3 | #include "Version.h" 4 | #pragma comment(lib, "../SDK/Lib/bedrock_server_api.lib") 5 | #pragma comment(lib, "../SDK/Lib/bedrock_server_var.lib") 6 | #pragma comment(lib, "../SDK/Lib/SymDBHelper.lib") 7 | #pragma comment(lib, "../SDK/Lib/LiteLoader.lib") 8 | 9 | HMODULE DllMainPtr; 10 | BOOL APIENTRY DllMain( HMODULE hModule, 11 | DWORD ul_reason_for_call, 12 | LPVOID lpReserved 13 | ) 14 | { 15 | DllMainPtr = hModule; 16 | switch (ul_reason_for_call) 17 | { 18 | case DLL_PROCESS_ATTACH: 19 | ll::registerPlugin( 20 | PLUGIN_NAME, 21 | PLUGIN_INTRODUCTION, 22 | ll::Version(PLUGIN_VERSION_MAJOR, PLUGIN_VERSION_MINOR, PLUGIN_VERSION_REVISION, PLUGIN_LLVERSION_STATUS), 23 | std::map { 24 | #ifdef PLUGIN_AUTHOR 25 | { "QingYu", PLUGIN_AUTHOR }, 26 | #endif // PLUGIN_AUTHOR 27 | //{ "Key", "Value" } 28 | } 29 | ); 30 | break; 31 | case DLL_THREAD_ATTACH: 32 | case DLL_THREAD_DETACH: 33 | case DLL_PROCESS_DETACH: 34 | break; 35 | } 36 | return TRUE; 37 | } 38 | 39 | void PluginInit(); 40 | 41 | extern "C" { 42 | // Do something after all the plugins loaded 43 | _declspec(dllexport) void onPostInit() { 44 | std::ios::sync_with_stdio(false); 45 | PluginInit(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Template/framework.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容 4 | // Windows 头文件 5 | #include 6 | -------------------------------------------------------------------------------- /Template/godef.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #ifndef GO_CGO_EXPORT_PROLOGUE_H 8 | #define GO_CGO_EXPORT_PROLOGUE_H 9 | 10 | #ifndef GO_CGO_GOSTRING_TYPEDEF 11 | typedef struct { 12 | const char* p; 13 | ptrdiff_t n; 14 | } _GoString_; 15 | #endif 16 | 17 | #endif 18 | 19 | #ifndef GO_CGO_PROLOGUE_H 20 | #define GO_CGO_PROLOGUE_H 21 | 22 | typedef signed char GoInt8; 23 | typedef unsigned char GoUint8; 24 | typedef short GoInt16; 25 | typedef unsigned short GoUint16; 26 | typedef int GoInt32; 27 | typedef unsigned int GoUint32; 28 | typedef long long GoInt64; 29 | typedef unsigned long long GoUint64; 30 | typedef GoInt64 GoInt; 31 | typedef GoUint64 GoUint; 32 | typedef float GoFloat32; 33 | typedef double GoFloat64; 34 | 35 | /* 36 | static assertion to make sure the file is being used on architecture 37 | at least with matching size of GoInt. 38 | */ 39 | typedef char _check_for_64_bit_pointer_matching_GoInt[sizeof(void*) == 64 / 8 ? 1 : -1]; 40 | 41 | #ifndef GO_CGO_GOSTRING_TYPEDEF 42 | typedef _GoString_ GoString; 43 | #endif 44 | typedef void* GoMap; 45 | typedef void* GoChan; 46 | typedef struct { 47 | void* t; 48 | void* v; 49 | } GoInterface; 50 | template 51 | struct GoSlice { 52 | T* _data; 53 | GoInt _len; 54 | GoInt _cap; 55 | constexpr GoSlice(const std::vector& vec) { 56 | _data = vec._data(); 57 | _len = vec.size(); 58 | _cap = vec.capacity(); 59 | } 60 | constexpr GoSlice(const size_t cap) { 61 | _data = new T[cap]; 62 | _len = cap; 63 | _cap = cap; 64 | } 65 | constexpr GoSlice(T* data, size_t len, size_t cap) { 66 | _data = data; 67 | _len = len; 68 | _cap = cap; 69 | } 70 | constexpr GoSlice() { 71 | _data = nullptr; 72 | _len = 0; 73 | _cap = 0; 74 | } 75 | constexpr void push_back(const T& v) { 76 | resize(_len + 1); 77 | _data[_len + 1] = v; 78 | _len++; 79 | } 80 | constexpr void resize(size_t new_size) { 81 | if (new_size <= _cap) 82 | return; 83 | T* new_data = new T[new_size]; 84 | memcpy_s(new_data, new_size, _data, _len); 85 | delete[] _data; 86 | _data = new_data; 87 | _cap = new_size; 88 | } 89 | constexpr T& operator[](size_t n) { 90 | return _data[n]; 91 | } 92 | constexpr size_t length() { 93 | return _len; 94 | } 95 | constexpr T* data() { 96 | return _data; 97 | } 98 | constexpr void shrink_to_fit() { 99 | if (_data) 100 | delete[] _data; 101 | } 102 | }; 103 | #endif -------------------------------------------------------------------------------- /Template/resource.h: -------------------------------------------------------------------------------- 1 | 2 | #define MAPModule 4 3 | #define IDR_DLL1 101 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /build.bat: -------------------------------------------------------------------------------- 1 | cd GOHelper 2 | go build -v -ldflags "-s -w" -trimpath -buildmode=c-shared -o MAP_Golang_Module.dll -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------