├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report.md │ └── feature-request.md └── workflows │ ├── build-test.yml │ ├── ci.yml │ └── publish.yaml ├── .gitignore ├── App.xaml ├── App.xaml.cs ├── AssemblyInfo.cs ├── Controls ├── GeneralPage.xaml ├── GeneralPage.xaml.cs ├── LoadingDialog.xaml ├── LoadingDialog.xaml.cs ├── MainPage.xaml ├── MainPage.xaml.cs ├── ModBar.xaml ├── ModBar.xaml.cs ├── ModInfos.xaml ├── ModInfos.xaml.cs ├── ModSourceInfos.xaml ├── ModSourceInfos.xaml.cs ├── MyItemsControl.xaml ├── MyItemsControl.xaml.cs ├── MyToggleButton.xaml ├── MyToggleButton.xaml.cs ├── ScriptEnginePage.xaml ├── ScriptEnginePage.xaml.cs ├── Settings.xaml ├── Settings.xaml.cs ├── SourceBar.xaml └── SourceBar.xaml.cs ├── Converters └── CompareNumbersConverter.cs ├── DataLoader.cs ├── Extensions └── ModShard.cs ├── FilePacker.cs ├── FileReader.cs ├── FodyWeavers.xml ├── LICENSE ├── Language ├── en-us.xaml ├── ru-ru.xaml └── zh-cn.xaml ├── Main.xaml ├── Main.xaml.cs ├── ModLoader.cs ├── ModReference ├── System.Collections.dll ├── System.Linq.dll ├── System.ObjectModel.dll ├── System.Runtime.dll └── netstandard.dll ├── ModShardLauncher.csproj ├── ModShardLauncher.sln ├── ModShardLauncherTest ├── CodeUtilsTest.cs ├── GlobalUsings.cs ├── LocalizationUtilsTest.cs └── ModShardLauncherTest.csproj ├── ModUtils ├── AsmUtils.cs ├── CodeUtils.cs ├── EventUtils.cs ├── GeneralUtils.cs ├── HookUtils.cs ├── LogUtils.cs ├── LootUtils.cs ├── ModMenuUtils.cs ├── ObjectUtils.cs ├── RoomUtils.cs ├── TableUtils │ ├── Backers.cs │ ├── ContractsStats.cs │ ├── Drops.cs │ ├── DungeonsSpawn.cs │ ├── ItemStats.cs │ ├── LocalizationUtils.cs │ ├── MobsStats.cs │ ├── PotionsStats.cs │ ├── RecipesCook.cs │ ├── RecipesCraft.cs │ ├── SkillsStats.cs │ ├── SurfaceSpawn.cs │ ├── TableArmor.cs │ ├── TableUtils.cs │ └── TableWeapons.cs ├── TextureUtils.cs ├── VariableUtils.cs ├── Weapon.cs └── WeaponUtils.cs ├── Mods ├── DisassemblyEditor.cs ├── Mod.cs ├── ModHooks.cs └── ModInterfaceEngine.cs ├── README.md ├── Reference ├── README.md ├── UndertaleModLib.dll └── UndertaleModTool.dll ├── Resources ├── Codes │ ├── CodeResources.Designer.cs │ ├── CodeResources.resx │ ├── ScriptEngine_create.gml │ ├── ScriptEngine_server.gml │ ├── SendMsg.gml │ ├── createHookObj.gml │ ├── give.gml │ └── msl_print.gml ├── ExportRoom.csx ├── Mystery Font.ttf ├── SSFont.ttf ├── Sprites │ ├── ModInfosBG.png │ ├── SSicon.png │ ├── arrow_down.png │ ├── arrow_down_down.png │ ├── arrow_down_over.png │ ├── arrow_up.png │ ├── arrow_up_down.png │ ├── arrow_up_over.png │ ├── checkbox_0.png │ ├── checkbox_1.png │ ├── checkbox_2.png │ ├── close.png │ ├── close_down.png │ ├── close_over.png │ ├── enable_button.png │ ├── enable_button_down.png │ ├── enable_button_over.png │ ├── icon.gif │ ├── icon_default.png │ ├── leftPanel.png │ ├── menu.png │ ├── menu_down.png │ ├── menu_over.png │ ├── min.png │ ├── min_down.png │ ├── min_over.png │ ├── mod.png │ ├── mod_down.png │ ├── mod_icon_fore.png │ ├── mod_over.png │ ├── open.png │ ├── open_down.png │ ├── open_over.png │ ├── patch_icon.png │ ├── refresh_icon.png │ ├── save.png │ ├── save_down.png │ ├── save_over.png │ ├── scrollbar_vertical.png │ ├── scrollbar_vertical_over.png │ ├── server.png │ ├── server_down.png │ ├── server_over.png │ ├── settings.png │ ├── settings_button.png │ ├── settings_button_down.png │ ├── settings_button_over.png │ ├── settings_down.png │ ├── settings_over.png │ ├── source.png │ ├── source_down.png │ ├── source_over.png │ └── splitter.png └── zpix.ttf ├── TextureLoader.cs ├── docs ├── guides │ ├── api.en.md │ ├── api.zh.md │ ├── how-to-play-mod.en.md │ ├── how-to-play-mod.zh.md │ ├── introduction.en.md │ ├── introduction.zh.md │ ├── start-modding-with-vsc.zh.md │ ├── start-modding.en.md │ └── start-modding.zh.md ├── img │ ├── Stoneshard.ico │ ├── class_0.en.png │ ├── class_0.zh.png │ ├── class_1.en.png │ ├── compile_0.en.png │ ├── compile_1.en.png │ ├── create_project_0.en.png │ ├── create_project_0.zh.png │ ├── create_project_1.en.png │ ├── create_project_1.zh.png │ ├── create_project_2.en.png │ ├── create_project_2.zh.png │ ├── linux_bottle_1.png │ ├── mod_0.en.png │ ├── mod_0.zh.png │ ├── mod_1.en.png │ ├── mod_1.zh.png │ ├── mod_2.en.png │ ├── mod_2.zh.png │ ├── mod_3.en.png │ ├── mod_3.zh.png │ ├── modding_codes.en.png │ ├── msl_template.en.png │ ├── msl_template_location.en.png │ ├── tool_UI.en.png │ ├── tool_UI2.en.png │ ├── tool_UI3.en.png │ ├── tool_UI4.en.png │ ├── tool_UI5.en.png │ ├── tool_UI6.en.png │ ├── weapon_0.en.png │ ├── weapon_0.zh.png │ ├── weapon_1.en.png │ └── weapon_2.en.png ├── index.en.md └── index.zh.md ├── future_workflow.md ├── ico.ico └── mkdocs.yml /.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/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug Report 3 | about: Create a report to help us improve 4 | title: "[BUG] Bug report" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## **Describe the Bug :** 11 | ... 12 | 13 | ## **Steps To Reproduce :** 14 | ... 15 | 16 | ## **Expected Behavior :** 17 | ... 18 | 19 | ## **Screenshots if applicable :** 20 | _You can directly paste screenshots here, no need for external hosting._ 21 | ... 22 | 23 | --- 24 | 25 | ## **Additional Information :** 26 | - Stoneshard Version : **X.X.X.X** 27 | - MSL Version : **X.X.X.X** 28 | 29 | ## **Additional Context :** 30 | _Add any other context about the problem here._ 31 | ... 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest an idea for this project 4 | title: "[ENHANCEMENT] Feature Request" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## **Describe the problem which requires a new feature.** 11 | ... 12 | 13 | ## **Describe the solution you'd like** 14 | ... 15 | 16 | ## **Describe alternatives you've considered if any** 17 | ... 18 | 19 | ## **Additional context** 20 | ... 21 | -------------------------------------------------------------------------------- /.github/workflows/build-test.yml: -------------------------------------------------------------------------------- 1 | name: Build + Test 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | branches: [ main ] 7 | push: 8 | branches: [ main ] 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: windows-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | fetch-depth: 0 19 | 20 | - name: Setup .NET 21 | uses: actions/setup-dotnet@v4 22 | with: 23 | dotnet-version: 6.0.x 24 | 25 | - name: Restore dependencies 26 | run: dotnet restore 27 | 28 | - name: Build 29 | run: dotnet build -c Release --no-restore 30 | 31 | - name: Test 32 | run: dotnet test -c Release --no-build --verbosity normal 33 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | workflow_dispatch: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | paths: 9 | - 'docs/**' 10 | permissions: 11 | contents: write 12 | jobs: 13 | deploy: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | with: 18 | fetch-depth: 0 19 | - uses: actions/setup-python@v4 20 | with: 21 | python-version: 3.x 22 | - uses: actions/cache@v2 23 | with: 24 | key: ${{ github.ref }} 25 | path: .cache 26 | - run: pip install mkdocs-material mkdocs-table-reader-plugin mkdocs-glightbox mkdocs-static-i18n[material] mkdocs-git-authors-plugin mkdocs-git-revision-date-plugin 27 | - run: mkdocs gh-deploy --force 28 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json 2 | 3 | name: publish 4 | on: 5 | workflow_dispatch: # Allow running the workflow manually from the GitHub UI 6 | push: 7 | branches: 8 | - 'main' # Run the workflow when pushing to the main branch (test only) 9 | tags: 10 | - '*' # Run the workflow with a tag 11 | 12 | env: 13 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 14 | DOTNET_NOLOGO: true 15 | NuGetDirectory: ${{ github.workspace }}/publish 16 | 17 | jobs: 18 | set_version: 19 | if: startsWith(github.ref, 'refs/tags/') 20 | runs-on: ubuntu-latest 21 | outputs: 22 | sha: ${{ steps.sha.outputs.sha }} 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v4 26 | with: 27 | fetch-depth: 0 28 | ref: main 29 | 30 | - name: Set Version 31 | id: package_version 32 | uses: KageKirin/set-csproj-version@v0 33 | with: 34 | file: ./ModShardLauncher.csproj 35 | version: ${{ github.ref_name }} 36 | 37 | - name: Set user info 38 | run: | 39 | git config user.name github-actions 40 | git config user.email github-actions@github.com 41 | 42 | - name: Check if there are any changes 43 | id: verify_diff 44 | run: | 45 | git diff --quiet . || echo "changed=true" >> $GITHUB_OUTPUT 46 | 47 | - name: Commit Files & Pull 48 | if: steps.verify_diff.outputs.changed == 'true' 49 | run: | 50 | git commit -a -m "Updated version with CI." 51 | git pull origin main --rebase 52 | 53 | - name: Push Changes 54 | if: steps.verify_diff.outputs.changed == 'true' 55 | uses: ad-m/github-push-action@master 56 | with: 57 | github_token: ${{ secrets.GITHUB_TOKEN }} 58 | branch: main 59 | 60 | - name: Get SHA 61 | id: sha 62 | run: | 63 | echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT 64 | echo ${{ steps.sha.outputs.sha }} 65 | 66 | create_msl: 67 | runs-on: ubuntu-latest 68 | needs: [ set_version ] 69 | steps: 70 | - uses: actions/checkout@v4 71 | with: 72 | fetch-depth: 0 # Get all history to allow automatic versioning using MinVer 73 | ref: ${{ needs.set_version.outputs.sha }} 74 | 75 | # Install the .NET SDK indicated in the global.json file 76 | - name: Setup .NET 77 | uses: actions/setup-dotnet@v4 78 | 79 | # Build the project in the folder from the environment variable NuGetDirectory 80 | - run: dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true /p:IncludeAllContentForSelfExtract=true /p:PublishReadyToRun=true --output ${{ env.NuGetDirectory }} 81 | 82 | # Zip the folder 83 | - name: Zip 84 | run: zip -r msl.zip ${{ env.NuGetDirectory }} 85 | 86 | # Publish the NuGet package as an artifact, so they can be used in the following jobs 87 | - uses: actions/upload-artifact@v3 88 | with: 89 | name: msl 90 | if-no-files-found: error 91 | retention-days: 7 92 | path: msl.zip 93 | 94 | create_release: 95 | runs-on: ubuntu-latest 96 | needs: [ create_msl ] 97 | steps: 98 | - uses: actions/checkout@v4 99 | 100 | - name: Create Release 101 | run: gh release create ${{ github.ref_name }} --generate-notes --prerelease 102 | env: 103 | GITHUB_TOKEN: ${{ github.TOKEN }} 104 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd 364 | 365 | # Jetbrains IDE projet settings folder 366 | .idea/ 367 | 368 | # VSCode settings 369 | .vscode/ 370 | 371 | # VSCode Markdown linting configuration 372 | .markdownlint.json 373 | 374 | # MSL related 375 | Settings.json -------------------------------------------------------------------------------- /App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace ModShardLauncher 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] 11 | -------------------------------------------------------------------------------- /Controls/GeneralPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using ModShardLauncher.Mods; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Controls.Primitives; 10 | using System.Windows.Media; 11 | using UndertaleModTool; 12 | 13 | namespace ModShardLauncher.Controls 14 | { 15 | /// 16 | /// GeneralPage.xaml 的交互逻辑 17 | /// 18 | public partial class GeneralPage : UserControl 19 | { 20 | public GeneralPage() 21 | { 22 | InitializeComponent(); 23 | 24 | // add Languages 25 | Languages.Add("中文"); 26 | Languages.Add("English"); 27 | //Languages.Add("Русский"); 28 | 29 | switch (Main.Settings.Language) 30 | { 31 | case "Chinese": 32 | LangSelector.SelectedIndex = 0; 33 | UserSettings.ChangeLanguage(0); 34 | break; 35 | case "English": 36 | LangSelector.SelectedIndex = 1; 37 | UserSettings.ChangeLanguage(1); 38 | break; 39 | case "Russian": 40 | LangSelector.SelectedIndex = 2; 41 | UserSettings.ChangeLanguage(2); 42 | break; 43 | } 44 | } 45 | public int selectIndex { get; set; } = 1; 46 | public List Languages { get; set; } = new List(); 47 | public int selection = -1; 48 | 49 | private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 50 | { 51 | if (selection == -1) 52 | { 53 | selection = LangSelector.SelectedIndex; 54 | return; 55 | } 56 | ComboBox combo = Msl.ThrowIfNull(sender as ComboBox); 57 | UserSettings.ChangeLanguage(combo.SelectedIndex); 58 | selection = combo.SelectedIndex; 59 | LangSelector.SelectedIndex = selection; 60 | } 61 | 62 | private void Logger_Checked(object sender, RoutedEventArgs e) 63 | { 64 | Main.Settings.EnableLogger = Msl.ThrowIfNull(Logger.IsChecked); 65 | UserSettings.CheckLog(Main.Settings.EnableLogger); 66 | Main.Settings.SaveSettings(); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Controls/LoadingDialog.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 18 | -------------------------------------------------------------------------------- /Controls/LoadingDialog.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Data; 10 | using System.Windows.Documents; 11 | using System.Windows.Input; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using System.Windows.Shapes; 15 | using System.Windows.Shell; 16 | 17 | namespace ModShardLauncher 18 | { 19 | /// 20 | /// LoadingDialog.xaml 的交互逻辑 21 | /// 22 | public partial class LoadingDialog : Window 23 | { 24 | public LoadingDialog() 25 | { 26 | InitializeComponent(); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Controls/MainPage.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 14 | 15 | 16 | 18 | 20 | 23 | 24 | 26 | 28 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /Controls/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Media; 12 | using System.Windows.Media.Imaging; 13 | using System.Windows.Navigation; 14 | using System.Windows.Shapes; 15 | 16 | namespace ModShardLauncher.Controls 17 | { 18 | /// 19 | /// MainPage.xaml 的交互逻辑 20 | /// 21 | public partial class MainPage : UserControl 22 | { 23 | public MainPage() 24 | { 25 | InitializeComponent(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Controls/ModBar.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 24 | 27 | 28 | 30 | 31 | 32 | 34 | 37 | 38 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /Controls/ModBar.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | using System.Windows.Data; 11 | using System.Windows.Documents; 12 | using System.Windows.Input; 13 | using System.Windows.Media; 14 | using System.Windows.Media.Imaging; 15 | using System.Windows.Navigation; 16 | using System.Windows.Shapes; 17 | 18 | namespace ModShardLauncher.Controls 19 | { 20 | /// 21 | /// ModBar.xaml 的交互逻辑 22 | /// 23 | public partial class ModBar : UserControl 24 | { 25 | public ImageSource? Icon = null; 26 | public ModBar() 27 | { 28 | InitializeComponent(); 29 | } 30 | } 31 | public class ByteArrayToImageSourceConverter : IValueConverter 32 | { 33 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 34 | { 35 | byte[] imageData = (byte[])value; 36 | if (imageData.Length == 0) return new BitmapImage(new Uri("/Resources/Sprites/icon_default.png", UriKind.Relative)); 37 | 38 | BitmapImage biImg = new(); 39 | MemoryStream ms = new(imageData); 40 | biImg.BeginInit(); 41 | biImg.StreamSource = ms; 42 | biImg.EndInit(); 43 | biImg.Freeze(); 44 | 45 | return biImg; 46 | } 47 | 48 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 49 | { 50 | throw new NotImplementedException(); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Controls/ModInfos.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Controls/ModInfos.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Threading.Tasks; 5 | using System.Windows; 6 | using System.Windows.Controls; 7 | using ModShardLauncher.Mods; 8 | using Serilog; 9 | 10 | namespace ModShardLauncher.Controls 11 | { 12 | /// 13 | /// ModInfos.xaml 的交互逻辑 14 | /// 15 | public partial class ModInfos : UserControl 16 | { 17 | public static ModInfos Instance; 18 | public List Mods { get; set; } = new(); 19 | public ModInfos() 20 | { 21 | InitializeComponent(); 22 | Instance = this; 23 | } 24 | private async void Open_Click(object sender, EventArgs e) 25 | { 26 | await DataLoader.DoOpenDialog(); 27 | Main.Instance.Refresh(); 28 | } 29 | private async void Save_Click(object sender, EventArgs e) 30 | { 31 | if (DataLoader.data.FORM == null) 32 | { 33 | MessageBox.Show(Application.Current.FindResource("LoadDataWarning").ToString()); 34 | return; 35 | } 36 | 37 | bool patchSucess = false; 38 | 39 | try 40 | { 41 | ModLoader.PatchFile(); 42 | Log.Information("Successfully patch vanilla"); 43 | patchSucess = true; 44 | Main.Instance.LogModList(); 45 | } 46 | catch(Exception ex) 47 | { 48 | Main.Instance.LogModList(); 49 | Log.Error(ex, "Something went wrong"); 50 | Log.Information("Failed patching vanilla"); 51 | MessageBox.Show(ex.ToString(), Application.Current.FindResource("SaveDataWarning").ToString()); 52 | } 53 | 54 | // attempt to save the patched data 55 | if (patchSucess) 56 | { 57 | Task save = DataLoader.DoSaveDialog(); 58 | await save; 59 | if (!save.Result) Log.Information("Saved cancelled."); 60 | // copy the dataloot.json in the stoneshard directory 61 | LootUtils.SaveLootTables(Msl.ThrowIfNull(Path.GetDirectoryName(DataLoader.savedDataPath))); 62 | } 63 | 64 | // reload the data 65 | await DataLoader.LoadFile(DataLoader.dataPath, true); 66 | Main.Instance.Refresh(); 67 | } 68 | 69 | private void Server_Click(object sender, EventArgs e) 70 | { 71 | ModInterfaceServer.StartServer(1333); 72 | Main.Instance.Refresh(); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Controls/ModSourceInfos.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Controls/ModSourceInfos.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows; 4 | using System.Windows.Controls; 5 | using Serilog; 6 | 7 | namespace ModShardLauncher.Controls 8 | { 9 | /// 10 | /// ModSourceInfos.xaml 的交互逻辑 11 | /// 12 | public partial class ModSourceInfos : UserControl 13 | { 14 | public static ModSourceInfos Instance; 15 | public List ModSources { get; set; } = new(); 16 | public ModSourceInfos() 17 | { 18 | InitializeComponent(); 19 | Instance = this; 20 | } 21 | private async void Open_Click(object sender, EventArgs e) 22 | { 23 | await DataLoader.DoOpenDialog(); 24 | Main.Instance.Refresh(); 25 | } 26 | private async void Save_Click(object sender, EventArgs e) 27 | { 28 | if (DataLoader.data.FORM == null) 29 | { 30 | MessageBox.Show(Application.Current.FindResource("LoadDataWarning").ToString()); 31 | return; 32 | } 33 | 34 | bool patchSucess = false; 35 | 36 | try 37 | { 38 | ModLoader.PatchFile(); 39 | Log.Information("Successfully patch vanilla"); 40 | patchSucess = true; 41 | Main.Instance.LogModList(); 42 | } 43 | catch(Exception ex) 44 | { 45 | Main.Instance.LogModList(); 46 | Log.Error(ex, "Something went wrong"); 47 | Log.Information("Failed patching vanilla"); 48 | MessageBox.Show(ex.ToString(), Application.Current.FindResource("SaveDataWarning").ToString()); 49 | } 50 | 51 | if (patchSucess) await DataLoader.DoSaveDialog(); 52 | Main.Instance.Refresh(); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Controls/MyItemsControl.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 14 | 15 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Controls/MyItemsControl.xaml.cs: -------------------------------------------------------------------------------- 1 | using ModShardLauncher.Mods; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Data; 10 | using System.Windows.Documents; 11 | using System.Windows.Input; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using System.Windows.Navigation; 15 | using System.Windows.Shapes; 16 | 17 | namespace ModShardLauncher.Controls 18 | { 19 | /// 20 | /// MyScrollViewer.xaml 的交互逻辑 21 | /// 22 | public partial class MyItemsControl : UserControl 23 | { 24 | public MyItemsControl() 25 | { 26 | InitializeComponent(); 27 | } 28 | public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register( 29 | "ItemsSource", 30 | typeof(object), 31 | typeof(MyItemsControl), 32 | new PropertyMetadata(default(object), OnItemsPropertyChanged)); 33 | private static void OnItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 34 | { 35 | } 36 | public List ItemsSource { get; set; } 37 | } 38 | public class TempSelector : DataTemplateSelector 39 | { 40 | public override DataTemplate SelectTemplate(object item, DependencyObject container) 41 | { 42 | if (item is ModFile) 43 | return Application.Current.FindResource("mod") as DataTemplate; 44 | else return Application.Current.FindResource("source") as DataTemplate; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Controls/MyToggleButton.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 32 | 33 | 34 | 35 | 36 | 41 | 42 | 48 | 49 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Controls/MyToggleButton.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Data; 10 | using System.Windows.Documents; 11 | using System.Windows.Input; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using System.Windows.Navigation; 15 | using System.Windows.Shapes; 16 | 17 | namespace ModShardLauncher.Controls 18 | { 19 | /// 20 | /// MyToggleButton.xaml 的交互逻辑 21 | /// 22 | public partial class MyToggleButton : UserControl 23 | { 24 | public ImageSource ImageSource { get; set; } 25 | public string Text { get; set; } 26 | [Category("Behavior")] 27 | public event EventHandler Checked; 28 | public event EventHandler Click; 29 | public static readonly DependencyProperty TextProperty = DependencyProperty.Register( 30 | "Text", 31 | typeof(string), 32 | typeof(MyToggleButton), 33 | new PropertyMetadata(default(string), OnTextChanged) 34 | ); 35 | public MyToggleButton() 36 | { 37 | InitializeComponent(); 38 | } 39 | private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 40 | { 41 | 42 | } 43 | private void MyButton_Checked(object sender, RoutedEventArgs e) 44 | { 45 | Checked?.Invoke(this, e); 46 | } 47 | 48 | private void MyButton_Click(object sender, RoutedEventArgs e) 49 | { 50 | Click?.Invoke(this, e); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Controls/ScriptEnginePage.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Controls/ScriptEnginePage.xaml.cs: -------------------------------------------------------------------------------- 1 | using ModShardLauncher.Mods; 2 | using System; 3 | using System.Windows; 4 | using System.Windows.Input; 5 | using System.Windows.Threading; 6 | 7 | namespace ModShardLauncher.Controls 8 | { 9 | /// 10 | /// ScriptEnginePage.xaml 的交互逻辑 11 | /// 12 | public partial class ScriptEnginePage : Window 13 | { 14 | public static ScriptEnginePage? Instance; 15 | 16 | public DispatcherTimer Timer; 17 | 18 | public ScriptEnginePage() 19 | { 20 | InitializeComponent(); 21 | Instance = this; 22 | Timer = new DispatcherTimer(); 23 | } 24 | 25 | private void ScriptBox_KeyDown(object sender, KeyEventArgs e) 26 | { 27 | if (e.Key == Key.Enter) 28 | { 29 | if (ScriptBox.Text.Length == 0) return; 30 | ModInterfaceServer.SendScript(ScriptBox.Text); 31 | ScriptBox.Text = ""; 32 | } 33 | } 34 | 35 | private void Window_Closed(object sender, EventArgs e) 36 | { 37 | ModInterfaceServer.Server.Close(); 38 | ModInterfaceServer.Server = null; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Controls/Settings.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /Controls/Settings.xaml.cs: -------------------------------------------------------------------------------- 1 | using ModShardLauncher.Controls; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | using System.Windows.Controls.Primitives; 10 | 11 | namespace ModShardLauncher.Controls 12 | { 13 | /// 14 | /// Settings.xaml 的交互逻辑 15 | /// 16 | public partial class Settings : UserControl 17 | { 18 | public Settings() 19 | { 20 | InitializeComponent(); 21 | } 22 | public List List { get; set; } = new List(); 23 | public GeneralPage GeneralPage = new GeneralPage(); 24 | 25 | private void GeneralSettings_Click(object sender, RoutedEventArgs e) 26 | { 27 | bool isChecked = Msl.ThrowIfNull(((ToggleButton)sender).IsChecked); 28 | if (isChecked) Viewer.Content = GeneralPage; 29 | else Viewer.Content = null; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Controls/SourceBar.xaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | 16 | 19 | 20 | 24 | 64 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /Controls/SourceBar.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using Serilog; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | using System.Windows.Data; 11 | using System.Windows.Documents; 12 | using System.Windows.Input; 13 | using System.Windows.Media; 14 | using System.Windows.Media.Imaging; 15 | using System.Windows.Navigation; 16 | using System.Windows.Shapes; 17 | 18 | namespace ModShardLauncher.Controls 19 | { 20 | /// 21 | /// SourceBar.xaml 的交互逻辑 22 | /// 23 | public partial class SourceBar : UserControl 24 | { 25 | public SourceBar() 26 | { 27 | InitializeComponent(); 28 | } 29 | 30 | private void CompileButton_Click(object sender, RoutedEventArgs e) 31 | { 32 | try 33 | { 34 | UtilsPacker.Pack(Msl.ThrowIfNull(DataContext as ModSource).Path); 35 | } 36 | catch(Exception ex) 37 | { 38 | Log.Error(ex, "Something went wrong"); 39 | } 40 | 41 | Msl.ThrowIfNull(Main.Instance.Viewer.Content as UserControl).UpdateLayout(); 42 | Main.Instance.Refresh(); 43 | } 44 | 45 | private void OpenButton_Click(object sender, RoutedEventArgs e) 46 | { 47 | System.Diagnostics.Process.Start("explorer.exe", Msl.ThrowIfNull(DataContext as ModSource).Path); 48 | 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Converters/CompareNumbersConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Globalization; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Data; 9 | 10 | namespace ModShardLauncher.Converters 11 | { 12 | public class CompareNumbersConverter : IMultiValueConverter 13 | { 14 | // these could be overridden on declaration 15 | public object TrueValue { get; set; } = Visibility.Visible; 16 | public object FalseValue { get; set; } = Visibility.Collapsed; 17 | 18 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 19 | { 20 | double a, b; 21 | try 22 | { 23 | a = (double)values[0]; 24 | b = (double)values[1]; 25 | } 26 | catch 27 | { 28 | return null; 29 | } 30 | 31 | if (parameter is string par) 32 | { 33 | int r; 34 | if (par == ">") // greater than 35 | r = 1; 36 | else if (par == "<") // less than 37 | r = -1; 38 | else 39 | return null; 40 | 41 | bool res = a.CompareTo(b) == r; 42 | return res ? TrueValue : FalseValue; 43 | } 44 | 45 | return null; 46 | } 47 | 48 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 49 | { 50 | throw new NotImplementedException(); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Extensions/ModShard.cs: -------------------------------------------------------------------------------- 1 | using UndertaleModLib; 2 | using UndertaleModLib.Models; 3 | 4 | namespace ModShardLauncher.Extensions 5 | { 6 | public class ModShard : UndertaleExtensionFile 7 | { 8 | public ModShard() 9 | { 10 | Filename = DataLoader.data.Strings.MakeString("ModShard.dll"); 11 | CleanupScript = DataLoader.data.Strings.MakeString(""); 12 | InitScript = DataLoader.data.Strings.MakeString(""); 13 | Kind = UndertaleExtensionKind.Dll; 14 | CreateFunc(); 15 | } 16 | public void CreateFunc() 17 | { 18 | UndertaleExtensionFunction ScriptThread = new() 19 | { 20 | Name = DataLoader.data.Strings.MakeString("ScriptThread"), 21 | ExtName = DataLoader.data.Strings.MakeString("ScriptThread"), 22 | RetType = UndertaleExtensionVarType.Double, 23 | Arguments = new UndertaleSimpleList(), 24 | Kind = 11, 25 | ID = DataLoader.data.ExtensionFindLastId() 26 | }; 27 | Functions.Add(ScriptThread); 28 | UndertaleExtensionFunction GetScript = new() 29 | { 30 | Name = DataLoader.data.Strings.MakeString("GetScript"), 31 | ExtName = DataLoader.data.Strings.MakeString("GetScript"), 32 | RetType = UndertaleExtensionVarType.String, 33 | Arguments = new UndertaleSimpleList(), 34 | Kind = 11, 35 | ID = ScriptThread.ID + 1 36 | }; 37 | Functions.Add(GetScript); 38 | UndertaleExtensionFunction PopScript = new() 39 | { 40 | Name = DataLoader.data.Strings.MakeString("PopScript"), 41 | ExtName = DataLoader.data.Strings.MakeString("PopScript"), 42 | RetType = UndertaleExtensionVarType.Double, 43 | Arguments = new UndertaleSimpleList(), 44 | Kind = 11, 45 | ID = GetScript.ID + 1 46 | }; 47 | Functions.Add(PopScript); 48 | UndertaleExtensionFunction RunCallBack = new() 49 | { 50 | Name = DataLoader.data.Strings.MakeString("RunCallBack"), 51 | ExtName = DataLoader.data.Strings.MakeString("RunCallBack"), 52 | RetType = UndertaleExtensionVarType.Double, 53 | Arguments = new UndertaleSimpleList() 54 | { 55 | new UndertaleExtensionFunctionArg() 56 | { 57 | Type = UndertaleExtensionVarType.String 58 | } 59 | }, 60 | Kind = 11, 61 | ID = PopScript.ID + 1 62 | }; 63 | Functions.Add(RunCallBack); 64 | 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /FilePacker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using Serilog; 4 | using System.Diagnostics; 5 | using ModShardPackerReference; 6 | 7 | namespace ModShardLauncher 8 | { 9 | public static class UtilsPacker 10 | { 11 | /// 12 | /// Pack a mod located in using the packing method from . 13 | /// 14 | /// 15 | /// 16 | public static bool Pack(string path) 17 | { 18 | bool resultPacking = false; 19 | 20 | try 21 | { 22 | resultPacking = FilePacker.Pack( 23 | null, 24 | path, 25 | ModLoader.ModPath, 26 | path, 27 | Main.Instance.mslVersion, 28 | new Type[2] {typeof(ModShardLauncher.Mods.Mod), typeof(UndertaleModLib.Models.UndertaleCode)} 29 | ); 30 | } 31 | catch(Exception ex) 32 | { 33 | if (ex is ArgumentNullException || ex is ArgumentException || ex is IOException || ex is DirectoryNotFoundException) 34 | { 35 | Log.Error(ex.ToString()); 36 | } 37 | else 38 | { 39 | Log.Error(ex, "Unexpected error"); 40 | } 41 | Console.WriteLine(ex.Message); 42 | } 43 | 44 | return resultPacking; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | -------------------------------------------------------------------------------- /Language/en-us.xaml: -------------------------------------------------------------------------------- 1 |  4 | A tool for StoneShard modding. 5 | Start your first mod from here. 6 | File 7 | Settings 8 | Open 9 | Languages 10 | Enable logger 11 | Refresh 12 | Patch 13 | Search by mod's name... 14 | Welcome! 15 | Enable 16 | Disable 17 | Welcome to use ModShardLauncher! 18 | if you want to refresh mods, just paste them into the /Mods path and click the refresh button on the left 19 | First, click File button and open a original data file then select Mods you want to enable. 20 | Then click patch button to patch mod into data file. 21 | Mod Name 22 | Mod Author 23 | Mod Description 24 | Enable 25 | ModVersion 26 | MSL Version 27 | Compile 28 | Patching failed, cant save 29 | Please load a game data file first! 30 | Mod version is different from game version 31 | Mod version is different from game version, maybe it will crash if you load it.Still want to load? 32 | Mod file lost. 33 | Compile Error: 34 | Save this path as default LoadPath? 35 | Save this path as default SavePath? 36 | General 37 | Mods 38 | ModSources 39 | Settings 40 | Menu 41 | Close 42 | Minimize 43 | Loading... 44 | Mod Interface Server starts at port {0}. 45 | -------------------------------------------------------------------------------- /Language/ru-ru.xaml: -------------------------------------------------------------------------------- 1 |  4 | Файл 5 | Настройки 6 | Открыть 7 | Язык 8 | Обновить 9 | Загрузить 10 | Поиск по названию мода... 11 | Добро пожаловать 12 | Добро пожаловать в ModShardLauncher! 13 | Если вы хотите обновить моды, просто вставьте их в папку /Mods и нажмите кнопку "Обновить" слева. 14 | Сначала нажмите кнопку "Файл" и откройте исходный файл данных, затем выберите моды, которые вы хотите включить. 15 | Затем нажмите кнопку "Загрузить", чтобы загрузить моды в файл данных. 16 | Название мода 17 | Автор мода 18 | Описание мода 19 | Включить мод 20 | Версия мода 21 | Версия игры 22 | Компилировать 23 | Пожалуйста, загрузите файл данных игры сначала! 24 | Версия мода отличается от версии игры 25 | Версия мода отличается от версии игры, возможно, это вызовет сбой. Вы всё равно хотите загрузить его? 26 | Файл мода отсутствует 27 | -------------------------------------------------------------------------------- /Language/zh-cn.xaml: -------------------------------------------------------------------------------- 1 |  4 | 一款用于StoneShard的模组工具. 5 | 模组之旅从这里启程. 6 | 文件 7 | 设置 8 | 打开 9 | 语言 10 | 启用Logger 11 | 刷新 12 | 加载 13 | 以模组名称搜索... 14 | 欢迎 15 | 启用 16 | 禁用 17 | 欢迎使用ModShardLauncher! 18 | 若想重新加载mod 请在启动器目录下的Mods文件夹内放入你想加载的Mod 并点击左上角的刷新按钮 19 | Mod名称 20 | Mod作者 21 | Mod描述 22 | 是否启用 23 | Mod版本 24 | 游戏版本 25 | 打包错误, 未能保存文件 26 | 编译 27 | 请先加载游戏文件! 28 | Mod版本与游戏版本不一致 29 | Mod版本与游戏版本不一致, 如果执意加载可能会崩溃.仍然要加载吗? 30 | Mod文件丢失 31 | 编译错误: 32 | 将此路径保存为默认加载路径? 33 | 将此路径保存为默认保存路径? 34 | 常规 35 | 模组 36 | 模组源码 37 | 设置 38 | 菜单 39 | 关闭 40 | 最小化 41 | 加载中... 42 | 模组交互服务器已在{0}端口上启动. 43 | -------------------------------------------------------------------------------- /ModReference/System.Collections.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/ModReference/System.Collections.dll -------------------------------------------------------------------------------- /ModReference/System.Linq.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/ModReference/System.Linq.dll -------------------------------------------------------------------------------- /ModReference/System.ObjectModel.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/ModReference/System.ObjectModel.dll -------------------------------------------------------------------------------- /ModReference/System.Runtime.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/ModReference/System.Runtime.dll -------------------------------------------------------------------------------- /ModReference/netstandard.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/ModReference/netstandard.dll -------------------------------------------------------------------------------- /ModShardLauncher.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.7.34024.191 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ModShardLauncher", "ModShardLauncher.csproj", "{381707F0-2C79-4B36-BD23-2114A0EF55D1}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModShardLauncherTest", "ModShardLauncherTest\ModShardLauncherTest.csproj", "{9083D03A-A393-4EFD-80EB-17ADF18F4C82}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|x64 = Debug|x64 14 | Debug|x86 = Debug|x86 15 | Release|Any CPU = Release|Any CPU 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {381707F0-2C79-4B36-BD23-2114A0EF55D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {381707F0-2C79-4B36-BD23-2114A0EF55D1}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {381707F0-2C79-4B36-BD23-2114A0EF55D1}.Debug|x64.ActiveCfg = Debug|Any CPU 23 | {381707F0-2C79-4B36-BD23-2114A0EF55D1}.Debug|x64.Build.0 = Debug|Any CPU 24 | {381707F0-2C79-4B36-BD23-2114A0EF55D1}.Debug|x86.ActiveCfg = Debug|Any CPU 25 | {381707F0-2C79-4B36-BD23-2114A0EF55D1}.Debug|x86.Build.0 = Debug|Any CPU 26 | {381707F0-2C79-4B36-BD23-2114A0EF55D1}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {381707F0-2C79-4B36-BD23-2114A0EF55D1}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {381707F0-2C79-4B36-BD23-2114A0EF55D1}.Release|x64.ActiveCfg = Release|Any CPU 29 | {381707F0-2C79-4B36-BD23-2114A0EF55D1}.Release|x64.Build.0 = Release|Any CPU 30 | {381707F0-2C79-4B36-BD23-2114A0EF55D1}.Release|x86.ActiveCfg = Release|Any CPU 31 | {381707F0-2C79-4B36-BD23-2114A0EF55D1}.Release|x86.Build.0 = Release|Any CPU 32 | {9083D03A-A393-4EFD-80EB-17ADF18F4C82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {9083D03A-A393-4EFD-80EB-17ADF18F4C82}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {9083D03A-A393-4EFD-80EB-17ADF18F4C82}.Debug|x64.ActiveCfg = Debug|Any CPU 35 | {9083D03A-A393-4EFD-80EB-17ADF18F4C82}.Debug|x64.Build.0 = Debug|Any CPU 36 | {9083D03A-A393-4EFD-80EB-17ADF18F4C82}.Debug|x86.ActiveCfg = Debug|Any CPU 37 | {9083D03A-A393-4EFD-80EB-17ADF18F4C82}.Debug|x86.Build.0 = Debug|Any CPU 38 | {9083D03A-A393-4EFD-80EB-17ADF18F4C82}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {9083D03A-A393-4EFD-80EB-17ADF18F4C82}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {9083D03A-A393-4EFD-80EB-17ADF18F4C82}.Release|x64.ActiveCfg = Release|Any CPU 41 | {9083D03A-A393-4EFD-80EB-17ADF18F4C82}.Release|x64.Build.0 = Release|Any CPU 42 | {9083D03A-A393-4EFD-80EB-17ADF18F4C82}.Release|x86.ActiveCfg = Release|Any CPU 43 | {9083D03A-A393-4EFD-80EB-17ADF18F4C82}.Release|x86.Build.0 = Release|Any CPU 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {52146A09-AD74-4763-84E8-8C333FE660A8} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /ModShardLauncherTest/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using Xunit; 2 | global using ModShardLauncher; -------------------------------------------------------------------------------- /ModShardLauncherTest/ModShardLauncherTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0-windows 5 | enable 6 | enable 7 | false 8 | false 9 | True 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | all 22 | 23 | 24 | runtime; build; native; contentfiles; analyzers; buildtransitive 25 | all 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /ModUtils/HookUtils.cs: -------------------------------------------------------------------------------- 1 | using Serilog; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace ModShardLauncher 9 | { 10 | public static partial class Msl 11 | { 12 | /// 13 | /// Add a hook with the name to . 14 | /// Havent done yet. 15 | /// 16 | /// 17 | /// 18 | /// All the things you want to get. 19 | public static void HookFunction(string functionName, string hookName, params string[] paramNames) 20 | { 21 | try 22 | { 23 | Log.Information(string.Format("Trying add hook in: {0}", functionName)); 24 | 25 | List? originalCode = GetStringGMLFromFile(functionName).Split("\n").ToList(); 26 | originalCode.Append($"var {hookName} = createHookObj({paramNames.Length}, {string.Join(", ", paramNames)})"); 27 | originalCode.Append($"SendMsg(\"HOK\", \"{hookName}\" + {hookName}, false)"); 28 | SetStringGMLInFile(string.Join("\n", originalCode), functionName); 29 | } 30 | catch (Exception ex) 31 | { 32 | Log.Error(ex, "Something went wrong"); 33 | throw; 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ModUtils/LogUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Serilog; 4 | using Newtonsoft.Json; 5 | using System.IO; 6 | using UndertaleModLib.Models; 7 | 8 | namespace ModShardLauncher; 9 | 10 | public static class LogUtils 11 | { 12 | public static void InjectLog() 13 | { 14 | string mslLog = @"function scr_msl_log(argument0) 15 | { 16 | var time = date_datetime_string(date_current_datetime()); 17 | if (global._msl_log != noone) 18 | { 19 | if (global._msl_log.buf != noone) 20 | { 21 | var string_log = ""["" + time + ""]: "" + argument0 + ""\n""; 22 | var len_log = string_byte_length(string_log); 23 | 24 | if (len_log > global._msl_log.size) 25 | { 26 | string_log = string_copy(string_log, 1, global._msl_log.size - 1) + ""\n""; 27 | len_log = string_byte_length(string_log); 28 | } 29 | 30 | if (len_log + global._msl_log.cur_size > global._msl_log.size) 31 | { 32 | scr_msl_log_save(); 33 | global._msl_log.nfile += 1; 34 | global._msl_log.cur_size = 0; 35 | } 36 | 37 | buffer_write(global._msl_log.buf, buffer_text, string_log); 38 | global._msl_log.cur_size += len_log; 39 | 40 | if (global._msl_log.timer == noone || !instance_exists(global._msl_log.timer)) 41 | { 42 | var t = instance_create_depth(0, 0, -100, o_msl_timer); 43 | t.end_time = 5; 44 | t.func = gml_Script_scr_msl_log_save; 45 | 46 | global._msl_log.timer = t.id; 47 | } 48 | } 49 | else 50 | { 51 | scr_actionsLogUpdate(""msl log buff does not exist. Please report that bug to the MSL devs.""); 52 | } 53 | } 54 | else 55 | { 56 | scr_actionsLogUpdate(""msl log does not exist. Please report that bug to the MSL devs.""); 57 | } 58 | }"; 59 | 60 | string mslLogSave = @"function scr_msl_log_save() 61 | { 62 | var nfile_name = global._msl_log.name + ""_"" + string(global._msl_log.nfile) + "".txt""; 63 | buffer_save_async(global._msl_log.buf, nfile_name, 0, global._msl_log.cur_size); 64 | instance_destroy(global._msl_log.timer); 65 | }"; 66 | 67 | UndertaleGameObject timer = Msl.AddObject("o_msl_timer", isPersistent: true); 68 | Msl.AddNewEvent(timer, @" 69 | func = -4; 70 | end_time = 0; 71 | cumulative_time = 0;", 72 | EventType.Create, 0); 73 | 74 | Msl.AddNewEvent(timer, @" 75 | cumulative_time += delta_time / 1000000; 76 | if (cumulative_time > end_time) 77 | { 78 | if (func != noone) 79 | { 80 | script_execute(func) 81 | } 82 | instance_destroy(); 83 | }", 84 | EventType.Step, 0); 85 | 86 | UndertaleGameObject log = Msl.AddObject("o_msl_log", isPersistent: true); 87 | Msl.AddNewEvent(log, @" 88 | size = 1000000 89 | buf = buffer_create(size, buffer_wrap, 1); 90 | cur_size = 0 91 | nfile = 0 92 | 93 | var curr_time = date_current_datetime(); 94 | var format_time = string_format(date_get_year(curr_time), 2, 0) + string_format(date_get_month(curr_time), 2, 0) + string_format(date_get_day(curr_time), 2, 0) + ""_"" + string_format(date_get_hour(curr_time), 2, 0) + string_format(date_get_minute(curr_time), 2, 0); 95 | name = ""Logs/msl_log_"" + string_replace_all(format_time, "" "", ""0""); 96 | 97 | timer = -4 98 | ", 99 | EventType.Create, 0); 100 | 101 | Msl.AddFunction(mslLogSave, "scr_msl_log_save"); 102 | Msl.AddFunction(mslLog, "scr_msl_log"); 103 | Msl.LoadGML(Msl.EventName("o_gameLoader", EventType.Create, 0)) 104 | .MatchAll() 105 | .InsertBelow(@"global._msl_log = instance_create_depth(0, 0, -100, o_msl_log);") 106 | .Save(); 107 | } 108 | } -------------------------------------------------------------------------------- /ModUtils/ObjectUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Serilog; 4 | using UndertaleModLib; 5 | using UndertaleModLib.Models; 6 | 7 | namespace ModShardLauncher 8 | { 9 | public static class GameObjectUtils 10 | { 11 | /// 12 | /// Extension method to apply several to a simultaneously. It is expected that all MslEvent.Code contain the path of their code. 13 | /// For example: 14 | /// 15 | /// gameObject.ApplyEvent(ModFiles, 16 | /// new MslEvent(fileName0, EventType.Create, 0), 17 | /// new MslEvent(fileName1, EventType.Other, 10), 18 | /// new MslEvent(fileName2, EventType.Other, 11) 19 | /// ); 20 | /// 21 | /// 22 | /// 23 | /// 24 | /// 25 | /// 26 | static public void ApplyEvent(this UndertaleGameObject gameObject, ModFile modFile, params MslEvent[] mslEvents) 27 | { 28 | foreach (MslEvent mslEvent in mslEvents) 29 | { 30 | mslEvent.Apply(gameObject, modFile); 31 | } 32 | } 33 | /// 34 | /// Extension method to apply several to a simultaneously. It is expected that all MslEvent.Code contain their code directly. 35 | /// For example: 36 | /// 37 | /// gameObject.ApplyEvent( 38 | /// new MslEvent(code0, EventType.Create, 0), 39 | /// new MslEvent(code1, EventType.Other, 10), 40 | /// new MslEvent(code2, EventType.Other, 11) 41 | /// ); 42 | /// 43 | /// 44 | /// 45 | /// 46 | /// 47 | static public void ApplyEvent(this UndertaleGameObject gameObject, params MslEvent[] mslEvents) 48 | { 49 | foreach (MslEvent mslEvent in mslEvents) 50 | { 51 | mslEvent.Apply(gameObject); 52 | } 53 | } 54 | } 55 | public static partial class Msl 56 | { 57 | /// 58 | /// Add and return a new named to the data.win if this name is not used already. 59 | /// Else return the existing . 60 | /// This methods does not allow any parametrization when creating this . 61 | /// 62 | /// 63 | /// 64 | public static UndertaleGameObject AddObject(string name) 65 | { 66 | return AddObject( 67 | name, 68 | spriteName:"", 69 | parentName: "", 70 | isVisible: false, 71 | isPersistent: false, 72 | isAwake: false, 73 | collisionShapeFlags: CollisionShapeFlags.Circle); 74 | } 75 | /// 76 | /// Add and return a new named to the data.win if this name is not used already. 77 | /// Else return the existing . 78 | /// A lot of parametrization is possible when creating this . 79 | /// 80 | /// 81 | /// 82 | /// 83 | /// 84 | /// 85 | /// 86 | /// 87 | /// 88 | /// 89 | public static UndertaleGameObject AddObject( 90 | string name, 91 | string spriteName = "", 92 | string parentName = "", 93 | bool isVisible = false, 94 | bool isPersistent = false, 95 | bool isAwake = false, 96 | CollisionShapeFlags collisionShapeFlags = CollisionShapeFlags.Circle) 97 | { 98 | try 99 | { 100 | // check if the object exists already 101 | UndertaleGameObject? existingObj = ModLoader.Data.GameObjects.FirstOrDefault(t => t.Name.Content == name); 102 | if(existingObj != null) 103 | { 104 | Log.Information(string.Format("Cannot create the GameObject since it already exists: {0}", name.ToString())); 105 | return existingObj; 106 | } 107 | 108 | // retrieve possible parent and sprite 109 | UndertaleSprite? sprite = null; 110 | if (spriteName != "") sprite = GetSprite(spriteName); 111 | UndertaleGameObject? parent = null; 112 | if (parentName != "") parent = GetObject(parentName); 113 | 114 | // doesnt exist so it can be added 115 | UndertaleGameObject obj = new() 116 | { 117 | Name = ModLoader.Data.Strings.MakeString(name), 118 | Sprite = sprite, 119 | ParentId = parent, 120 | Visible = isVisible, 121 | Persistent = isPersistent, 122 | CollisionShape = collisionShapeFlags, 123 | Awake = isAwake, 124 | }; 125 | ModLoader.Data.GameObjects.Add(obj); 126 | Log.Information(string.Format("Successfully created gameObject: {0}", name.ToString())); 127 | return obj; 128 | } 129 | catch 130 | { 131 | throw; 132 | } 133 | } 134 | /// 135 | /// Return the named if it exists. Else raise an exception. 136 | /// 137 | /// 138 | /// 139 | public static UndertaleGameObject GetObject(string name) 140 | { 141 | try 142 | { 143 | UndertaleGameObject gameObject = ModLoader.Data.GameObjects.First(t => t.Name.Content == name); 144 | Log.Information(string.Format("Found gameObject: {0}", name.ToString())); 145 | return gameObject; 146 | } 147 | catch 148 | { 149 | throw; 150 | } 151 | } 152 | /// 153 | /// Replace the named by . 154 | /// Raise an exception if the named does not exist. 155 | /// 156 | /// 157 | /// 158 | public static void SetObject(string name, UndertaleGameObject o) 159 | { 160 | try 161 | { 162 | (int indexObj, _) = ModLoader.Data.GameObjects.Enumerate().First(t => t.Item2.Name.Content == name); 163 | ModLoader.Data.GameObjects[indexObj] = o; 164 | Log.Information(string.Format("Successfully replaced gameObject: {0}", name.ToString())); 165 | } 166 | catch(Exception ex) 167 | { 168 | Log.Error(ex, "Something went wrong"); 169 | throw; 170 | } 171 | } 172 | } 173 | } -------------------------------------------------------------------------------- /ModUtils/TableUtils/Backers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Serilog; 3 | 4 | namespace ModShardLauncher; 5 | 6 | public partial class Msl 7 | { 8 | public static void InjectTableBackers(string? name = null, string? nickname = null) 9 | { 10 | // Table filename 11 | const string tableName = "gml_GlobalScript_table_backers"; 12 | 13 | // Load table if it exists 14 | List table = ThrowIfNull(ModLoader.GetTable(tableName)); 15 | 16 | // Prepare line 17 | string newline = $"{name};{nickname};"; 18 | 19 | // Add line to table 20 | table.Add(newline); 21 | ModLoader.SetTable(table, tableName); 22 | Log.Information($"Injected {name}:{nickname} into {tableName} table."); 23 | } 24 | } -------------------------------------------------------------------------------- /ModUtils/TableUtils/ContractsStats.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Linq; 5 | using Serilog; 6 | 7 | namespace ModShardLauncher; 8 | 9 | [SuppressMessage("ReSharper", "InconsistentNaming")] 10 | [SuppressMessage("ReSharper", "IdentifierTypo")] 11 | 12 | public partial class Msl 13 | { 14 | public enum ContractsStatsCategory 15 | { 16 | kill, 17 | destroy, 18 | clear, 19 | interact, 20 | find 21 | } 22 | 23 | public enum ContractsStatsDungeonType 24 | { 25 | Crypt, 26 | Catacombs, 27 | Bastion 28 | } 29 | 30 | public static void InjectTableContractsStats( 31 | string id, 32 | byte Amount, 33 | ContractsStatsCategory Category, 34 | string Faction, // Could be an enum ? Leaving as string for modded factions for now 35 | string Village_Type, // Could be an enum ? Leaving as string for modded villages and multiple choices 36 | ContractsStatsDungeonType DungeonType, 37 | string Script, 38 | byte Contract_Deadline, 39 | byte Contract_Expiration, 40 | short Contract_Reward, 41 | short Contract_Reputation, 42 | short Contract_Reputation_Loss, 43 | byte Village_Aftermath, 44 | string Dungeon_Aftermath, // Could be an enum ? Leaving as string for multiple choices 45 | string Contract_NPC, 46 | byte Contract_Respawn, // Unknown type, assuming byte for now 47 | byte Mod_time, // Unknown type, assuming byte for now 48 | bool Can_Generate, 49 | float k 50 | ) 51 | { 52 | // Table filename 53 | const string tableName = "gml_GlobalScript_table_contracts_stats"; 54 | 55 | // Load table if it exists 56 | List table = ThrowIfNull(ModLoader.GetTable(tableName)); 57 | 58 | // Prepare line 59 | string newline = $"{id};{Amount};{Category};{Faction};{Village_Type};{DungeonType};{Script};{Contract_Deadline};{Contract_Expiration};{Contract_Reward};{Contract_Reputation};{Contract_Reputation_Loss};{Village_Aftermath};{Dungeon_Aftermath};{Contract_NPC};{Contract_Respawn};{Mod_time};{Can_Generate};{k};"; 60 | 61 | // Find hook 62 | (int ind, string? foundLine) = table.Enumerate().FirstOrDefault(x => x.Item2.Contains("bastion_HostageRottenWillow")); 63 | 64 | // Add line to table 65 | if (foundLine != null) 66 | { 67 | table.Insert(ind + 1, newline); 68 | ModLoader.SetTable(table, tableName); 69 | Log.Information($"Injected contract {id} into {tableName}"); 70 | } 71 | else 72 | { 73 | Log.Error($"Hook not found in {tableName}. {id} was not injected."); 74 | throw new Exception($"Hook not found in {tableName}. {id} was not injected."); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /ModUtils/TableUtils/Drops.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using Serilog; 7 | using Serilog.Debugging; 8 | 9 | namespace ModShardLauncher; 10 | 11 | [SuppressMessage("ReSharper", "InconsistentNaming")] 12 | public partial class Msl 13 | { 14 | private static string EqTypeParser(HashSet eqTypes) 15 | { 16 | string eqTypesStr = ""; 17 | foreach (DropsEqType t in eqTypes) 18 | eqTypesStr += $"{GetEnumMemberValue(t)}, "; 19 | eqTypesStr = eqTypesStr.TrimEnd(',', ' '); 20 | return eqTypesStr; 21 | } 22 | 23 | public enum DropsHook 24 | { 25 | CRYPTS, 26 | CATACOMBS, 27 | BASTIONS, 28 | OTHER 29 | } 30 | 31 | public enum DropsTier 32 | { 33 | [EnumMember(Value = "1")] 34 | Tier1, 35 | [EnumMember(Value = "2")] 36 | Tier2, 37 | [EnumMember(Value = "3")] 38 | Tier3, 39 | [EnumMember(Value = "4")] 40 | Tier4, 41 | [EnumMember(Value = "5")] 42 | Tier5 43 | } 44 | 45 | [Flags] 46 | public enum DropsSlotTags 47 | { 48 | raw = 1, 49 | common = 2 50 | } 51 | 52 | public enum DropsEqType 53 | { 54 | weapon, 55 | dagger, 56 | [EnumMember(Value = "2HStaff")] 57 | TwoHandedStaff, 58 | Chest, 59 | Legs, 60 | Waist, 61 | Arms, 62 | Head, 63 | jewelry, 64 | sword, 65 | mace, 66 | axe, 67 | spear, 68 | crossbow 69 | } 70 | 71 | [Flags] 72 | public enum DropsEqTags 73 | { 74 | aldor = 1, 75 | magic = 2, 76 | elven = 4, 77 | unique = 8 78 | } 79 | 80 | [Flags] 81 | public enum DropsEqRarity 82 | { 83 | common = 1, 84 | uncommon = 2, 85 | rare = 4, 86 | unique = 8 87 | } 88 | 89 | public record DropsSlot(string id, DropsSlotTags? tags, string count, byte chance); 90 | public record DropsEq(HashSet types, DropsEqTags tags, DropsEqRarity? rarity, string dur, byte chance); 91 | 92 | public static void InjectTableDrops( 93 | DropsHook hook, 94 | string id, 95 | DropsTier tier, 96 | HashSet? tierMod = null, 97 | DropsSlot? slot_1 = null, 98 | DropsSlot? slot_2 = null, 99 | DropsSlot? slot_3 = null, 100 | DropsSlot? slot_4 = null, 101 | DropsSlot? slot_5 = null, 102 | DropsSlot? slot_6 = null, 103 | DropsSlot? slot_7 = null, 104 | DropsSlot? slot_8 = null, 105 | DropsSlot? slot_9 = null, 106 | DropsEq? eq_1 = null, 107 | DropsEq? eq_2 = null, 108 | DropsEq? eq_3 = null, 109 | DropsEq? eq_4 = null, 110 | DropsEq? eq_5 = null 111 | ) 112 | { 113 | // Table filename 114 | const string tableName = "gml_GlobalScript_table_drops"; 115 | 116 | // Load table if it exists 117 | List table = ThrowIfNull(ModLoader.GetTable(tableName)); 118 | 119 | // Parse tier 120 | string tierModStr = ""; 121 | if (tierMod != null) 122 | { 123 | foreach (SurfaceSpawnTier t in tierMod) 124 | tierModStr += $"{GetEnumMemberValue(t)}, "; 125 | tierModStr = tierModStr.TrimEnd(',', ' '); 126 | } 127 | 128 | // Prepare line 129 | string newline = $"{id};{GetEnumMemberValue(tier)};{tierModStr};{slot_1?.id};{slot_1?.tags};{slot_1?.count};{slot_1?.chance};;{slot_2?.id};{slot_2?.tags};{slot_2?.count};{slot_2?.chance};;{slot_3?.id};{slot_3?.tags};{slot_3?.count};{slot_3?.chance};;{slot_4?.id};{slot_4?.tags};{slot_4?.count};{slot_4?.chance};;{slot_5?.id};{slot_5?.tags};{slot_5?.count};{slot_5?.chance};;{slot_6?.id};{slot_6?.tags};{slot_6?.count};{slot_6?.chance};;{slot_7?.id};{slot_7?.tags};{slot_7?.count};{slot_7?.chance};;{slot_8?.id};{slot_8?.tags};{slot_8?.count};{slot_8?.chance};;{slot_9?.id};{slot_9?.tags};{slot_9?.count};{slot_9?.chance};;{(eq_1 != null ? EqTypeParser(eq_1.types) : "")};{eq_1?.tags};{eq_1?.rarity};{eq_1?.dur};{eq_1?.chance};;{(eq_2 != null ? EqTypeParser(eq_2.types) : "")};{eq_2?.rarity};{eq_2?.dur};{eq_2?.chance};;{(eq_3 != null ? EqTypeParser(eq_3.types) : "")};{eq_3?.rarity};{eq_3?.dur};{eq_3?.chance};;{(eq_4 != null ? EqTypeParser(eq_4.types) : "")};{eq_4?.rarity};{eq_4?.dur};{eq_4?.chance};;{(eq_5 != null ? EqTypeParser(eq_5.types) : "")};{eq_5?.rarity};{eq_5?.dur};{eq_5?.chance};"; 130 | 131 | // Find hook 132 | string hookStr = "// " + hook; 133 | (int ind, string? foundLine) = table.Enumerate().FirstOrDefault(x => x.Item2.Contains(hookStr)); 134 | 135 | // Add line to table 136 | if (foundLine != null) 137 | { 138 | table.Insert(ind + 1, newline); 139 | ModLoader.SetTable(table, tableName); 140 | Log.Information($"Injected Drop {id} into table {tableName} under {hook}"); 141 | } 142 | else 143 | { 144 | Log.Error($"Cannot find hook {hook} in table {tableName}"); 145 | throw new Exception($"Cannot find hook {hook} in table {tableName}"); 146 | } 147 | } 148 | } -------------------------------------------------------------------------------- /ModUtils/TableUtils/DungeonsSpawn.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using Serilog; 7 | 8 | namespace ModShardLauncher; 9 | 10 | [SuppressMessage("ReSharper", "InconsistentNaming")] 11 | public partial class Msl 12 | { 13 | public enum DungeonsSpawnHook 14 | { 15 | GENERIC, 16 | UNDEAD 17 | } 18 | 19 | public enum DungeonsSpawnTemplateType 20 | { 21 | Normal, 22 | Advanced, 23 | Special 24 | } 25 | 26 | public enum DungeonsSpawnTier 27 | { 28 | [EnumMember(Value = "1")] 29 | Tier1, 30 | [EnumMember(Value = "2")] 31 | Tier2, 32 | [EnumMember(Value = "3")] 33 | Tier3, 34 | [EnumMember(Value = "4")] 35 | Tier4, 36 | [EnumMember(Value = "5")] 37 | Tier5 38 | } 39 | 40 | [Flags] 41 | public enum DungeonsSpawnFaction 42 | { 43 | Undead = 1, 44 | Vampire = 2, 45 | Brigand = 4 46 | } 47 | 48 | public static void InjectTableDungeonsSpawn( 49 | DungeonsSpawnHook hook, 50 | string id, // Could be byte, not sure how it's used 51 | DungeonsSpawnTemplateType Template_Type, 52 | HashSet Dungeon_Tier, 53 | DungeonsSpawnFaction Faction, 54 | string Enemy1, 55 | string? Enemy2 = null, 56 | string? Enemy3 = null, 57 | string? Enemy4 = null, 58 | string? Enemy5 = null, 59 | string? Enemy6 = null 60 | ) 61 | { 62 | // Table filename 63 | const string tableName = "gml_GlobalScript_table_dungeons_spawn"; 64 | 65 | // Load table if it exists 66 | List table = ThrowIfNull(ModLoader.GetTable(tableName)); 67 | 68 | // Parse Dungeon_Tier 69 | string dungeonTierStr = ""; 70 | foreach (DungeonsSpawnTier tier in Dungeon_Tier) 71 | dungeonTierStr += $"{GetEnumMemberValue(tier)}, "; 72 | dungeonTierStr = dungeonTierStr.TrimEnd(',', ' '); 73 | 74 | // Prepare new line 75 | string newline = $"{id};{Template_Type};{dungeonTierStr};{Faction};{Enemy1};{Enemy2};{Enemy3};{Enemy4};{Enemy5};{Enemy6};"; 76 | 77 | // Find hook 78 | string hookStr = "// " + GetEnumMemberValue(hook); 79 | (int ind, string? foundLine) = table.Enumerate().FirstOrDefault(x => x.Item2.Contains(hookStr)); 80 | 81 | // Add line to table 82 | if (foundLine != null) 83 | { 84 | table.Insert(ind + 1, newline); 85 | ModLoader.SetTable(table, tableName); 86 | Log.Information($"Injected Dungeon Spawn {id} into {tableName} under {hook}"); 87 | } 88 | else 89 | { 90 | Log.Error($"Cannot find Hook {hook} in table {tableName}"); 91 | throw new Exception($"Hook {hook} not found in table {tableName}"); 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /ModUtils/TableUtils/PotionsStats.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Serilog; 4 | 5 | namespace ModShardLauncher; 6 | 7 | public partial class Msl 8 | { 9 | public static void InjectTablePotionsStats(string name, string effectScript, params string[] blockedEffects) 10 | { 11 | // Weird table. It has no header, and seems to work like this: 12 | // Name of the potion | script with actual effect | any number of incompatible effects that cannot coexist with the actual effect 13 | // 14 | // Example: 15 | // MyPotion;myEffectScript;blockedEffectScript1;blockedEffectScript2;blockedEffectScript3;blockedEffectScript4... 16 | // 17 | // This seems to be used when rolling potions in the game, to ensure that the potion doesn't have conflicting effects. 18 | // Needs more investigation to figure out how many blocked effects are allowed, max vanilla potion has 26. 19 | 20 | // Table filename 21 | const string tableName = "gml_GlobalScript_table_potions_stats"; 22 | 23 | // Load table if it exists 24 | List table = ThrowIfNull(ModLoader.GetTable(tableName)); 25 | 26 | // Prepare line 27 | string newline = $"{name};{effectScript};{string.Join(";", blockedEffects)};"; 28 | 29 | // Adding potentially missing ; at the end of the line. Could be unnecessary ? 30 | while (newline.Count(t => t == ';') < 28) 31 | newline += ';'; 32 | 33 | // Add line to end of table 34 | table.Add(newline); 35 | ModLoader.SetTable(table, tableName); 36 | Log.Information($"Injected {name} into {tableName} table."); 37 | } 38 | } -------------------------------------------------------------------------------- /ModUtils/TableUtils/RecipesCook.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using Serilog; 7 | 8 | namespace ModShardLauncher; 9 | 10 | [SuppressMessage("ReSharper", "InconsistentNaming")] 11 | [SuppressMessage("ReSharper", "IdentifierTypo")] 12 | public partial class Msl 13 | { 14 | public enum RecipesCookHook 15 | { 16 | [EnumMember(Value = "FRYING & SALTING")] 17 | FryingAndSalting, 18 | SOUPS, 19 | [EnumMember(Value = "MAIN COURSES")] 20 | MainCourses, 21 | SALADS, 22 | DESSERTS 23 | } 24 | 25 | public enum RecipesCookCategory 26 | { 27 | other, 28 | soup, 29 | main, 30 | side, 31 | dessert 32 | } 33 | 34 | public enum RecipesCookAdditive 35 | { 36 | X, 37 | V, 38 | butter 39 | } 40 | 41 | public enum RecipesCookSource 42 | { 43 | [EnumMember(Value = "Base Recipe")] 44 | BaseRecipe, 45 | Trade, 46 | [EnumMember(Value = "Random Find")] 47 | RandomFind, 48 | [EnumMember(Value = "Reputation Reward")] 49 | ReputationReward 50 | } 51 | 52 | public static void InjectTableRecipesCook( 53 | RecipesCookHook hook, 54 | string NAME, 55 | RecipesCookCategory CAT, 56 | string? Recipe1 = null, 57 | string? Recipe2 = null, 58 | string? Recipe3 = null, 59 | string? Recipe4 = null, 60 | string? Recipe5 = null, 61 | RecipesCookAdditive ADDITIVES = RecipesCookAdditive.X, 62 | bool COOKPOT = false, 63 | bool PLATE = false, 64 | bool DEEP_PLATE = false, 65 | bool SATIETY = false, 66 | short? MORALE = null, 67 | short? SANITY = null, 68 | RecipesCookSource SOURCE = RecipesCookSource.BaseRecipe 69 | ) 70 | { 71 | // Table filename 72 | const string tableName = "gml_GlobalScript_table_recipes_cook"; 73 | 74 | // Load table if it exists 75 | List table = ThrowIfNull(ModLoader.GetTable(tableName)); 76 | 77 | // Prepare line 78 | string newline = $"{NAME};{CAT};{Recipe1 ?? "-"};{Recipe2 ?? "-"};{Recipe3 ?? "-"};{Recipe4 ?? "-"};{Recipe5 ?? "-"};{GetEnumMemberValue(ADDITIVES)};{(COOKPOT ? "V" : "X")};{(PLATE ? "V" : "X")};{(DEEP_PLATE ? "V" : "X")};{(SATIETY ? "V" : "X")};{MORALE};{SANITY};{GetEnumMemberValue(SOURCE)};"; 79 | 80 | // Find hook 81 | string hookStr = "// " + GetEnumMemberValue(hook); 82 | (int ind, string? foundLine) = table.Enumerate().FirstOrDefault(x => x.Item2.Contains(hookStr)); 83 | 84 | // Add line to table 85 | if (foundLine != null) 86 | { 87 | table.Insert(ind + 1, newline); 88 | ModLoader.SetTable(table, tableName); 89 | Log.Information($"Injected Armor {NAME} into table {tableName} under {hook}"); 90 | } 91 | else 92 | { 93 | Log.Error($"Cannot find hook {hook} in table {tableName}"); 94 | throw new Exception($"Cannot find hook {hook} in table {tableName}"); 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /ModUtils/TableUtils/RecipesCraft.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using Serilog; 7 | 8 | namespace ModShardLauncher; 9 | 10 | [SuppressMessage("ReSharper", "InconsistentNaming")] 11 | public partial class Msl 12 | { 13 | public enum RecipesCraftHook 14 | { 15 | BASIC, 16 | ADVANCED, 17 | OTHER 18 | } 19 | public enum RecipesCraftCategory 20 | { 21 | basic, 22 | advanced, 23 | other 24 | } 25 | 26 | public enum RecipesCraftSource 27 | { 28 | Trade, 29 | [EnumMember(Value = "Base Recipe")] 30 | BaseRecipe, 31 | [EnumMember(Value = "Random Find")] 32 | RandomFind, 33 | [EnumMember(Value = "Pol Find")] 34 | PolFind 35 | } 36 | 37 | public static void InjectTableRecipesCraft( 38 | RecipesCraftHook hook, 39 | string NAME, 40 | RecipesCraftCategory CAT, 41 | ushort XP, 42 | ushort AMOUNT, 43 | RecipesCraftSource SOURCE, 44 | string Recipe1, 45 | string? Recipe2 = null, 46 | string? Recipe3 = null, 47 | string? Recipe4 = null, 48 | string? Recipe5 = null, 49 | string? Recipe6 = null 50 | ) 51 | { 52 | // Table filename 53 | const string tableName = "gml_GlobalScript_table_recipes_craft"; 54 | 55 | // Load table if it exists 56 | List table = ThrowIfNull(ModLoader.GetTable(tableName)); 57 | 58 | // Prepare new line 59 | string newline = $"{NAME};{CAT};{Recipe1};{Recipe2 ?? "-"};{Recipe3 ?? "-"};{Recipe4 ?? "-"};{Recipe5 ?? "-"};{Recipe6 ?? "-"};{AMOUNT};{XP};{GetEnumMemberValue(SOURCE)}"; 60 | 61 | // Find hook 62 | (int ind, string? foundLine) = table.Enumerate().FirstOrDefault(x => x.Item2.Contains(hook.ToString())); 63 | 64 | // Add line to table 65 | if (foundLine != null) 66 | { 67 | table.Insert(ind + 1, newline); 68 | ModLoader.SetTable(table, tableName); 69 | Log.Information($"Injected craft recipe {NAME} into {tableName} under {hook}"); 70 | } 71 | else 72 | { 73 | Log.Error($"Cannot find hook {hook} in table {tableName}"); 74 | throw new Exception($"Hook {hook} not found in table {tableName}"); 75 | } 76 | } 77 | } -------------------------------------------------------------------------------- /ModUtils/TableUtils/SkillsStats.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using Serilog; 7 | 8 | namespace ModShardLauncher; 9 | 10 | [SuppressMessage("ReSharper", "InconsistentNaming")] 11 | [SuppressMessage("ReSharper", "IdentifierTypo")] 12 | public partial class Msl 13 | { 14 | public enum SkillsStatsHook 15 | { 16 | BASIC, 17 | RANGED, 18 | SWORDS, 19 | [EnumMember(Value = "2H SWORDS")] 20 | TWOHANDEDSWORDS, 21 | [EnumMember(Value = "2H MACES")] 22 | TWOHANDEDMACES, 23 | [EnumMember(Value = "2H AXES")] 24 | TWOHANDEDAXES, 25 | AXES, 26 | MACES, 27 | STAVES, 28 | SHIELDS, 29 | DAGGERS, 30 | [EnumMember(Value = "DUAL WIELDING")] 31 | DUALWIELDING, 32 | SPEARS, 33 | COMBAT, 34 | ATHLETICS, 35 | SURVIVAL, 36 | PYRO, 37 | GEO, 38 | ELECTRO, 39 | ARMOR, 40 | [EnumMember(Value = "MAGIC MASTERY")] 41 | MAGICMASTERY, 42 | UNDEAD, 43 | [EnumMember(Value = "PROLOGUE STATUES")] 44 | PROLOGUESTATUES, 45 | [EnumMember(Value = "PROLOGUE ARCHON")] 46 | PROLOGUEARCHON, 47 | PROSELYTES, 48 | BRIGANDS, 49 | [EnumMember(Value = "ANCIENT TROLL")] 50 | ANCIENTTROLL, 51 | BEASTS, 52 | MANTICORE 53 | } 54 | 55 | public enum SkillsStatsTarget 56 | { 57 | [EnumMember(Value = "No Target")] 58 | NoTarget, 59 | [EnumMember(Value = "Target Object")] 60 | TargetObject, 61 | [EnumMember(Value = "Target Point")] 62 | TargetPoint, 63 | [EnumMember(Value = "Target Area")] 64 | TargetArea, 65 | [EnumMember(Value = "Target Ally")] 66 | TargetAlly 67 | } 68 | 69 | public enum SkillsStatsPattern 70 | { 71 | normal, 72 | five, 73 | line, 74 | circle, 75 | pyramid, 76 | pyramid_shift 77 | } 78 | 79 | public enum SkillsStatsValidator 80 | { 81 | [EnumMember(Value = "")] 82 | none, 83 | AVOID_TILEMARKS, 84 | DASH 85 | } 86 | 87 | public enum SkillsStatsClass 88 | { 89 | skill, 90 | spell, 91 | attack, 92 | } 93 | 94 | public enum SkillsStatsBranch 95 | { 96 | none, // For some reason the string none has to be written, rather than leaving the field empty. Inconsistent but it is what it is. 97 | ranged, 98 | sword, 99 | [EnumMember(Value = "2hsword")] 100 | two_handed_sword, 101 | [EnumMember(Value = "2hmace")] 102 | two_handed_mace, 103 | [EnumMember(Value = "2haxe")] 104 | two_handed_axe, 105 | axe, 106 | mace, 107 | staff, 108 | shield, 109 | dagger, 110 | dual, 111 | spear, 112 | combat, 113 | athletic, 114 | pyromancy, 115 | geomancy, 116 | electromancy, 117 | armor, 118 | magic_mastery, 119 | necromancy, 120 | sanguimancy 121 | } 122 | 123 | public enum SkillsStatsMetacategory 124 | { 125 | [EnumMember(Value = "")] 126 | none, 127 | weapon, 128 | utility 129 | } 130 | 131 | public static void InjectTableSkillsStats( 132 | SkillsStatsHook hook, 133 | string id, 134 | string? Object = null, 135 | SkillsStatsTarget Target = SkillsStatsTarget.NoTarget, 136 | string Range = "0", 137 | ushort KD = 0, 138 | ushort MP = 0, 139 | ushort Reserv = 0, 140 | ushort Duration = 0, 141 | byte AOE_Lenght = 0, 142 | byte AOE_Width = 0, 143 | bool is_movement = false, 144 | SkillsStatsPattern Pattern = SkillsStatsPattern.normal, 145 | SkillsStatsValidator Validators = SkillsStatsValidator.none, 146 | SkillsStatsClass Class = SkillsStatsClass.skill, 147 | bool Bonus_Range = false, // could be byte ? Not sure as only values are 0 and 1 148 | string? Starcast = null, 149 | SkillsStatsBranch Branch = SkillsStatsBranch.none, 150 | bool is_knockback = false, 151 | bool Crime = false, 152 | SkillsStatsMetacategory metacategory = SkillsStatsMetacategory.none, 153 | short FMB = 0, 154 | string AP = "x", 155 | bool Attack = false, 156 | bool Stance = false, 157 | bool Charge = false, 158 | bool Maneuver = false, 159 | bool Spell = false 160 | ) 161 | { 162 | // Table filename 163 | const string tableName = "gml_GlobalScript_table_skills_stats"; 164 | 165 | // Load table if it exists 166 | List table = ThrowIfNull(ModLoader.GetTable(tableName)); 167 | 168 | // Prepare line 169 | string newline = $"{id};{Object};{GetEnumMemberValue(Target)};{Range};{KD};{MP};{Reserv};{Duration};{AOE_Lenght};{AOE_Width};{(is_movement ? "1" : "0")};{Pattern};{GetEnumMemberValue(Validators)};{Class};{(Bonus_Range ? "1" : "0")};{Starcast};{GetEnumMemberValue(Branch)};{(is_knockback ? "1" : "0")};{(Crime ? "1" : "")};{GetEnumMemberValue(metacategory)};{FMB};{AP};{(Attack ? "1" : "")};{(Stance ? "1" : "")};{(Charge ? "1" : "")};{(Maneuver ? "1" : "")};{(Spell ? "1" : "")};"; 170 | 171 | // Find Hook 172 | string hookStr = "// " + GetEnumMemberValue(hook); 173 | (int ind, string? foundLine) = table.Enumerate().FirstOrDefault(x => x.Item2.Contains(hookStr)); 174 | 175 | // Add line to table 176 | if (foundLine != null) 177 | { 178 | table.Insert(ind + 1, newline); 179 | ModLoader.SetTable(table, tableName); 180 | Log.Information($"Injected Skill Stat {id} into {tableName} under {hook}"); 181 | } 182 | else 183 | { 184 | Log.Error($"Cannot find Hook {hook} in table {tableName}"); 185 | throw new Exception($"Hook {hook} not found in table {tableName}"); 186 | } 187 | } 188 | } -------------------------------------------------------------------------------- /ModUtils/TableUtils/SurfaceSpawn.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using Serilog; 7 | 8 | namespace ModShardLauncher; 9 | 10 | [SuppressMessage("ReSharper", "InconsistentNaming")] 11 | [SuppressMessage("ReSharper", "IdentifierTypo")] 12 | public partial class Msl 13 | { 14 | public enum SurfaceSpawnSlot 15 | { 16 | Hostile, 17 | Neutral 18 | } 19 | 20 | public enum SurfaceSpawnTier 21 | { 22 | [EnumMember(Value = "1")] 23 | Tier1, 24 | [EnumMember(Value = "2")] 25 | Tier2, 26 | [EnumMember(Value = "3")] 27 | Tier3, 28 | [EnumMember(Value = "4")] 29 | Tier4, 30 | [EnumMember(Value = "5")] 31 | Tier5 32 | } 33 | 34 | // Bitmask enum, use like this: `SurfaceSpawnBiome Biome = SurfaceSpawnBiome.Forest | SurfaceSpawnBiome.Steppe` to have multiple choices 35 | [Flags] 36 | public enum SurfaceSpawnBiome 37 | { 38 | Any = 1, 39 | Forest = 2, 40 | Pineforest = 4, 41 | Field = 8, 42 | Pinefield = 16, 43 | Steppe = 32 44 | } 45 | 46 | public enum SurfaceSpawnFaction 47 | { 48 | Brigand, 49 | Beast, 50 | // Anything below is not confirmed, just assuming it would work 51 | Undead, 52 | Vampire, 53 | GrandMagistrate, 54 | RottenWillow, 55 | Mercenary, 56 | Neutral 57 | } 58 | 59 | public static void InjectTableSurfaceSpawn( 60 | SurfaceSpawnSlot Slot, 61 | // SurfaceSpawnTier Tier, 62 | HashSet Tier, 63 | SurfaceSpawnBiome Biome, 64 | SurfaceSpawnFaction Faction, 65 | byte Spawn_Chance, 66 | string Enemy1, 67 | string? Enemy2 = null, 68 | string? Enemy3 = null, 69 | string? Enemy4 = null, 70 | string? Enemy5 = null, 71 | string? Enemy6 = null 72 | ) 73 | { 74 | // Table filename 75 | const string tableName = "gml_GlobalScript_table_surface_spawn"; 76 | 77 | // Load table if it exists 78 | List table = ThrowIfNull(ModLoader.GetTable(tableName)); 79 | 80 | // Parse tier 81 | string tierStr = ""; 82 | foreach (SurfaceSpawnTier tier in Tier) 83 | tierStr += $"{GetEnumMemberValue(tier)}, "; 84 | tierStr = tierStr.TrimEnd(',', ' '); 85 | 86 | // Prepare line 87 | string newline = $"{Slot};{tierStr};{Biome};{Faction};{Spawn_Chance};{Enemy1};{Enemy2};{Enemy3};{Enemy4};{Enemy5};{Enemy6};"; 88 | 89 | // Add line to table 90 | table.Add(newline); 91 | ModLoader.SetTable(table, tableName); 92 | Log.Information($"Injected a Spawn into table {tableName}"); 93 | } 94 | } -------------------------------------------------------------------------------- /ModUtils/TableUtils/TableUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Reflection; 4 | using System.Runtime.Serialization; 5 | 6 | namespace ModShardLauncher 7 | { 8 | public partial class Msl 9 | { 10 | private static string? GetEnumMemberValue(this T value) 11 | where T : Enum 12 | { 13 | return typeof(T) 14 | .GetTypeInfo() 15 | .DeclaredMembers 16 | .SingleOrDefault(x => x.Name == value.ToString())? 17 | .GetCustomAttribute(false)? 18 | .Value ?? value.ToString(); 19 | } 20 | 21 | // Tables left to do : 22 | // - ai 23 | // - supply / demand if necessary ? 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ModUtils/TableUtils/TableWeapons.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics.CodeAnalysis; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using Serilog; 7 | 8 | namespace ModShardLauncher; 9 | 10 | [SuppressMessage("ReSharper", "InconsistentNaming")] 11 | [SuppressMessage("ReSharper", "IdentifierTypo")] 12 | public partial class Msl 13 | { 14 | public enum WeaponsTier 15 | { 16 | [EnumMember(Value = "1")] 17 | Tier1, 18 | [EnumMember(Value = "2")] 19 | Tier2, 20 | [EnumMember(Value = "3")] 21 | Tier3, 22 | [EnumMember(Value = "4")] 23 | Tier4, 24 | [EnumMember(Value = "5")] 25 | Tier5 26 | } 27 | 28 | /// 29 | /// Enum used in Weapons table. 30 | /// Defines the slot the weapon can be equipped in. 31 | /// 32 | public enum WeaponsSlot 33 | { 34 | sword, 35 | axe, 36 | mace, 37 | dagger, 38 | [EnumMember(Value = "2hsword")] 39 | twohandedsword, 40 | spear, 41 | [EnumMember(Value = "2haxe")] 42 | twohandedaxe, 43 | [EnumMember(Value = "2hmace")] 44 | twohandedmace, 45 | bow, 46 | crossbow, 47 | sling, 48 | [EnumMember(Value = "2hStaff")] 49 | twohandedstaff, 50 | chain, 51 | lute 52 | } 53 | 54 | /// 55 | /// Enum used in Weapons table. 56 | /// Defines the rarity of the weapon. 57 | /// 58 | public enum WeaponsRarity 59 | { 60 | Common, 61 | Unique 62 | // Legendary // Doesn't seem to be used post-RtR 63 | } 64 | 65 | /// 66 | /// Enum used in Weapons table. 67 | /// Defines the material the weapon is made out of. 68 | /// 69 | public enum WeaponsMaterial 70 | { 71 | wood, 72 | metal, 73 | leather 74 | } 75 | 76 | /// 77 | /// Enum used in Weapons table. 78 | /// Defines the rarity of the weapon in description. 79 | /// 80 | public enum WeaponsTags 81 | { 82 | // SPECIAL 83 | unique, 84 | magic, 85 | special, 86 | [EnumMember(Value = "special exc")] 87 | specialexc, 88 | WIP, 89 | 90 | // ALDOR 91 | aldor, 92 | [EnumMember(Value = "aldor common")] 93 | aldorcommon, 94 | [EnumMember(Value = "aldor uncommon")] 95 | aldoruncommon, 96 | [EnumMember(Value = "aldor rare")] 97 | aldorrare, 98 | [EnumMember(Value = "aldor magic")] 99 | aldormagic, 100 | 101 | // FOREIGN 102 | fjall, 103 | elven, 104 | skadia, 105 | nistra 106 | } 107 | 108 | public static void InjectTableWeapons( 109 | // Would love to use a hook but devs fucked up the table's categories' names 110 | string name, 111 | WeaponsTier Tier, 112 | string id, 113 | WeaponsSlot Slot, 114 | WeaponsRarity rarity, 115 | WeaponsMaterial Mat, 116 | WeaponsTags tags, 117 | byte Rng = 1, 118 | int? Price = null, 119 | byte Markup = 1, 120 | short? MaxDuration = null, 121 | short? Armor_Piercing = null, 122 | short? Armor_Damage = null, 123 | short? Bodypart_Damage = null, 124 | short? Slashing_Damage = null, 125 | short? Piercing_Damage = null, 126 | short? Blunt_Damage = null, 127 | short? Rending_Damage = null, 128 | short? Fire_Damage = null, 129 | short? Shock_Damage = null, 130 | short? Poison_Damage = null, 131 | short? Caustic_Damage = null, 132 | short? Frost_Damage = null, 133 | short? Arcane_Damage = null, 134 | short? Unholy_Damage = null, 135 | short? Sacred_Damage = null, 136 | short? Psionic_Damage = null, 137 | short? FMB = null, 138 | short? Hit_Chance = null, 139 | short? CRT = null, 140 | short? CRTD = null, 141 | short? CTA = null, 142 | short? PRR = null, 143 | short? Block_Power = null, 144 | short? Block_Recovery = null, 145 | byte? Bleeding_Chance = null, 146 | byte? Daze_Chance = null, 147 | byte? Stun_Chance = null, 148 | byte? Knockback_Chance = null, 149 | byte? Immob_Chance = null, 150 | byte? Stagger_Chance = null, 151 | short? MP = null, 152 | short? MP_Restoration = null, 153 | short? Cooldown_Reduction = null, 154 | short? Skills_Energy_Cost = null, 155 | short? Spells_Energy_Cost = null, 156 | short? Magic_Power = null, 157 | short? Miscast_Chance = null, 158 | short? Miracle_Chance = null, 159 | short? Miracle_Power = null, 160 | short? Bonus_Range = null, 161 | short? max_hp = null, 162 | short? Health_Restoration = null, 163 | short? Healing_Received = null, 164 | short? Crit_Avoid = null, 165 | short? Fatigue_Gain = null, 166 | short? Lifesteal = null, 167 | short? Manasteal = null, 168 | short? Damage_Received = null, 169 | short? Pyromantic_Power = null, 170 | short? Geomantic_Power = null, 171 | short? Venomantic_Power = null, 172 | short? Electroantic_Power = null, 173 | short? Cryomantic_Power = null, 174 | short? Arcanistic_Power = null, 175 | short? Astromantic_Power = null, 176 | short? Psimantic_Power = null, 177 | short? Balance = null, // Could be byte ? 178 | string? upgrade = null, 179 | bool fireproof = false, 180 | bool NoDrop = false 181 | ) 182 | { 183 | // Table filename 184 | const string tableName = "gml_GlobalScript_table_weapons"; 185 | 186 | // Load table if it exists 187 | List table = ThrowIfNull(ModLoader.GetTable(tableName)); 188 | 189 | // Prepare line 190 | string newline = $"{name};{GetEnumMemberValue(Tier)};{id};{GetEnumMemberValue(Slot)};{rarity};{Mat};{Price};{Markup};{MaxDuration};{Rng};;{Armor_Piercing};{Armor_Damage};{Bodypart_Damage};;{Slashing_Damage};{Piercing_Damage};{Blunt_Damage};{Rending_Damage};{Fire_Damage};{Shock_Damage};{Poison_Damage};{Caustic_Damage};{Frost_Damage};{Arcane_Damage};{Unholy_Damage};{Sacred_Damage};{Psionic_Damage};;{FMB};{Hit_Chance};{CRT};{CRTD};{CTA};{PRR};{Block_Power};{Block_Recovery};;{Bleeding_Chance};{Daze_Chance};{Stun_Chance};{Knockback_Chance};{Immob_Chance};{Stagger_Chance};;{MP};{MP_Restoration};{Cooldown_Reduction};{Skills_Energy_Cost};{Spells_Energy_Cost};{Magic_Power};{Miscast_Chance};{Miracle_Chance};{Miracle_Power};{Bonus_Range};;{max_hp};{Health_Restoration};{Healing_Received};{Crit_Avoid};{Fatigue_Gain};{Lifesteal};{Manasteal};{Damage_Received};;{Pyromantic_Power};{Geomantic_Power};{Venomantic_Power};{Electroantic_Power};{Cryomantic_Power};{Arcanistic_Power};{Astromantic_Power};{Psimantic_Power};;{Balance};{GetEnumMemberValue(tags)};{upgrade};{(fireproof ? 1 : "")};{(NoDrop ? 1 : "")};"; 191 | 192 | // Add line to table 193 | table.Add(newline); 194 | ModLoader.SetTable(table, tableName); 195 | Log.Information($"Injected Weapon {id} into table {tableName}"); 196 | } 197 | } -------------------------------------------------------------------------------- /ModUtils/TextureUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Serilog; 5 | using UndertaleModLib; 6 | using UndertaleModLib.Models; 7 | 8 | namespace ModShardLauncher 9 | { 10 | public class RectTexture 11 | { 12 | public ushort X; 13 | public ushort Y; 14 | public ushort Width; 15 | public ushort Height; 16 | 17 | public RectTexture(ushort x, ushort y, ushort width, ushort height) 18 | { 19 | X = x; 20 | Y = y; 21 | Width = width; 22 | Height = height; 23 | } 24 | } 25 | public class MarginData 26 | { 27 | public int Top; 28 | public int Bottom; 29 | public int Left; 30 | public int Right; 31 | 32 | public MarginData(int top, int bottom, int left, int right) 33 | { 34 | Top = top; 35 | Bottom = bottom; 36 | Left = left; 37 | Right = right; 38 | } 39 | } 40 | public class BoundingData 41 | { 42 | public T Width; 43 | public T Height; 44 | 45 | public BoundingData(T width, T height) 46 | { 47 | Width = width; 48 | Height = height; 49 | } 50 | } 51 | public class OriginData 52 | { 53 | public int X; 54 | public int Y; 55 | 56 | public OriginData(int x, int y) 57 | { 58 | X = x; 59 | Y = y; 60 | } 61 | } 62 | public static partial class Msl 63 | { 64 | public static UndertaleTexturePageItem CreateTexureItem(UndertaleEmbeddedTexture texture, RectTexture source, RectTexture target, BoundingData bounding) 65 | { 66 | return new() 67 | { 68 | Name = ModLoader.Data.Strings.MakeString("PageItem " + ModLoader.Data.TexturePageItems.Count), 69 | 70 | SourceX = source.X, 71 | SourceY = source.Y, 72 | SourceHeight = source.Height, 73 | SourceWidth = source.Width, 74 | 75 | TargetX = target.X, 76 | TargetY = target.Y, 77 | TargetHeight = target.Height, 78 | TargetWidth = target.Width, 79 | 80 | BoundingHeight = bounding.Height, 81 | BoundingWidth = bounding.Width, 82 | TexturePage = texture 83 | }; 84 | } 85 | public static UndertaleSprite CreateSpriteNoCollisionMasks(string spriteName, MarginData margin, OriginData origin, BoundingData bounding) 86 | { 87 | UndertaleSprite newSprite = new() 88 | { 89 | Name = ModLoader.Data.Strings.MakeString(spriteName), 90 | Width = bounding.Width, 91 | Height = bounding.Height, 92 | MarginLeft = margin.Left, 93 | MarginRight = margin.Right, 94 | MarginTop = margin.Top, 95 | MarginBottom = margin.Bottom, 96 | OriginX = origin.X, 97 | OriginY = origin.Y, 98 | }; 99 | 100 | return newSprite; 101 | } 102 | public static UndertaleSprite GetSprite(string name) 103 | { 104 | try 105 | { 106 | UndertaleSprite sprite = ModLoader.Data.Sprites.First(t => t.Name.Content == name); 107 | Log.Information(string.Format("Found sprite: {0}", name.ToString())); 108 | return sprite; 109 | } 110 | catch(Exception ex) 111 | { 112 | Log.Error(ex, "Something went wrong"); 113 | throw; 114 | } 115 | } 116 | public static UndertaleEmbeddedTexture GetEmbeddedTexture(string name) 117 | { 118 | try 119 | { 120 | UndertaleEmbeddedTexture embeddedTexture = ModLoader.Data.EmbeddedTextures.First(t => t.Name.Content == name); 121 | Log.Information(string.Format("Found embedded texture: {0}", name.ToString())); 122 | return embeddedTexture; 123 | } 124 | catch(Exception ex) 125 | { 126 | Log.Error(ex, "Something went wrong"); 127 | throw; 128 | } 129 | } 130 | public static UndertaleTexturePageItem GetTexturePageItem(string name) 131 | { 132 | try 133 | { 134 | UndertaleTexturePageItem texturePageItem = ModLoader.Data.TexturePageItems.First(t => t.Name.Content == name); 135 | Log.Information(string.Format("Found texture page item: {0}", name.ToString())); 136 | return texturePageItem; 137 | } 138 | catch(Exception ex) 139 | { 140 | Log.Error(ex, "Something went wrong"); 141 | throw; 142 | } 143 | } 144 | public static string AddNewTexturePageItem(string embeddedTextureName, RectTexture source, RectTexture target, BoundingData bounding) 145 | { 146 | try 147 | { 148 | UndertaleEmbeddedTexture embeddedTexture = GetEmbeddedTexture(embeddedTextureName); 149 | 150 | UndertaleTexturePageItem texturePageItem = CreateTexureItem( 151 | embeddedTexture, 152 | source, 153 | target, 154 | bounding 155 | ); 156 | ModLoader.Data.TexturePageItems.Add(texturePageItem); 157 | Log.Information(string.Format("Successfully added a new texture from: {0}", embeddedTextureName.ToString())); 158 | return texturePageItem.Name.Content; 159 | 160 | } 161 | catch(Exception ex) 162 | { 163 | Log.Error(ex, "Something went wrong"); 164 | throw; 165 | } 166 | } 167 | public static string AddNewSprite(string spriteName, List texturePageItemNames, MarginData margin, OriginData origin, BoundingData bounding) 168 | { 169 | try 170 | { 171 | UndertaleSprite newSprite = CreateSpriteNoCollisionMasks( 172 | spriteName, 173 | margin, 174 | origin, 175 | bounding 176 | ); 177 | 178 | IEnumerable texturePageItems = texturePageItemNames 179 | .Select(x => GetTexturePageItem(x)) 180 | .Select(x => new UndertaleSprite.TextureEntry(){ Texture = x }); 181 | 182 | foreach(UndertaleSprite.TextureEntry texturePageItem in texturePageItems) 183 | { 184 | newSprite.Textures.Add(texturePageItem); 185 | } 186 | 187 | ModLoader.Data.Sprites.Add(newSprite); 188 | 189 | Log.Information(string.Format("Successfully added new sprite: {0}", newSprite.Name.Content)); 190 | return newSprite.Name.Content; 191 | 192 | } 193 | catch(Exception ex) 194 | { 195 | Log.Error(ex, "Something went wrong"); 196 | throw; 197 | } 198 | } 199 | } 200 | } -------------------------------------------------------------------------------- /ModUtils/VariableUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Serilog; 4 | using UndertaleModLib.Models; 5 | 6 | namespace ModShardLauncher 7 | { 8 | public static partial class Msl 9 | { 10 | public static UndertaleVariable GetVariable(string name) 11 | { 12 | try 13 | { 14 | UndertaleVariable variable = ModLoader.Data.Variables.First(t => t.Name?.Content == name); 15 | Log.Information(string.Format("Found variable: {0}", variable.ToString())); 16 | 17 | return variable; 18 | } 19 | catch(Exception ex) { 20 | Log.Error(ex, "Something went wrong"); 21 | throw; 22 | } 23 | } 24 | public static UndertaleString GetString(string name) 25 | { 26 | try 27 | { 28 | UndertaleString variable = ModLoader.Data.Strings.First(t => t.Content == name); 29 | Log.Information(string.Format("Found string: {0}", variable.ToString())); 30 | 31 | return variable; 32 | } 33 | catch(Exception ex) { 34 | Log.Error(ex, "Something went wrong"); 35 | throw; 36 | } 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /ModUtils/WeaponUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using ModShardLauncher.Mods; 5 | using Serilog; 6 | 7 | namespace ModShardLauncher 8 | { 9 | public static partial class Msl 10 | { 11 | public static Weapon GetWeapon(string id) 12 | { 13 | try 14 | { 15 | string weaponsName = ModLoader.Weapons.First(t => t.StartsWith(id)); 16 | 17 | // for a lazy evaluation to avoid going through all the WeaponDescriptions list 18 | IEnumerator weaponDescriptionEnumerator = ModLoader.WeaponDescriptions.Where(t => t.StartsWith(id)).GetEnumerator(); 19 | 20 | // getting the first element - the localization name 21 | weaponDescriptionEnumerator.MoveNext(); 22 | List localizationNames = weaponDescriptionEnumerator.Current.Split(";").ToList(); 23 | localizationNames.Remove(""); 24 | localizationNames.RemoveAt(0); 25 | 26 | // getting the second element - the description 27 | weaponDescriptionEnumerator.MoveNext(); 28 | List weaponDescription = weaponDescriptionEnumerator.Current.Split(";").ToList(); 29 | weaponDescription.Remove(""); 30 | weaponDescription.RemoveAt(0); 31 | 32 | Log.Information(string.Format("Found weapon: {0}", weaponsName.ToString())); 33 | return new(weaponsName, weaponDescription, localizationNames); 34 | } 35 | catch(Exception ex) 36 | { 37 | Log.Error(ex, "Something went wrong"); 38 | throw; 39 | } 40 | } 41 | public static void SetWeapon(string id, Weapon weapon) 42 | { 43 | try 44 | { 45 | string targetName = ModLoader.Weapons.First(t => t.StartsWith(id)); 46 | int indexTargetName = ModLoader.Weapons.IndexOf(targetName); 47 | 48 | // for a lazy evaluation to avoid going through all the WeaponDescriptions list 49 | IEnumerator<(int, string)> weaponDescriptionEnumerator = ModLoader.WeaponDescriptions.Where(t => t.StartsWith(id)).Enumerate().GetEnumerator(); 50 | 51 | // getting the first element - the localization name 52 | weaponDescriptionEnumerator.MoveNext(); 53 | (int indexLocalizationName, _) = weaponDescriptionEnumerator.Current; 54 | 55 | // getting the first element - the description 56 | weaponDescriptionEnumerator.MoveNext(); 57 | (int indexDescription, _) = weaponDescriptionEnumerator.Current; 58 | 59 | (string, string, string) w2s = Weapon.Weapon2String(weapon); 60 | ModLoader.Weapons[indexTargetName] = w2s.Item1; 61 | ModLoader.WeaponDescriptions[indexDescription] = w2s.Item2; 62 | ModLoader.WeaponDescriptions[indexLocalizationName] = w2s.Item3; 63 | 64 | Log.Information(string.Format("Successfully set weapon: {0}", targetName.ToString())); 65 | } 66 | catch(Exception ex) 67 | { 68 | Log.Error(ex, "Something went wrong"); 69 | throw; 70 | } 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /Mods/DisassemblyEditor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using UndertaleModLib; 5 | using UndertaleModLib.Decompiler; 6 | using UndertaleModLib.Models; 7 | 8 | namespace ModShardLauncher.Mods 9 | { 10 | public class DisassemblyEditor 11 | { 12 | public UndertaleData Data => DataLoader.data; 13 | public UndertaleCode Code; 14 | public List CodeContents; 15 | public int Index { get; private set; } = 0; 16 | public DisassemblyEditor(UndertaleCode code) 17 | { 18 | Code = code; 19 | CodeContents = code.Disassemble(Data.Variables, Data.CodeLocals.For(Code)).Split("\n").ToList(); 20 | } 21 | public bool TryGotoNext(Func predicate) 22 | { 23 | if (CodeContents.FirstOrDefault(predicate) == default) return false; 24 | else 25 | { 26 | Index = CodeContents.IndexOf(CodeContents.First(predicate)); 27 | return true; 28 | } 29 | } 30 | public void Emit(OpCodes o) 31 | { 32 | 33 | } 34 | } 35 | public enum OpCodes 36 | { 37 | Conv, 38 | Mul, 39 | Div, 40 | Rem, 41 | Mod, 42 | Add, 43 | Sub 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Mods/Mod.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace ModShardLauncher.Mods 10 | { 11 | public class Mod 12 | { 13 | public override string ToString() 14 | { 15 | return Name; 16 | } 17 | public virtual string Name { get => GetType().Name; } 18 | public virtual string Author { get => "未知"; } 19 | public virtual string Description { get => "未知"; } 20 | public virtual string ShortDesc { get => "未知"; } 21 | public virtual string Version { get => "v0.0.0.0"; } 22 | public virtual string TargetVersion { get => "v0.0.0.0"; } 23 | public List ModWeapons = new(); 24 | public ModFile ModFiles = new(); 25 | public Mod() { } 26 | public virtual void LoadAssembly() 27 | { 28 | 29 | } 30 | public virtual void PatchMod() 31 | { 32 | 33 | } 34 | } 35 | public enum ModLanguage 36 | { 37 | Russian, 38 | English, 39 | Chinese, 40 | German, 41 | Spanish, 42 | French, 43 | Italian, 44 | Portuguese, 45 | Polish, 46 | Turkish, 47 | Japanese, 48 | Korean 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Mods/ModHooks.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ModShardLauncher.Mods 8 | { 9 | public class ModHooks 10 | { 11 | public virtual void OnGameStart(object[] obj) { } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ModShardLauncher 2 | 3 | 4 | ## Description 5 | 6 | ModShardLauncher is a **powerful** and **user-friendly** mod loader for the game Stoneshard.
7 | It's designed to let players easily **install** and **manage** a wide variety of **mods**, as well as **playing with multiple mods at a time** !
8 | 9 | **But that's not it** :
10 | It also lets modders **create mods** through **C#** instead of **UndertaleModTool**, which improves **compatibility** and prevents updates from systematically **breaking** mods. 11 | 12 | With **ModShardLoader**, you can **customize** your Stoneshard gameplay to suit your **preferences**.
13 | Whether you want to tweak the **game mechanics**, add **new content**, or **anything else**, **ModShardLoader** makes it possible. 14 | 15 | ## Documentation 16 | 17 | - [Documentation](https://modshardteam.github.io/ModShardLauncher/guides/introduction.html) 18 | - [这里是文档](https://modshardteam.github.io/ModShardLauncher/zh/guides/introduction.html) 19 | 20 | ## Roadmap 21 | 22 | See roadmap [here](https://github.com/ModShardTeam/ModShardLauncher/milestones). 23 | 24 | ## Usage 25 | ### For Players 26 | [How to install mods](https://modshardteam.github.io/ModShardLauncher/guides/how-to-play-mod.html) 27 | ### For Modders 28 | [How to create mods with MSL](https://modshardteam.github.io/ModShardLauncher/guides/start-modding.html)
29 | #### Mod Template :
30 | - [Source Code](https://github.com/ModShardTeam/ModShardLauncherTemplate) 31 | - [NuGet Package](https://www.nuget.org/packages/ModShardLauncher.Templates) 32 | #### Mod Examples : 33 | - [Quicksave](https://github.com/Nylux/Stoneshard-Quicksave) 34 | - [SpeedManager](https://github.com/Nylux/Stoneshard-SpeedManager) 35 | - [NeoConsole](https://github.com/Nylux/Stoneshard-NeoConsole) 36 | - [ExamplesForLog](https://github.com/remyCases/ExamplesForLogMod) 37 | 38 | ## Features 39 | 40 | ### For Players 41 | 42 | | **Name** | **Status** | 43 | | :------ | :--------: | 44 | | Installing Mods | :heavy_check_mark: | 45 | | Version Checking | :x: | 46 | | Auto-updates | :x: | 47 | | Conflict Checking | :x: | 48 | | Mod Settings | :heavy_check_mark: | 49 | 50 | ### For Modders 51 | 52 | | Name | Status | 53 | | :------ | :--------: | 54 | | Mod Settings | :heavy_check_mark: | 55 | | GML Editing | :heavy_check_mark: | 56 | | Assembly Editing | :heavy_check_mark: | 57 | | GameObjects | :heavy_check_mark: | 58 | | Events | :heavy_check_mark: | 59 | | Functions | :heavy_check_mark: | 60 | | Tables | :heavy_check_mark: | 61 | | Weapons | :heavy_check_mark: | 62 | | Rooms | :heavy_check_mark: | 63 | | Sounds | :x: | 64 | | Sprites | :heavy_check_mark: | 65 | | Shaders | :x: | 66 | | Fonts | :x: | 67 | | DE2 Dialogues | :x: | 68 | | Extensions | :heavy_check_mark: | 69 | 70 | ## Contributing 71 | ### Building From Source 72 | Requires the [.NET 6.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) 73 | 74 | `git clone git@github.com:ModShardTeam/ModShardLauncher.git`
75 | `cd ModShardLauncher`
76 | `dotnet build` 77 | 78 | ### Editing The Documentation 79 | **TODO** 80 | -------------------------------------------------------------------------------- /Reference/README.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Reference/UndertaleModLib.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Reference/UndertaleModLib.dll -------------------------------------------------------------------------------- /Reference/UndertaleModTool.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Reference/UndertaleModTool.dll -------------------------------------------------------------------------------- /Resources/Codes/CodeResources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // 此代码由工具生成。 4 | // 运行时版本:4.0.30319.42000 5 | // 6 | // 对此文件的更改可能会导致不正确的行为,并且如果 7 | // 重新生成代码,这些更改将会丢失。 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ModShardLauncher.Resources.Codes { 12 | using System; 13 | 14 | 15 | /// 16 | /// 一个强类型的资源类,用于查找本地化的字符串等。 17 | /// 18 | // 此类是由 StronglyTypedResourceBuilder 19 | // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 20 | // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen 21 | // (以 /str 作为命令选项),或重新生成 VS 项目。 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class CodeResources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal CodeResources() { 33 | } 34 | 35 | /// 36 | /// 返回此类使用的缓存的 ResourceManager 实例。 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ModShardLauncher.Resources.Codes.CodeResources", typeof(CodeResources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// 重写当前线程的 CurrentUICulture 属性,对 51 | /// 使用此强类型资源类的所有资源查找执行重写。 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// 查找 System.Byte[] 类型的本地化资源。 65 | /// 66 | internal static byte[] createHookObj { 67 | get { 68 | object obj = ResourceManager.GetObject("createHookObj", resourceCulture); 69 | return ((byte[])(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// 查找 System.Byte[] 类型的本地化资源。 75 | /// 76 | internal static byte[] give { 77 | get { 78 | object obj = ResourceManager.GetObject("give", resourceCulture); 79 | return ((byte[])(obj)); 80 | } 81 | } 82 | 83 | /// 84 | /// 查找 System.Byte[] 类型的本地化资源。 85 | /// 86 | internal static byte[] msl_print { 87 | get { 88 | object obj = ResourceManager.GetObject("msl_print", resourceCulture); 89 | return ((byte[])(obj)); 90 | } 91 | } 92 | 93 | /// 94 | /// 查找 System.Byte[] 类型的本地化资源。 95 | /// 96 | internal static byte[] ScriptEngine_create { 97 | get { 98 | object obj = ResourceManager.GetObject("ScriptEngine_create", resourceCulture); 99 | return ((byte[])(obj)); 100 | } 101 | } 102 | 103 | /// 104 | /// 查找 System.Byte[] 类型的本地化资源。 105 | /// 106 | internal static byte[] ScriptEngine_server { 107 | get { 108 | object obj = ResourceManager.GetObject("ScriptEngine_server", resourceCulture); 109 | return ((byte[])(obj)); 110 | } 111 | } 112 | 113 | /// 114 | /// 查找 System.Byte[] 类型的本地化资源。 115 | /// 116 | internal static byte[] SendMsg { 117 | get { 118 | object obj = ResourceManager.GetObject("SendMsg", resourceCulture); 119 | return ((byte[])(obj)); 120 | } 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /Resources/Codes/CodeResources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | createHookObj.gml;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 123 | 124 | 125 | give.gml;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 126 | 127 | 128 | msl_print.gml;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 129 | 130 | 131 | ScriptEngine_create.gml;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 132 | 133 | 134 | ScriptEngine_server.gml;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 135 | 136 | 137 | SendMsg.gml;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 138 | 139 | -------------------------------------------------------------------------------- /Resources/Codes/ScriptEngine_create.gml: -------------------------------------------------------------------------------- 1 | client = network_create_socket(0) 2 | network_set_config(network_config_connect_timeout, 1000) 3 | server = network_connect_raw(client, "127.0.0.1", 1333) 4 | global.Server = server 5 | SendMsg("HOK", "OnGameStart", true) -------------------------------------------------------------------------------- /Resources/Codes/ScriptEngine_server.gml: -------------------------------------------------------------------------------- 1 | if (server >= 0 && ds_exists(async_load, 1)) 2 | { 3 | var cid = ds_map_find_value(async_load, "id") 4 | var t = ds_map_find_value(async_load, "type") 5 | if (t == 3) 6 | { 7 | var buffer = ds_map_find_value(async_load, "buffer") 8 | var length = buffer_read(buffer, buffer_u32) 9 | var ID = buffer_read(buffer, buffer_u32) 10 | var message = "" 11 | for (var i = 0; i < length; i++) 12 | message += buffer_read(buffer, buffer_string) 13 | var scr = string_split(message, " ") 14 | var scriptID = asset_get_index(scr[0]) 15 | array_delete(scr, 0, 1) 16 | for (i = 0; i < array_length(scr); i++) 17 | { 18 | if (string_starts_with(scr[i], "\"") && string_ends_with(scr[i], "\"")) 19 | { 20 | scr[i] = string_replace_all(scr[i], "_", " ") 21 | scr[i] = string_delete(scr[i], 1, 1) 22 | scr[i] = string_delete(scr[i], string_length(scr[i]), 1) 23 | } 24 | } 25 | var ret = "" 26 | if (scriptID == -1) 27 | ret = ("script is wrong: " + message) 28 | else if (array_length(scr) > 0) 29 | ret = script_execute_ext(scriptID, scr) 30 | else 31 | ret = script_execute(scriptID) 32 | buffer = buffer_create(4, buffer_grow, 1) 33 | buffer_write(buffer, buffer_u32, ID) 34 | buffer_write(buffer, buffer_string, "[CLB]") 35 | buffer_write(buffer, buffer_string, message) 36 | network_send_raw(server, buffer, buffer_get_size(buffer)) 37 | } 38 | } -------------------------------------------------------------------------------- /Resources/Codes/SendMsg.gml: -------------------------------------------------------------------------------- 1 | function SendMsg(argument0, argument1, argument2) 2 | { 3 | var buffer = buffer_create(4, buffer_grow, 1) 4 | switch (argument0) 5 | { 6 | case "MSG": 7 | buffer_write(buffer, buffer_u32, -1) 8 | break 9 | case "CLB": 10 | buffer_write(buffer, buffer_u32, argument2) 11 | break 12 | case "HOK": 13 | buffer_write(buffer, buffer_u32, -1) 14 | break 15 | } 16 | 17 | buffer_write(buffer, buffer_string, (("[" + argument0) + "]")) 18 | buffer_write(buffer, buffer_string, argument1) 19 | if (argument0 == "HOK") buffer_write(buffer, buffer_string, "" + string(argument2)) 20 | network_send_raw(global.Server, buffer, buffer_get_size(buffer)) 21 | } -------------------------------------------------------------------------------- /Resources/Codes/createHookObj.gml: -------------------------------------------------------------------------------- 1 | function createHookObj() 2 | { 3 | var res = array_create(argument[0]) 4 | for(var i = 1; i <= argument[0]; i++) 5 | res[i - 1] = variable_instance_get(id, argument[i]) 6 | return json_stringify(res, 1) 7 | } -------------------------------------------------------------------------------- /Resources/Codes/give.gml: -------------------------------------------------------------------------------- 1 | function give(argument0, argument1) 2 | { 3 | switch argument1 4 | { 5 | case "weapon": 6 | with (o_inventory) 7 | { 8 | with (scr_inventory_add_weapon(argument0, (1 << 0))) 9 | scr_inv_atr_set("Duration", 100) 10 | } 11 | break 12 | } 13 | } -------------------------------------------------------------------------------- /Resources/Codes/msl_print.gml: -------------------------------------------------------------------------------- 1 | function msl_print(argument0) 2 | { 3 | show_message(argument0) 4 | } -------------------------------------------------------------------------------- /Resources/Mystery Font.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Mystery Font.ttf -------------------------------------------------------------------------------- /Resources/SSFont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/SSFont.ttf -------------------------------------------------------------------------------- /Resources/Sprites/ModInfosBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/ModInfosBG.png -------------------------------------------------------------------------------- /Resources/Sprites/SSicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/SSicon.png -------------------------------------------------------------------------------- /Resources/Sprites/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/arrow_down.png -------------------------------------------------------------------------------- /Resources/Sprites/arrow_down_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/arrow_down_down.png -------------------------------------------------------------------------------- /Resources/Sprites/arrow_down_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/arrow_down_over.png -------------------------------------------------------------------------------- /Resources/Sprites/arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/arrow_up.png -------------------------------------------------------------------------------- /Resources/Sprites/arrow_up_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/arrow_up_down.png -------------------------------------------------------------------------------- /Resources/Sprites/arrow_up_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/arrow_up_over.png -------------------------------------------------------------------------------- /Resources/Sprites/checkbox_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/checkbox_0.png -------------------------------------------------------------------------------- /Resources/Sprites/checkbox_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/checkbox_1.png -------------------------------------------------------------------------------- /Resources/Sprites/checkbox_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/checkbox_2.png -------------------------------------------------------------------------------- /Resources/Sprites/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/close.png -------------------------------------------------------------------------------- /Resources/Sprites/close_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/close_down.png -------------------------------------------------------------------------------- /Resources/Sprites/close_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/close_over.png -------------------------------------------------------------------------------- /Resources/Sprites/enable_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/enable_button.png -------------------------------------------------------------------------------- /Resources/Sprites/enable_button_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/enable_button_down.png -------------------------------------------------------------------------------- /Resources/Sprites/enable_button_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/enable_button_over.png -------------------------------------------------------------------------------- /Resources/Sprites/icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/icon.gif -------------------------------------------------------------------------------- /Resources/Sprites/icon_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/icon_default.png -------------------------------------------------------------------------------- /Resources/Sprites/leftPanel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/leftPanel.png -------------------------------------------------------------------------------- /Resources/Sprites/menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/menu.png -------------------------------------------------------------------------------- /Resources/Sprites/menu_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/menu_down.png -------------------------------------------------------------------------------- /Resources/Sprites/menu_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/menu_over.png -------------------------------------------------------------------------------- /Resources/Sprites/min.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/min.png -------------------------------------------------------------------------------- /Resources/Sprites/min_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/min_down.png -------------------------------------------------------------------------------- /Resources/Sprites/min_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/min_over.png -------------------------------------------------------------------------------- /Resources/Sprites/mod.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/mod.png -------------------------------------------------------------------------------- /Resources/Sprites/mod_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/mod_down.png -------------------------------------------------------------------------------- /Resources/Sprites/mod_icon_fore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/mod_icon_fore.png -------------------------------------------------------------------------------- /Resources/Sprites/mod_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/mod_over.png -------------------------------------------------------------------------------- /Resources/Sprites/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/open.png -------------------------------------------------------------------------------- /Resources/Sprites/open_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/open_down.png -------------------------------------------------------------------------------- /Resources/Sprites/open_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/open_over.png -------------------------------------------------------------------------------- /Resources/Sprites/patch_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/patch_icon.png -------------------------------------------------------------------------------- /Resources/Sprites/refresh_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/refresh_icon.png -------------------------------------------------------------------------------- /Resources/Sprites/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/save.png -------------------------------------------------------------------------------- /Resources/Sprites/save_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/save_down.png -------------------------------------------------------------------------------- /Resources/Sprites/save_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/save_over.png -------------------------------------------------------------------------------- /Resources/Sprites/scrollbar_vertical.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/scrollbar_vertical.png -------------------------------------------------------------------------------- /Resources/Sprites/scrollbar_vertical_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/scrollbar_vertical_over.png -------------------------------------------------------------------------------- /Resources/Sprites/server.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/server.png -------------------------------------------------------------------------------- /Resources/Sprites/server_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/server_down.png -------------------------------------------------------------------------------- /Resources/Sprites/server_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/server_over.png -------------------------------------------------------------------------------- /Resources/Sprites/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/settings.png -------------------------------------------------------------------------------- /Resources/Sprites/settings_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/settings_button.png -------------------------------------------------------------------------------- /Resources/Sprites/settings_button_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/settings_button_down.png -------------------------------------------------------------------------------- /Resources/Sprites/settings_button_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/settings_button_over.png -------------------------------------------------------------------------------- /Resources/Sprites/settings_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/settings_down.png -------------------------------------------------------------------------------- /Resources/Sprites/settings_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/settings_over.png -------------------------------------------------------------------------------- /Resources/Sprites/source.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/source.png -------------------------------------------------------------------------------- /Resources/Sprites/source_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/source_down.png -------------------------------------------------------------------------------- /Resources/Sprites/source_over.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/source_over.png -------------------------------------------------------------------------------- /Resources/Sprites/splitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/Sprites/splitter.png -------------------------------------------------------------------------------- /Resources/zpix.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/Resources/zpix.ttf -------------------------------------------------------------------------------- /docs/guides/api.zh.md: -------------------------------------------------------------------------------- 1 | # API 2 | 3 | 该页面介绍了本工具可以使用的API. 4 | 5 | [TOC] 6 | 7 | ## ModLoader 8 | 9 | ### ModLoader.AddObject(string name) 10 | 11 | 根据给出的名称, 向数据文件中添加一个Game Object, 并返回这个Object. 12 | 13 | ### ModLoader.GetObject(string name) 14 | 15 | 根据给出的名称, 从数据文件中查找一个Game Object, 并返回这个Object. 如果找不到则返回null. 16 | 17 | ### ModLoader.SetObject(string name, UndertaleGameObject o) 18 | 19 | 根据给出的名称和Object, 给数据文件中对应的Game Object赋值. 20 | 21 | ### ModLoader.AddCode(string Code, string name) 22 | 23 | 根据给出的名称和Code, 向数据文件中添加一个Code, 并返回这个Code. 24 | !!! notice "" 25 | 注意不要使用AddCode来添加新的function, 若想添加新的function, 请使用AddFunction. 26 | 27 | ### ModLoader.AddFunction(string Code, string name) 28 | 29 | 根据给出的名称和Code, 向数据文件中添加一个包含Function的Code, 并返回这个Code 30 | !!! notice "" 31 | 请使用本方法添加Function, 否则数据文件将损坏. 32 | 33 | ### ModLoader.GetTable(string name) 34 | 35 | 根据给出的名称, 从数据文件中查找一个Table, 将其转换为List并返回这个List. 36 | 37 | ### GetDecompiledCode(string name) 38 | 39 | 根据给出的名称, 从数据文件中查找一个Code, 并返回这个Code的Decompile版本代码. 40 | 41 | ### GetDisassemblydCode(string name) 42 | 43 | 根据给出的名称, 从数据文件中查找一个Code, 并返回这个Code的Disassembly版本代码.(说实话, 我并不知道这个方法有什么卵用) -------------------------------------------------------------------------------- /docs/guides/how-to-play-mod.en.md: -------------------------------------------------------------------------------- 1 | # Installing Mods 2 | 3 | ## Downloading ModShardLauncher 4 | 5 | In order to install mods, you will require the **ModShardLauncher**.
6 | You can grab it on **Github** by clicking the button below.
7 | 8 | 9 | [ModShardLauncher :octicons-link-external-16:](https://github.com/DDDDDragon/ModShardLauncher/releases){ .md-button .md-button--primary}  10 | 11 | Make sure you download the `msl.zip` file, and ^^**not the source code**^^.
12 |
13 | Alternatively, you can build ModShardLauncher from source, but it's out of this guide's scope. 14 |
15 | 16 | If launching MSL opens a console and closes immediately, you may require the **.NET Desktop Runtime 6.0** 17 | 18 | [.NET Desktop Runtime 6.0 :octicons-link-external-16:](https://dotnet.microsoft.com/en-us/download/dotnet/6.0){ .md-button .md-button--primary}  19 | 20 | --- 21 | 22 | ## Linux setup instructions 23 | 24 | ### Pre-requisites 25 | 26 | - ***Bottles*** - https://usebottles.com/ 27 | - ***Stoneshard*** - The Windows version of Stoneshard must be used as the native Linux version is bundled differently 28 | 29 | ### Steps 30 | 1. Create a Bottle environment for gaming 31 | 32 | ![linux_bottle_1.png](../img/linux_bottle_1.png) 33 | 2. Open the newly created bottle and click "Add Shortcut" and browse to then select the `ModShardLauncher.exe` 34 | 3. Modify the newly added item by clicking the three dot menu and going to "Change Launch Options". 35 | The working directory must be updated to the directory that `ModShardLauncher.exe` resides in. 36 | 4. The bottle settings need to be updated to support the .NET environment. This can be found below the "Add Shortcut" 37 | button, select "Settings" and then "Environment Variables". A new variable needs to be added to handle the 38 | extraction location `DOTNET_BUNDLE_EXTRACT_BASE_DIR=Z:\home\{user}\dotnet_bundle_extract`, update this to a path of your choosing. 39 | 40 | *If you run into file permission issues with Bottles this is due to it running in a flatpak. 41 | I suggest using [Flatseal](https://flathub.org/apps/com.github.tchx84.Flatseal) to give Bottles access to the required paths.* 42 | --- 43 | 44 | ## ModShardLauncher Setup 45 | 46 | ???+ warning "IMPORTANT - Installing after RtR" 47 | Make sure you are on the `modbranch` beta of Stoneshard on Steam before proceeding below.
48 | When launching the game, the version at the top right should say `X.X.X.X-vm`.
49 | 50 | Here's how to do it :
51 | - Right click on Stoneshard in your library on steam.
52 | - Click `Properties`.
53 | - Go in the `Betas` tab.
54 | - Select the `modbranch` beta.
55 | - Steam will now update your game files, when it's done, proceed below. 56 | 57 | - **Extract** `ModShardLauncher.zip` anywhere. 58 | - **Rename** `data.win` to `vanilla.win` in your Stoneshard folder. 59 | - **Run** `ModShardLauncher.exe`. 60 | 61 | --- 62 | 63 | ## UI Tour 64 | 65 | Let's take a quick tour of the UI to better know MSL.

66 | 67 |
![Main Menu](../img/tool_UI.png){: style="width:50%"}
68 | 69 |
70 | The button on the top left of the window shows the button's name.

71 | The `Anvil` button below that leads to the `Mods` menu. (***^^This is the only menu you will need^^***.)

72 | The `C#` button leads to the `Mod Sources` menu. (*It's used by modders to create their mods*.)

73 | The `Cog` button leads to the `Settings` menu. (*It's used for some settings you probably won't need*.)

74 |
75 | 76 | --- 77 | 78 | ## Installing a Mod 79 | 80 | Now that we've got MSL running, let's install some mods.
81 | Here's an [example video showing the installation](https://www.youtube.com/watch?v=_J0oJYGi38E&t=13s) of [NeoConsole](https://github.com/Nylux/Stoneshard-NeoConsole/releases). (*enable the subtitles !*)

82 | Note: It's a bit outdated, but the process is pretty much the same, a new video will be made at some point.
83 | 84 | ???+ warning "MAKE SURE YOU ARE ON THE MODBRANCH BETA OF STONESHARD ON STEAM" 85 | 86 | - Close MSL. 87 | - Download your mod's `.sml` file. 88 | - Place the `.sml` file in MSL's `Mods` folder. 89 | - Start MSL. 90 | - Click on the **anvil button** to open the `Mods` menu. 91 | - At the top left of the window, click on the **folder button**. 92 | - Select the `vanilla.win` file in the `Stoneshard` folder 93 | - In the `Mods` menu, **tick the box** next to the mods you wish to enable. 94 | - Click on the **save button** and save under any name (eg. `modded.win`) 95 | - Close MSL. 96 | - Start **Stoneshard**. It should ask you to select a `.win` file. 97 | - Select the `modded.win` file and enjoy your mods ! 98 | 99 |

100 | -------------------------------------------------------------------------------- /docs/guides/how-to-play-mod.zh.md: -------------------------------------------------------------------------------- 1 | !!! warning "TODO" 2 | 3 |
![](../img/tool_UI.png){: style="width:50%"}
-------------------------------------------------------------------------------- /docs/guides/introduction.en.md: -------------------------------------------------------------------------------- 1 | # ModShardLauncher 2 | 3 | ## What is **ModShardLauncher**? 4 | 5 | --- 6 | 7 | **ModShardLauncher** is a tool to patch **mods** into StoneShard original data files.
8 | 9 | In the past, we modders used a tool called **UndertaleModTool (UTMT)** to edit the source code and save it.
10 | But if the game received even the most insignificant of updates, all mods would break.
11 | Additionally, multiple mods couldn't work together unless you actually combined them by hand.
12 | 13 | To deal with these issues and limitations, I wanted to make a tool.
14 | That's what **ModShardLauncher** is. 15 | 16 | ## How does **ModShardLauncher** work? 17 | 18 | --- 19 | 20 | Did you know that **UTMT** was made in C# ?
21 | 22 | Using **UTMT**'s source code, **ModShardLauncher** can load data files.
23 | And with C#'s reflection, **ModShardLauncher** can load .dll files as mods and patch the '**modthings**' into data files, then save them. 24 | 25 | ## I want to start modding now! 26 | 27 | --- 28 | 29 | [Just check out the guides here !](../guides/start-modding.md) -------------------------------------------------------------------------------- /docs/guides/introduction.zh.md: -------------------------------------------------------------------------------- 1 | # ModShardLauncher 2 | 3 | ## 什么是**ModShardLauncher**? 4 | 5 | **ModShardLauncher**是一个用于给StoneShard(紫色晶石)这款游戏加载mod的工具。 6 | 7 | 在我开发这款工具之前, mod作者们都是使用**UTMT**, 即UndertaleModTool这款工具来开发mod并保存的. 这样开发的难点在于, 作者们只能制作源码mod, 也就是说, 不同的mod不能一起加载, 除非你自己把他们的内容整合到一起. 而且UTMT使用较为繁琐, 并不适合用于开发StoneShard的mod. 一旦作者进行更新, 所有mod将不再适用, 源文件需要重新被编辑和保存. 8 | 9 | 为了解决这些痛苦的问题, 我打算开发一款工具, 也就是**ModShardLauncher**. 10 | 11 | ## **ModShardLauncher**是如何工作的? 12 | 13 | 实际上, **UTMT**是用C#这门语言开发的. 因此, 引用它的源码就可以很方便的读取和保存data.win中的数据. 并且在C#强大的反射功能支持下, mod作者们可以通过该工具内置的打包器将所有mod代码以及贴图打包成 `.sml` 文件, 然后工具内置的读取器可以读取这种格式的文件, 并将其中的数据打包进新的data.win文件. 以达成多mod共存, 便捷开发的目的. 14 | 15 | ## 太棒辣 我现在就想开发一个自己的mod! 16 | 17 | [那就从这里开始吧!](../guides/start-modding.md) -------------------------------------------------------------------------------- /docs/guides/start-modding-with-vsc.zh.md: -------------------------------------------------------------------------------- 1 | # 使用Visual Studio Code进行开发 2 | 3 | [TOC] 4 | 5 | ## 前言 6 | 7 | 为什么要把这个教程单独拿出来呢? 首先一个原因是考虑到想做mod的各位对于编程可能一无所知, 而下载Visual Studio的步骤与某些编程知识是相关的, 因此可能会造成一些误解或让各位在前期做无用功。 8 | 9 | Visual Studio Code 是作者很喜欢的一款文本编辑器, 因此关于这方面的内容我们都围绕VSCode来讲. 10 | 11 | ## 下载工具 12 | 13 | [在这里下载](https://code.visualstudio.com/) 14 | 15 | 网上也有很多关于下载VSCode的教程, 你可以参考这些教程来进行下载. 基本上一路按继续就可以了. 16 | 17 | ## 下载插件 18 | 19 | -------------------------------------------------------------------------------- /docs/guides/start-modding.zh.md: -------------------------------------------------------------------------------- 1 | # 开始吧! 2 | 3 | [TOC] 4 | 5 | ## C#基础 6 | 7 | 如果你想要制作mod, 那请确保你有一定的C#基础, 不然你可能会看不懂工具的API是怎么用的. 8 | 9 | ## 下载工具 10 | 11 | 要想制作mod, 你首先需要一个写代码的工具. 12 | 13 | 比如**Visual Studio**, 这是一款很专业的开发工具, 你可以用它方便地开发mod. 14 | 15 | [在这里下载](https://visualstudio.microsoft.com/) 16 | 17 | 在下载时, 确保你选择了 `.NET Desktop Development` 工作负载. 其他的负载可以不用下载. 18 | 19 | 最后, 到微软官网查找 `.NET 6.0 SDK` 来下载安装包. 然后重启你的电脑来应用这些更改. 20 | 21 | 另一个选择是**Visual Studio Code**, 在我看来其实用VSCode就足以制作StoneShard的mod了. 22 | 23 | 对于**Visual Studio Code**的教程, 请移步[这里](../guides/start-modding-with-vsc.md) 24 | 25 | ## 创建你的第一个mod 26 | 27 | 首先, 你需要启动 **ModShardLauncher.exe** , 启动之后它会在根目录下创建两个文件夹, 28 | 一个是Mods, 另一个是ModSources. 29 | 30 | 然后在ModSources文件夹中创建一个新的文件夹, 你的第一个mod就从这里开始了. 31 | 32 | ### 创建mod! 33 | 34 | 创建mod的方式有很多, 我们先来拿**Visual Studio**举例. 35 | 首先运行VS, 点击创建新项目, 搜索类库并单击下一步. 如图: 36 |
![](../img/create_project_0.png){: style="width:50%"}
37 | 38 | 然后输入你mod的名字, 选择路径为刚才 **ModShardLauncher.exe** 创建的 Mods 文件夹. 39 |
![](../img/create_project_1.png){: style="width:50%"}
40 | 41 | 最后选择 .Net 6.0即可 42 |
![](../img/create_project_2.png){: style="width:50%"}
43 | 44 | ### 程序集引用! 45 | 46 | 首先我们需要引用工具的程序集, 即Dll文件. 47 | 48 | 先打开解决方案资源管理器. 49 |
![](../img/mod_0.png){: style="width:50%"}
50 | 51 | 右键依赖项, 并单击添加项目引用. 52 |
![](../img/mod_1.png){: style="width:50%"}
53 | 54 | 点击浏览. 55 |
![](../img/mod_2.png){: style="width:50%"}
56 | 57 | 最后选择ModShardLauncher.dll并点击添加. 58 |
![](../img/mod_3.png){: style="width:50%"}
59 | 60 | ### Mod主类! 61 | 62 | 如果你有C#基础, 那你一定对 **类**(Class) 有了解.我们接下来就要创建一个Mod的主类. 63 | 64 | 创建项目时, VS应该已经为我们创建了一个类, 名字叫做Class1. 我们要做的就是先添加对 `ModShardLauncher` 和 `ModShardLauncher.Mods` 这两个命名空间的引用. 然后将代码改成如下这样: 65 |
![](../img/class_0.png){: style="width:50%"}
66 | 67 | 68 | 可以看到我们先是把类的访问级别从 `internal` 改为了 `public` , 这样一来Mod加载时就可以读取到这个类. 然后我们把类名改成了 `MyFirstMod` , 并让这个类继承 `Mod` 类. 69 | 70 | ### Mod信息! 71 | 72 | 接下来我们给Mod添加基础的信息. 73 | 74 | 在 `MyFirstMod` 类中添加如下代码: 75 | ```C# 76 | public override string Name => "MyFirstMod"; 77 | public override string Author => "Mantodea"; 78 | public override string Description => "我的第一个mod"; 79 | ``` 80 | 这样我们就设置了mod的名称, 作者与描述信息. 81 | 82 | ### 编译Mod! 83 | 84 | 接下来我们启动**ModShardLauncher**. 可以看到我们的Mod源码已经被加载出来了. 85 |
![](../img/compile_0.png){: style="width:50%"}
86 | 87 | 在编译mod之前, 我们需要先点击模组界面左上角的文件夹按钮, 并选择 **原版** 的data.win文件进行加载. 88 | 89 | ??? reason "为什么要使用原版文件?" 90 | 91 | 这个工具是基于data.win文件内的各种信息的名称来工作的, 如果你已经加入了源码mod, 很可能会出现各种崩溃的情况. 92 | 93 | ??? reason "为什么要加载游戏文件才能编译?" 94 | 95 | 为了获取游戏版本, 防止极小可能出现的版本不同而崩溃现象(确信) 96 | 97 | 然后我们就可以点击 `MyFirstMod` 栏位右下角的编译辣! (UI现在嘎嘎好看是不是) 98 | 99 | 编译成功后的结果: 100 |
![](../img/compile_1.png){: style="width:50%"}
101 | 102 | ## 创建你的第一把武器 103 | 104 | 就在刚刚, 你的第一个mod已经成功编译了! 接下来, 让我们为它添加一些看得到的东西吧. 105 | 106 | ### 创建武器类! 107 | 108 | 首先点击右侧的解决方案资源管理器, 然后右键你的项目, 点击添加, 最后点击新建项, 如图: 109 |
![](../img/weapon_0.png){: style="width:50%"}
110 | 111 | 名字就输入这把武器的名称即可, 这里我们使用 `MyFirstWeapon` 作为它的名字. 112 | 113 | 接下来进入代码界面, 还是一样的操作, 将 `internal` 改为 `public` , 以便Mod加载时可以加载到这把武器的信息. 然后添加对 `ModShardLauncher` 和 `ModShardLauncher.Mods` 这两个命名空间的引用. 并让武器类继承 `Weapon` 类. 114 | 115 | ### 修改武器的信息! 116 | 117 | 玩过紫晶的人都知道, 紫晶里的武器属性很多. 挨个设置不仅麻烦, 还会很痛苦, 而且还有可能落下某些属性, 导致mod没法正常加载. 118 | 119 | ??? why "你知道的太多了" 120 | ~~实际上是因为毛子写的代码很傻逼.~~ 121 | 122 | 那么有没有一种办法可以让我们简单快捷的设置一把武器的属性呢? 123 | 124 | 首先我们添加如下代码来重写 `SetDefaults` 方法. 125 | ```C# 126 | public override void SetDefaults() 127 | { 128 | 129 | } 130 | ``` 131 | ??? why "你知道的太多了" 132 | ~~有种tModLoader的风格, 我已经被荼毒了.~~ 133 | 134 | 看英文可以知道, 这个方法用于在加载武器时设定它的属性. 135 | 136 | 接下来我们隆重介绍---- **`CloneDefaults`** 方法! 137 | 138 | 没错, 为了防止玩家累死(不是) 我们modder开发时经常忘记各种属性, 我提供了一个方法来让当前这把武器的除 `Name` 与 `ID` 两个属性之外的所有属性全部照抄另外一把原版武器----**`CloneDefaults`**! 因此, 只需把代码改成这样: 139 | ```C# 140 | public override void SetDefaults() 141 | { 142 | CloneDefaults("Homemade Blade"); 143 | Name = "MyFirstWeapon"; 144 | ID = "MyFirstMod1"; 145 | } 146 | ``` 147 | 148 | 这样一来, 这把武器就变成了一把除了名字不一样其他全部一样的换皮土刀(有种NTR的感觉) 149 | 150 | 但是需要注意的是, `CloneDefaults` 并不会对武器的各种语言名称和介绍进行赋值, 这些仍然需要你手动修改. 因此我们再加上两行: 151 | 152 | ```C# 153 | public override void SetDefaults() 154 | { 155 | CloneDefaults("Homemade Blade"); 156 | Name = "MyFirstWeapon"; 157 | ID = "MyFirstMod1"; 158 | Description[ModLanguage.Chinese] = "这是我的第一把武器"; 159 | NameList[ModLanguage.Chinese] = "我的神剑咖喱棒"; 160 | } 161 | ``` 162 | 163 | 这样一来我们的第一把武器算是初步完成了. 164 | 165 | ### 武器贴图! 166 | 167 | StoneShard做mod最痛苦的一部分就是这里了. 贴图, 一把最基础的武器竟然需要六张贴图, 这无疑增加了modder的工作量. 168 | 169 | 如果你没得贴图, 你可以使用UTMT对原版的贴图进行导出, 然后放在Mod目录除 `.vs, bin 和 obj` 的任何地方, 打包时会自动将他们打包进data.win的. 170 |
![](../img/weapon_1.png){: style="width:50%"}
171 | 172 | 如图所示, 从上到下依次是: 人物右手拿武器, 人物左手拿武器, 背包中的武器(有三张的原因是紫晶的武器有破损系统, 如果你不想画, 可以把完整版的武器复制三遍), 掉落的武器. 173 | 174 | ??? why "注意" 175 | 武器在背包中的贴图长宽必须是27的倍数, 这是因为紫晶的背包一格为27*27 176 | 177 | 以上这张图只针对单手武器, 如果是双手武器, 则只需要char而不需要char_left, 因为双手武器只有一种拿取方式. 178 | 179 | 准备好所有这些东西后, 你就可以再次打开 **ModShardLauncher.exe** 重复之前的编译步骤. 180 | 181 | ### 加载Mod! 182 | 183 | !!! notice "**注意!!!**" 184 | 有一点很重要, 你需要把工具目录下一个叫做 `ModShard.dll` 的文件移动到游戏的根目录, 他是该工具内置的一个游戏插件. 否则你将无法启动游戏! 185 | 186 | 最后一步, 也就是加载Mod了, 在你编译完mod之后, 你会发现上方的模组界面中多出了你的mod, 选择它右下角的启用. 最后点击左上角的保存按钮, 就可以把mod数据打包进你刚才加载的那个原版data.win了. 把打包好的数据随便存在什么地方, 把原版的data.win挪走, 再进入游戏, 就会提示你选择数据文件. 选择我们刚才保存的那个数据文件即可. 187 | 188 | ### 进入游戏! 189 | 190 | 打开游戏后, 你会发现打开了一个除游戏之外的窗口, 那是刚才的插件打开的, 它的作用是类似于一个控制台, 可以在游戏过程中运行一些内置函数.(如果没打开记得联系我 一定是哪里出问题了) 191 | 192 | 正常进入游戏, 插件内置了一个give函数, 你可以在插件窗口的下方 `Script` 文本框中输入 193 | ``` 194 | give MyFirstWeapon 195 | ``` 196 | 来获取刚才那把mod武器. 197 | 198 | 如果你想用这个功能获取其他武器, 请注意把武器名中的空格改为 `_` , 如: 199 | ``` 200 | give Homemade_Blade 201 | ``` 202 | 203 | 执行了give函数后, 可以发现背包中就多了一把mod武器了. 204 |
![](../img/weapon_2.png){: style="width:50%"}
-------------------------------------------------------------------------------- /docs/img/Stoneshard.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/Stoneshard.ico -------------------------------------------------------------------------------- /docs/img/class_0.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/class_0.en.png -------------------------------------------------------------------------------- /docs/img/class_0.zh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/class_0.zh.png -------------------------------------------------------------------------------- /docs/img/class_1.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/class_1.en.png -------------------------------------------------------------------------------- /docs/img/compile_0.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/compile_0.en.png -------------------------------------------------------------------------------- /docs/img/compile_1.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/compile_1.en.png -------------------------------------------------------------------------------- /docs/img/create_project_0.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/create_project_0.en.png -------------------------------------------------------------------------------- /docs/img/create_project_0.zh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/create_project_0.zh.png -------------------------------------------------------------------------------- /docs/img/create_project_1.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/create_project_1.en.png -------------------------------------------------------------------------------- /docs/img/create_project_1.zh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/create_project_1.zh.png -------------------------------------------------------------------------------- /docs/img/create_project_2.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/create_project_2.en.png -------------------------------------------------------------------------------- /docs/img/create_project_2.zh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/create_project_2.zh.png -------------------------------------------------------------------------------- /docs/img/linux_bottle_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/linux_bottle_1.png -------------------------------------------------------------------------------- /docs/img/mod_0.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/mod_0.en.png -------------------------------------------------------------------------------- /docs/img/mod_0.zh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/mod_0.zh.png -------------------------------------------------------------------------------- /docs/img/mod_1.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/mod_1.en.png -------------------------------------------------------------------------------- /docs/img/mod_1.zh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/mod_1.zh.png -------------------------------------------------------------------------------- /docs/img/mod_2.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/mod_2.en.png -------------------------------------------------------------------------------- /docs/img/mod_2.zh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/mod_2.zh.png -------------------------------------------------------------------------------- /docs/img/mod_3.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/mod_3.en.png -------------------------------------------------------------------------------- /docs/img/mod_3.zh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/mod_3.zh.png -------------------------------------------------------------------------------- /docs/img/modding_codes.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/modding_codes.en.png -------------------------------------------------------------------------------- /docs/img/msl_template.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/msl_template.en.png -------------------------------------------------------------------------------- /docs/img/msl_template_location.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/msl_template_location.en.png -------------------------------------------------------------------------------- /docs/img/tool_UI.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/tool_UI.en.png -------------------------------------------------------------------------------- /docs/img/tool_UI2.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/tool_UI2.en.png -------------------------------------------------------------------------------- /docs/img/tool_UI3.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/tool_UI3.en.png -------------------------------------------------------------------------------- /docs/img/tool_UI4.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/tool_UI4.en.png -------------------------------------------------------------------------------- /docs/img/tool_UI5.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/tool_UI5.en.png -------------------------------------------------------------------------------- /docs/img/tool_UI6.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/tool_UI6.en.png -------------------------------------------------------------------------------- /docs/img/weapon_0.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/weapon_0.en.png -------------------------------------------------------------------------------- /docs/img/weapon_0.zh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/weapon_0.zh.png -------------------------------------------------------------------------------- /docs/img/weapon_1.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/weapon_1.en.png -------------------------------------------------------------------------------- /docs/img/weapon_2.en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/docs/img/weapon_2.en.png -------------------------------------------------------------------------------- /docs/index.en.md: -------------------------------------------------------------------------------- 1 | # ModShardLauncher Modding Documentation 2 | 3 | Welcome to the **ModShardLauncher Modding Documentation** ! 4 | 5 | !!! info "Multiple languages" 6 | This documentation is available in **multiple languages**.
7 | You can change the language by clicking the **language button** at the **top** of the page.

8 | Some pages may not be available in all languages, so feel free to contribute! -------------------------------------------------------------------------------- /docs/index.zh.md: -------------------------------------------------------------------------------- 1 | # ModShardLauncher Modding Documentation 2 | 3 | 欢迎访问 **ModShardLauncher 文档** ! 4 | 5 | !!! info "多种语言" 6 | 本文档提供多种语言版本。
7 | 您可以点击页面顶部的语言按钮更改语言。

8 | 某些页面可能不支持所有语言,请随时提供您的意见! -------------------------------------------------------------------------------- /future_workflow.md: -------------------------------------------------------------------------------- 1 | # RELEASE RECIPE 2 | 3 | - `git pull` in main repo 4 | - Edit version in ModShardLauncher.csproj 5 | - `git tag vX.XX.X.X` 6 | - `git push origin vX.XX.X.X` last modification 7 | - `git log` to check for properly tagged commit 8 | - `git pull` for safety 9 | - dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true /p:IncludeAllContentForSelfExtract=true /p:PublishReadyToRun=true --self-contained 10 | - locate `publish` folder in `bin/release/net6.0-windows\win-x64\` 11 | - Move required dlls (everything in `ModReference` + `Reference` folders) in the folder 12 | - Run `ModShardLauncher.exe` once 13 | - Verify there is no unexpected file / folder / mods 14 | - Archive to msl.zip 15 | - Test in sandbox environment (no need to install .NET, use a vanilla.win + a mod you **__KNOW__** works) and check proper injection with UTMTCE 16 | - Add archive to release 17 | - Publish release -------------------------------------------------------------------------------- /ico.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModShardTeam/ModShardLauncher/2703478b5b1272e41d3c78fe6170a9b3cea26984/ico.ico -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: ModShardLauncher Modding Documentation 2 | repo_url: https://github.com/ModShardTeam/ModShardLauncher 3 | repo_name: ModShardTeam/ModShardLauncher 4 | edit_uri: edit/main/docs/ 5 | use_directory_urls: false 6 | copyright: All rights belong to Ink Stains Games.
This is a community 7 | project and is not affiliated with Ink Stains Games. 8 | 9 | 10 | theme: 11 | name: material 12 | favicon: img/Stoneshard.ico 13 | features: 14 | - navigation.path 15 | - navigation.indexes 16 | - header.autohide 17 | - toc.integrate 18 | - navigation.top 19 | - search.suggest 20 | - search.highlight 21 | - content.tabs.link 22 | - content.code.annotate 23 | - content.code.copy 24 | - content.action.edit 25 | - content.action.view 26 | language: en 27 | locale: en 28 | palette: 29 | - scheme: default 30 | toggle: 31 | icon: material/brightness-7 32 | name: Switch to Dark Mode 33 | - scheme: slate 34 | toggle: 35 | icon: material/brightness-4 36 | name: Switch to Light Mode 37 | 38 | extra: 39 | social: 40 | - icon: fontawesome/brands/discord 41 | link: https://discord.gg/YxfRKYUuht 42 | name: Stoneshard Mod Hub Discord 43 | - icon: fontawesome/brands/github 44 | link: https://github.com/DDDDDragon/ModShardLauncher 45 | name: GitHub Repository 46 | - icon: fontawesome/brands/steam 47 | link: https://store.steampowered.com/app/625960/Stoneshard/ 48 | name: Stoneshard on Steam 49 | - icon: simple/gogdotcom 50 | link: https://www.gog.com/game/stoneshard 51 | name: Stoneshard on GOG 52 | 53 | markdown_extensions: 54 | - attr_list 55 | - admonition 56 | - pymdownx.details 57 | - pymdownx.superfences 58 | - pymdownx.highlight: 59 | anchor_linenums: true 60 | line_spans: __span 61 | pygments_lang_class: true 62 | - pymdownx.inlinehilite 63 | - pymdownx.snippets 64 | - pymdownx.critic 65 | - pymdownx.caret 66 | - pymdownx.keys 67 | - pymdownx.mark 68 | - pymdownx.tilde 69 | - pymdownx.tabbed: 70 | alternate_style: true 71 | - pymdownx.emoji: 72 | emoji_index: !!python/name:material.extensions.emoji.twemoji 73 | emoji_generator: !!python/name:material.extensions.emoji.to_svg 74 | 75 | 76 | plugins: 77 | - search 78 | - table-reader 79 | - glightbox 80 | - git-authors 81 | - git-revision-date 82 | - i18n: 83 | docs_structure: suffix 84 | reconfigure_material: true 85 | reconfigure_search: true 86 | languages: 87 | - locale: en 88 | default: true 89 | name: English 90 | build: true 91 | - locale: zh 92 | name: 中文 93 | build: true 94 | nav_translations: 95 | Index: 首页 96 | Welcome: 欢迎 97 | Guides: 指南 98 | Introduction: 简介 99 | Creating your First Mod: 开始 100 | Installing Mods: 如何使用MOD 101 | API: API 102 | Modding: MOD制作 103 | # You can remove the nav_translations above and remove comments here if you want to have custom ZH nav. 104 | # This would avoid setting up empty 'TODO' pages. 105 | # nav: 106 | # - 首页: "index.md" 107 | # - 指南: 108 | # - "简介": "guides/introduction.md" 109 | # - ... : ... 110 | 111 | 112 | nav: 113 | - Index: 114 | - "Index": "index.md" 115 | - Guides: 116 | - "Introduction": "guides/introduction.md" 117 | - "Installing Mods": "guides/how-to-play-mod.md" 118 | - Modding : 119 | - "API": "guides/api.md" 120 | - "Creating your First Mod": "guides/start-modding.md" --------------------------------------------------------------------------------