Compare commits
No commits in common. "neoforge" and "7f35bab4343e1403575ab183bc2055e0a06567fc" have entirely different histories.
neoforge
...
7f35bab434
|
@ -1,50 +0,0 @@
|
||||||
name: Build TurnBasedMC and create Release
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- '*'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check-release-exists:
|
|
||||||
runs-on: any_archLinux
|
|
||||||
outputs:
|
|
||||||
status: ${{ steps.release_exists_check.outputs.http_code }}
|
|
||||||
steps:
|
|
||||||
- name: Check if release already exists
|
|
||||||
id: release_exists_check
|
|
||||||
run: |
|
|
||||||
curl -X GET "https://git.seodisparate.com/api/v1/repos/stephenseo/TurnBasedMinecraftMod/releases/tags/${GITHUB_REF_NAME}" \
|
|
||||||
-H 'accept: application/json' -o release_check_resp.json 2>/dev/null \
|
|
||||||
-w '%{http_code}\n' | sed 's/^\([0-9]\+\)/http_code=\1/' >> "$GITHUB_OUTPUT"
|
|
||||||
build-and-create-release:
|
|
||||||
needs: check-release-exists
|
|
||||||
if: ${{ needs.check-release-exists.outputs.status == '404' }}
|
|
||||||
runs-on: highmem_self
|
|
||||||
steps:
|
|
||||||
- run: git clone --depth=1 --no-single-branch https://git.seodisparate.com/stephenseo/TurnBasedMinecraftMod.git TurnBasedMinecraftMod
|
|
||||||
- run: cd TurnBasedMinecraftMod && git checkout ${GITHUB_REF_NAME}
|
|
||||||
- run: cd TurnBasedMinecraftMod && sed -i '/org.gradle.jvmargs/s/Xmx[0-9]\+[mMgG]/Xmx1024m/' gradle.properties && echo 'neogradle.subsystems.decompiler.maxThreads=1' >> gradle.properties
|
|
||||||
- run: cd TurnBasedMinecraftMod && ./gradlew --console=plain build
|
|
||||||
- run: cd TurnBasedMinecraftMod/build/libs && find . -type f -regex '.*all.jar$' -exec sha256sum '{}' ';' -exec bash -c 'sha256sum {} >> sha256sums.txt' ';' && java --version >> javaVersion.txt && javac --version >> javaVersion.txt
|
|
||||||
- name: Create release and attach jar
|
|
||||||
run: |
|
|
||||||
curl --fail-with-body -X 'POST' \
|
|
||||||
"https://git.seodisparate.com/api/v1/repos/stephenseo/TurnBasedMinecraftMod/releases" \
|
|
||||||
-H 'accept: application/json' \
|
|
||||||
-H "Authorization: token ${GITHUB_TOKEN}" \
|
|
||||||
-H 'Content-Type: application/json' \
|
|
||||||
-d "{
|
|
||||||
\"name\": \"TurnBasedMinecraftMod version ${GITHUB_REF_NAME}\",
|
|
||||||
\"body\": \"See the [Changelog](https://git.seodisparate.com/stephenseo/TurnBasedMinecraftMod/src/branch/neoforge/Changelog.md)
|
|
||||||
|
|
||||||
$(java --version | sed -n '1p;2,$s/^/ /p')
|
|
||||||
$(javac --version)
|
|
||||||
$(find TurnBasedMinecraftMod/build/libs -regex '.*all.jar$' -exec sha256sum '{}' ';')\",
|
|
||||||
\"tag_name\": \"${GITHUB_REF_NAME}\"
|
|
||||||
}" > response.json \
|
|
||||||
&& curl --fail-with-body -X 'POST' \
|
|
||||||
"https://git.seodisparate.com/api/v1/repos/stephenseo/TurnBasedMinecraftMod/releases/$(jq .id < response.json)/assets" \
|
|
||||||
-H 'accept: application/json' \
|
|
||||||
-H "Authorization: token ${GITHUB_TOKEN}" \
|
|
||||||
-H 'Content-Type: multipart/form-data' \
|
|
||||||
-F "attachment=@$(find TurnBasedMinecraftMod/build/libs -regex '.*all.jar$');type=application/java-archive" > response2.json
|
|
25
.gitignore
vendored
|
@ -1,25 +0,0 @@
|
||||||
# eclipse
|
|
||||||
bin
|
|
||||||
*.launch
|
|
||||||
.settings
|
|
||||||
.metadata
|
|
||||||
.classpath
|
|
||||||
.project
|
|
||||||
|
|
||||||
# idea
|
|
||||||
out
|
|
||||||
*.ipr
|
|
||||||
*.iws
|
|
||||||
*.iml
|
|
||||||
.idea
|
|
||||||
|
|
||||||
# gradle
|
|
||||||
build
|
|
||||||
.gradle
|
|
||||||
|
|
||||||
# other
|
|
||||||
eclipse
|
|
||||||
run
|
|
||||||
|
|
||||||
logs/
|
|
||||||
runs/
|
|
0
.nojekyll
Normal file
177
404.html
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" data-bs-theme="dark">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="/img/favicon.ico">
|
||||||
|
<title>Documentation for TurnBasedMinecraftMod</title>
|
||||||
|
<link href="/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="/css/fontawesome.min.css" rel="stylesheet">
|
||||||
|
<link href="/css/brands.min.css" rel="stylesheet">
|
||||||
|
<link href="/css/solid.min.css" rel="stylesheet">
|
||||||
|
<link href="/css/v4-font-face.min.css" rel="stylesheet">
|
||||||
|
<link href="/css/base.css" rel="stylesheet">
|
||||||
|
<link id="hljs-light" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css" disabled>
|
||||||
|
<link id="hljs-dark" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github-dark.min.css" >
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
|
||||||
|
<script>hljs.highlightAll();</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand" href="/.">Documentation for TurnBasedMinecraftMod</a>
|
||||||
|
<!-- Expander button -->
|
||||||
|
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#navbar-collapse" aria-controls="navbar-collapse" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Expanded navigation -->
|
||||||
|
<div id="navbar-collapse" class="navbar-collapse collapse">
|
||||||
|
<!-- Main navigation -->
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="/." class="nav-link">TurnBasedMinecraftMod</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="/client_config/" class="nav-link">Client-side Config</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="/server_config/" class="nav-link">Server-side Config</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="nav navbar-nav ms-md-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="#" class="nav-link" data-bs-toggle="modal" data-bs-target="#mkdocs_search_modal">
|
||||||
|
<i class="fa fa-search"></i> Search
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<button id="theme-menu" aria-expanded="false" data-bs-toggle="dropdown" data-bs-display="static" aria-label="Toggle theme" class="nav-link dropdown-toggle">
|
||||||
|
<i class="fa-solid fa-circle-half-stroke fa-fw"></i>
|
||||||
|
<span class="d-lg-none ms-2">Toggle theme</span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="light" aria-pressed="false">
|
||||||
|
<i class="fa-solid fa-sun fa-fw"></i>
|
||||||
|
<span class="ms-2">Light</span>
|
||||||
|
<i class="fa-solid fa-check ms-auto d-none"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="dark" aria-pressed="true">
|
||||||
|
<i class="fa-solid fa-moon fa-fw"></i>
|
||||||
|
<span class="ms-2">Dark</span>
|
||||||
|
<i class="fa-solid fa-check ms-auto"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="auto" aria-pressed="false">
|
||||||
|
<i class="fa-solid fa-circle-half-stroke fa-fw"></i>
|
||||||
|
<span class="ms-2">Auto</span>
|
||||||
|
<i class="fa-solid fa-check ms-auto d-none"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="/js/darkmode.js"></script>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="row-fluid">
|
||||||
|
<div id="main-content" class="span12">
|
||||||
|
<h1 id="404-page-not-found" style="text-align: center">404</h1>
|
||||||
|
<p style="text-align: center"><strong>Page not found</strong></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="col-md-12">
|
||||||
|
<hr>
|
||||||
|
<p>Documentation built with <a href="https://www.mkdocs.org/">MkDocs</a>.</p>
|
||||||
|
</footer>
|
||||||
|
<script src="/js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script>
|
||||||
|
var base_url = "/",
|
||||||
|
shortcuts = {"help": 191, "next": 78, "previous": 80, "search": 83};
|
||||||
|
</script>
|
||||||
|
<script src="/js/base.js"></script>
|
||||||
|
<script src="/search/main.js"></script>
|
||||||
|
|
||||||
|
<div class="modal" id="mkdocs_search_modal" tabindex="-1" role="dialog" aria-labelledby="searchModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="searchModalLabel">Search</h4>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>From here you can search these documents. Enter your search terms below.</p>
|
||||||
|
<form>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="search" class="form-control" placeholder="Search..." id="mkdocs-search-query" title="Type search term here">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div id="mkdocs-search-results" data-no-results-text="No results found"></div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><div class="modal" id="mkdocs_keyboard_modal" tabindex="-1" role="dialog" aria-labelledby="keyboardModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="keyboardModalLabel">Keyboard Shortcuts</h4>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width: 20%;">Keys</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="help shortcut"><kbd>?</kbd></td>
|
||||||
|
<td>Open this help</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="next shortcut"><kbd>n</kbd></td>
|
||||||
|
<td>Next page</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="prev shortcut"><kbd>p</kbd></td>
|
||||||
|
<td>Previous page</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="search shortcut"><kbd>s</kbd></td>
|
||||||
|
<td>Search</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
560
Changelog.md
|
@ -1,560 +0,0 @@
|
||||||
# Upcoming changes
|
|
||||||
|
|
||||||
# Version Forge-1.26.5
|
|
||||||
|
|
||||||
Update TBM\_Config.toml to have haste\_speed and slow\_speed for all mob
|
|
||||||
entries.
|
|
||||||
|
|
||||||
Update Config to merge in new changes. This means that the existing config will
|
|
||||||
be overwritten much less frequently (if ever).
|
|
||||||
|
|
||||||
Update to Forge 52.0.26 (MC 1.21.1).
|
|
||||||
|
|
||||||
# Version NeoForge-1.26.5-MC-1.21.1
|
|
||||||
|
|
||||||
Update TBM\_Config.toml to have haste\_speed and slow\_speed for all mob
|
|
||||||
entries.
|
|
||||||
|
|
||||||
Update ClientConfigGui to quit to mod-menu screen in NeoForge (before, it quit
|
|
||||||
to the main screen or current game).
|
|
||||||
|
|
||||||
Update Config to merge in new changes. This means that the existing config will
|
|
||||||
be overwritten much less frequently (if ever).
|
|
||||||
|
|
||||||
Update to NeoForge 21.1.74 (MC 1.21.1).
|
|
||||||
|
|
||||||
# Version NeoForge-1.26.5
|
|
||||||
|
|
||||||
Update TBM\_Config.toml to have haste\_speed and slow\_speed for all mob
|
|
||||||
entries.
|
|
||||||
|
|
||||||
Update ClientConfigGui to quit to mod-menu screen in NeoForge (before, it quit
|
|
||||||
to the main screen or current game).
|
|
||||||
|
|
||||||
Update Config to merge in new changes. This means that the existing config will
|
|
||||||
be overwritten much less frequently (if ever).
|
|
||||||
|
|
||||||
Update to NeoForge 21.3.11-beta (MC 1.21.3).
|
|
||||||
|
|
||||||
# Version Forge-1.26.4
|
|
||||||
|
|
||||||
[Add support for "per-player-stats" in Turn-Based-Battle.](https://stephen-seo.github.io/TurnBasedMinecraftMod/server_config/#per-player-settings)
|
|
||||||
|
|
||||||
Update to Forge 52.0.24 (MC 1.21.1).
|
|
||||||
|
|
||||||
# Version NeoForge-1.26.4-MC-1.21.1
|
|
||||||
|
|
||||||
[Add support for "per-player-stats" in Turn-Based-Battle.](https://stephen-seo.github.io/TurnBasedMinecraftMod/server_config/#per-player-settings)
|
|
||||||
|
|
||||||
Update to Neoforge 21.1.73 (Minecraft 1.21.1).
|
|
||||||
|
|
||||||
# Version NeoForge-1.26.4
|
|
||||||
|
|
||||||
[Add support for "per-player-stats" in Turn-Based-Battle.](https://stephen-seo.github.io/TurnBasedMinecraftMod/server_config/#per-player-settings)
|
|
||||||
|
|
||||||
Update to NeoForge 21.3.6-beta (MC 1.21.3).
|
|
||||||
|
|
||||||
# Version Forge-1.26.3
|
|
||||||
|
|
||||||
Tweak to "Ping" packet to not create client-local Battle instance if it does
|
|
||||||
not exist.
|
|
||||||
|
|
||||||
# Version NeoForge-1.26.3
|
|
||||||
|
|
||||||
Port to NeoForge 21.3.2-beta (MC 1.21.3).
|
|
||||||
|
|
||||||
Note that MC 1.21.1 (NeoForge 21.1.72) will still be supported in a separate
|
|
||||||
branch (neoforge\_mc1.21.1) until MC version 1.22 is released.
|
|
||||||
|
|
||||||
Tweak to "Ping" packet to not create client-local Battle instance if it does
|
|
||||||
not exist.
|
|
||||||
|
|
||||||
# Version NeoForge-1.26.3-MC-1.21.1
|
|
||||||
|
|
||||||
Tweak to "Ping" packet to not create client-local Battle instance if it does
|
|
||||||
not exist.
|
|
||||||
|
|
||||||
# Version Forge-1.26.2
|
|
||||||
|
|
||||||
Show battling Entities next to their attack button in the BattleGUI.
|
|
||||||
|
|
||||||
# Version NeoForge-1.26.2
|
|
||||||
|
|
||||||
Show battling Entities next to their attack button in the BattleGUI.
|
|
||||||
|
|
||||||
# Version Forge-1.26.1
|
|
||||||
|
|
||||||
Minor fixes/refactorings that should make the mod more robust.
|
|
||||||
|
|
||||||
Port to Forge 52.0.22 (Minecraft 1.21.1).
|
|
||||||
|
|
||||||
Allow leaving battle GUI with Escape key (temporarily), and some refactorings
|
|
||||||
to (hopefully) fix that pesky transient client-freeze-bug.
|
|
||||||
|
|
||||||
Minecraft's music should be paused during battle, even if it starts mid-battle.
|
|
||||||
(Minecraft's music may play up to 4 seconds before it is paused by TBMM.)
|
|
||||||
|
|
||||||
# Version NeoForge-1.26.1
|
|
||||||
|
|
||||||
Minor fixes/refactorings that should make the mod more robust.
|
|
||||||
|
|
||||||
Port to NeoForge-21.1.72 (Minecraft 1.21.1).
|
|
||||||
|
|
||||||
Allow leaving battle GUI with Escape key (temporarily), and some refactorings
|
|
||||||
to (hopefully) fix that pesky transient client-freeze-bug.
|
|
||||||
|
|
||||||
Minecraft's music should be paused during battle, even if it starts mid-battle.
|
|
||||||
(Minecraft's music may play up to 4 seconds before it is paused by TBMM.)
|
|
||||||
|
|
||||||
# Version Forge-1.26.0
|
|
||||||
|
|
||||||
Port to Forge 52.0.21 (Minecraft 1.21.1).
|
|
||||||
|
|
||||||
Client-config available via `/tbm-client-edit` (same as NeoForge), but there is
|
|
||||||
no way to access it via the mod-list (unlike NeoForge). Removed from file
|
|
||||||
holding server-side config (same as NeoForge).
|
|
||||||
|
|
||||||
Add option in client-config to set battle/silly music volume, and an option for
|
|
||||||
whether or not battle/silly music volume is affected by global music volume
|
|
||||||
setting and whether or not it is affected by master volume setting.
|
|
||||||
|
|
||||||
Proper volume handling (like in the NeoForge branch).
|
|
||||||
|
|
||||||
Added Armadillo, Bogged, and Breeze to mob list in config.
|
|
||||||
|
|
||||||
# Version NeoForge-1.26.0
|
|
||||||
|
|
||||||
Make it possible to open the client-config from the Mod-list GUI.
|
|
||||||
|
|
||||||
Port to NeoForge 21.1.69 (Minecraft 1.21.1).
|
|
||||||
|
|
||||||
Fix volume handling of battle/silly music. (Previous implementation did not
|
|
||||||
properly reduce volume based on Minecraft's "music volume" setting.)
|
|
||||||
|
|
||||||
Move client-config to NeoForge's configuration.
|
|
||||||
|
|
||||||
Add GUI to edit client-config that can be opened with /tbm-client-edit command.
|
|
||||||
|
|
||||||
Add option in client-config to set battle/silly music volume, and an option for
|
|
||||||
whether or not battle/silly music volume is affected by global music volume
|
|
||||||
setting and whether or not it is affected by master volume setting.
|
|
||||||
|
|
||||||
Added Armadillo, Bogged, and Breeze to mob list in config.
|
|
||||||
|
|
||||||
# Version NeoForge-1.25.2
|
|
||||||
|
|
||||||
Fix invalid use of throwable potions. (Previously, the Player would "drink"
|
|
||||||
splash/lingering potions when used.) Now, if a splash/lingering potion is
|
|
||||||
"Use"d in battle, it will be thrown.
|
|
||||||
|
|
||||||
Add experimental support for "right-click" of arbitrary items on hotbar when
|
|
||||||
"Use" is used in battle.
|
|
||||||
|
|
||||||
# Version Forge-1.25.2
|
|
||||||
|
|
||||||
Fix invalid use of throwable potions. (Previously, the Player would "drink"
|
|
||||||
splash/lingering potions when used.) Now, if a splash/lingering potion is
|
|
||||||
"Use"d in battle, it will be thrown.
|
|
||||||
|
|
||||||
Add experimental support for "right-click" of arbitrary items on hotbar when
|
|
||||||
"Use" is used in battle.
|
|
||||||
|
|
||||||
# Version Forge-1.25.1
|
|
||||||
|
|
||||||
Add icon for mod in Mod list description.
|
|
||||||
|
|
||||||
Update for Forge 49.0.19.
|
|
||||||
Works on Forge Minecraft 1.20.4.
|
|
||||||
|
|
||||||
# Version NeoForge-1.25.1
|
|
||||||
|
|
||||||
Add icon for mod in Mod list description.
|
|
||||||
|
|
||||||
Update for NeoForge 20.4.108-beta.
|
|
||||||
Works on NeoForge Minecraft 1.20.4.
|
|
||||||
|
|
||||||
# Version NeoForge-1.25.0
|
|
||||||
|
|
||||||
Add new dependency `j-ogg-vorbis`.
|
|
||||||
|
|
||||||
Implement playing Vorbis encoded .ogg files for battle/silly music.
|
|
||||||
|
|
||||||
# Version Forge-1.25.0
|
|
||||||
|
|
||||||
Remove usage of "shadow jar" in build.gradle, and use jarJar instead.
|
|
||||||
|
|
||||||
Add new dependency `j-ogg-vorbis`.
|
|
||||||
|
|
||||||
Implement playing Vorbis encoded .ogg files for battle/silly music.
|
|
||||||
|
|
||||||
# Version NeoForge-1.24.0
|
|
||||||
|
|
||||||
Update to NeoForge 1.20.2-20.2.88.
|
|
||||||
|
|
||||||
Allow use of Crossbows in battle (it should behave identically to Bows).
|
|
||||||
|
|
||||||
# Version Forge-1.24.0
|
|
||||||
|
|
||||||
Update to Forge 1.20.2-48.1.0.
|
|
||||||
|
|
||||||
The `master` branch of this repository will track the build for Minecraft Forge.
|
|
||||||
|
|
||||||
The `neoforge` branch of this repo. will track the build for NeoForge.
|
|
||||||
|
|
||||||
Allow use of Crossbows in battle (it should behave identically to Bows).
|
|
||||||
|
|
||||||
# Version 1.23.1
|
|
||||||
|
|
||||||
More robust handling of disallowed Damage Sources in battle (via config).
|
|
||||||
Basically, the mod will load all possible damage sources. Damage sources to be
|
|
||||||
ignored in battle can be modified with "/tbm-server-edit" and clicking on
|
|
||||||
"ignore\_damage\_sources". It can also be manually modified in the server
|
|
||||||
config's "ignore\_damage\_sources" array.
|
|
||||||
|
|
||||||
# Version 1.23.0
|
|
||||||
|
|
||||||
Support reproducible builds. This means that if this mod is compiled, then it
|
|
||||||
should be byte-by-byte exactly the same as another compiled jar (assuming it
|
|
||||||
was compiled with the same version of Java and same mod version.)
|
|
||||||
|
|
||||||
Update to Forge 1.20.1-47.1.0.
|
|
||||||
|
|
||||||
Experimental support for "use item" for unrecognized items. Note that this uses
|
|
||||||
the Minecraft API's `Item.finishUsingItem(...)`.
|
|
||||||
|
|
||||||
# Version 1.22.0
|
|
||||||
|
|
||||||
Update to Forge 1.19.3-44.1.0.
|
|
||||||
|
|
||||||
# Version 1.21.4
|
|
||||||
|
|
||||||
More refactoring of check-if-in-battle lookup code.
|
|
||||||
|
|
||||||
Fix potential bug where clients cannot attack entities if their config didn't
|
|
||||||
exist client-side. They should now always be available to attack regardless of
|
|
||||||
whether or not the client has the config entry for an entity.
|
|
||||||
|
|
||||||
# Version 1.21.3
|
|
||||||
|
|
||||||
Implemented "player-only" battles, which can be enabled in the server-side
|
|
||||||
config or set using `/tbm-server-edit`. (Somewhat untested because I am only 1
|
|
||||||
person.)
|
|
||||||
|
|
||||||
# Version 1.21.2
|
|
||||||
|
|
||||||
Refactored checking-if-in-battle code from `O(n)` to `O(1)` complexity.
|
|
||||||
(In other words, utilizes the HashMap's constant time lookup of a key instead of
|
|
||||||
checking every key's id if the entity's id is the same. This speeds up the
|
|
||||||
lookup from linear to constant time.)
|
|
||||||
|
|
||||||
# Version 1.21.1
|
|
||||||
|
|
||||||
Refactored checking-if-in-battle code to be more efficient.
|
|
||||||
|
|
||||||
# Version 1.21.0
|
|
||||||
|
|
||||||
Updated mod to use forge-1.19.2-43.1.1
|
|
||||||
|
|
||||||
# Version 1.20
|
|
||||||
|
|
||||||
Implemented ignoring specific damage sources while in battle (like lava or
|
|
||||||
drowning). The damage sources can be tweaked with `/tbm-server-edit`.
|
|
||||||
|
|
||||||
Also updated entity entries in the config so that the mod logs much less when an
|
|
||||||
entity does not have specific values (which gets logged if missing).
|
|
||||||
|
|
||||||
Note that the TBM_Config.toml file has been updated. This means that your existing
|
|
||||||
TBM_Config.toml will be renamed and replaced by the newly updated config.
|
|
||||||
If you made changes to this file, you will need to apply them again to the new
|
|
||||||
updated config to keep the changes.
|
|
||||||
|
|
||||||
# Version 1.19
|
|
||||||
|
|
||||||
Updated to work with forge-1.19-41.1.0. (Somehow, this mod's version number
|
|
||||||
ended up being the same as Minecraft's version number. Don't count on this to
|
|
||||||
remain the same.)
|
|
||||||
|
|
||||||
Added Allay, Frog, Tadpole, and Warden entities to the config. (The config
|
|
||||||
version has incremented, so existing config will be replaced. Note that existing
|
|
||||||
config will not be deleted, but renamed.)
|
|
||||||
|
|
||||||
# Version 1.18.7
|
|
||||||
|
|
||||||
Incremented network channel's protocol version to 2, because a packet's format
|
|
||||||
was changed in the previous version.
|
|
||||||
|
|
||||||
# Version 1.18.6
|
|
||||||
|
|
||||||
Add server config option to disable the turn timer (recommended to not disable
|
|
||||||
the turn timer, otherwise a player could hang a battle for forever).
|
|
||||||
|
|
||||||
Fix turn timer not respecting the server's turn timer value. For example, if the
|
|
||||||
server had it set to 5 seconds, but the client had it set to 15 seconds, the
|
|
||||||
turn timer would erronously show 15 seconds at the start of the next turn.
|
|
||||||
|
|
||||||
# Version 1.18.5
|
|
||||||
|
|
||||||
Fix invalid Battle text output when a Player drinks a potion.
|
|
||||||
|
|
||||||
# Version 1.18.4
|
|
||||||
|
|
||||||
Fix attacks not hitting due to "invulnerability frames".
|
|
||||||
|
|
||||||
Change attacks to be applied approx 150ms apart.
|
|
||||||
|
|
||||||
# Version 1.18.3
|
|
||||||
|
|
||||||
[The ability to change server-side config from within the game using
|
|
||||||
"/tbm-server-edit".](https://youtu.be/9xkbHNWkcIY)
|
|
||||||
|
|
||||||
Fix Battle not checking Player "speed/slow" status to apply the
|
|
||||||
"player\_haste\_speed" and "player\_slow\_speed" settings.
|
|
||||||
|
|
||||||
# Version 1.18.2
|
|
||||||
|
|
||||||
The list of targets in the Battle GUI when selecting a target did not display
|
|
||||||
Players' names in their team color. This version now shows Player names with
|
|
||||||
their team color in the target buttons/list.
|
|
||||||
|
|
||||||
# Version 1.18.1
|
|
||||||
|
|
||||||
Fix battle text output such that players in teams will have their name displayed
|
|
||||||
with the team's color (and some refactoring of related battle text output).
|
|
||||||
|
|
||||||
# Version 1.18.0
|
|
||||||
|
|
||||||
Mod now works with Forge-1.18.2-40.1.0 .
|
|
||||||
Note that the mod's version is confusingly similar (1.18.0).
|
|
||||||
|
|
||||||
TBM should allow players to eat any food from any mod (including food items from Pam's HarvestCraft).
|
|
||||||
|
|
||||||
# Version 1.17.2.6
|
|
||||||
|
|
||||||
(Branched from 1.17.2)
|
|
||||||
|
|
||||||
Implemented getting EntityInfo for CustomNPCs that have the same name as a
|
|
||||||
"custom entry" in the "server\_config.entity" array in the config.
|
|
||||||
|
|
||||||
# Version 1.17.2.5
|
|
||||||
|
|
||||||
(Branched from 1.17.2)
|
|
||||||
|
|
||||||
Refactored OtherModHandling.java to be more efficient when handling CustomNPCs
|
|
||||||
DamagedEvent.
|
|
||||||
|
|
||||||
# Version 1.17.2.4
|
|
||||||
|
|
||||||
(Branched from 1.17.2)
|
|
||||||
|
|
||||||
Fix usage of NpcAPI.
|
|
||||||
|
|
||||||
# Version 1.17.2.3
|
|
||||||
|
|
||||||
(Branched from 1.17.2)
|
|
||||||
|
|
||||||
Fix potential unhandled exception crash bug related to handling CustomNPCs
|
|
||||||
Player hurt events.
|
|
||||||
|
|
||||||
# Version 1.17.2.2
|
|
||||||
|
|
||||||
(Branched from 1.17.2)
|
|
||||||
|
|
||||||
Fix potential NullPointerException crash bug.
|
|
||||||
|
|
||||||
# Version 1.17.2.1
|
|
||||||
|
|
||||||
(Branched from 1.17.2)
|
|
||||||
|
|
||||||
Attempt to fix CustomNPCs mods not damaging players in TurnBased combat.
|
|
||||||
|
|
||||||
# Version 1.17.2
|
|
||||||
|
|
||||||
(try to) Fix potential freeze bug when an entity leaves battle.
|
|
||||||
|
|
||||||
# Version 1.17.1
|
|
||||||
|
|
||||||
Add experimental support for Pam's Harvestcraft foods.
|
|
||||||
|
|
||||||
# Version 1.17
|
|
||||||
|
|
||||||
Update mod for Forge 1.16.5-36.1.0 .
|
|
||||||
|
|
||||||
# Version 1.16
|
|
||||||
|
|
||||||
Add config options regarding creeper behavior.
|
|
||||||
|
|
||||||
By default, creepers will not explode if they leave battle (maybe due to a
|
|
||||||
player fleeing), until the cooldown time ends.
|
|
||||||
|
|
||||||
By default, creepers that explode will damage anyone, even if they weren't in
|
|
||||||
turn-based battle.
|
|
||||||
|
|
||||||
# Version 1.15
|
|
||||||
|
|
||||||
Add server-side config option that determines on what turn a Creeper will
|
|
||||||
explode in battle.
|
|
||||||
|
|
||||||
# Version 1.14
|
|
||||||
|
|
||||||
Implemented support for Creepers in battle.
|
|
||||||
|
|
||||||
Added an option to the config to prevent config from being overwritten on
|
|
||||||
update.
|
|
||||||
|
|
||||||
Fixed some display text during battle.
|
|
||||||
|
|
||||||
# Version 1.13
|
|
||||||
|
|
||||||
Disabled midi playback due to currently being unable to change its volume.
|
|
||||||
|
|
||||||
Note mp3 playback breaks sometimes. Using an mp3 file without album art seems to
|
|
||||||
work though...
|
|
||||||
|
|
||||||
# Version 1.12
|
|
||||||
|
|
||||||
Fix potential crash if mod is loaded on dedicated server.
|
|
||||||
|
|
||||||
# Version 1.11
|
|
||||||
|
|
||||||
Fixed text display in BattleGUI.
|
|
||||||
|
|
||||||
Updated TBM\_Config.toml with new vanilla mobs.
|
|
||||||
|
|
||||||
Fixed version parsing of TBM\_Config.toml.
|
|
||||||
|
|
||||||
# Version 1.10
|
|
||||||
|
|
||||||
Updated for 1.16.3
|
|
||||||
|
|
||||||
Compiled against forge version "1.16.3-34.1.0"
|
|
||||||
|
|
||||||
However, MP3 playing seems to not work sometimes.
|
|
||||||
|
|
||||||
# Version 1.9
|
|
||||||
|
|
||||||
Updated mod for 1.14.4
|
|
||||||
(Took a long while, and no new features were added due to making sure everything
|
|
||||||
still works).
|
|
||||||
|
|
||||||
Compiled against forge version "1.14.4-28.1.0"
|
|
||||||
|
|
||||||
Entity names have changed in the config, so this newer version will replace the
|
|
||||||
old version. Older existing config should be renamed rather than deleted.
|
|
||||||
|
|
||||||
# Version 1.8
|
|
||||||
|
|
||||||
Update to forge version "1.12.2-14.23.5.2768".
|
|
||||||
|
|
||||||
Fix bug where more than config-set-amount of entities can be in battle.
|
|
||||||
|
|
||||||
Add mp3 support, can now play mp3s.
|
|
||||||
|
|
||||||
Minor improvements.
|
|
||||||
|
|
||||||
# Version 1.7
|
|
||||||
|
|
||||||
Fix bug where after using "/tbm-edit", ignore_battle option is saved in
|
|
||||||
config with the wrong name.
|
|
||||||
|
|
||||||
Add "/tbm-edit custom", which lets an OP add an entity entry for entities with
|
|
||||||
custom names (via name-tags). The entry added into the config file will use
|
|
||||||
"custom_name" instead of "name" to specify if it is a regular entity entry
|
|
||||||
or an entry for a specific custom name.
|
|
||||||
|
|
||||||
Minor fixes and improvements.
|
|
||||||
|
|
||||||
# Version 1.6
|
|
||||||
|
|
||||||
Fix bug where player can start battle with self.
|
|
||||||
|
|
||||||
Change config to use ".toml" instead of ".xml".
|
|
||||||
|
|
||||||
Added command "/tbm-edit" that allows OPs to edit entity entries for TBM.
|
|
||||||
Can be used to add mobs from other mods easily.
|
|
||||||
|
|
||||||
Change how battle info text is displayed.
|
|
||||||
|
|
||||||
# Version 1.5
|
|
||||||
|
|
||||||
Fix proper consumption of food/potion items in battle.
|
|
||||||
|
|
||||||
Added some debug output on internal freeze occurrence (investigation of the
|
|
||||||
freeze bug is still ongoing).
|
|
||||||
|
|
||||||
# Version 1.4
|
|
||||||
|
|
||||||
Fix duplicate "... entered battle" messages.
|
|
||||||
|
|
||||||
Added max-distance config option for how close a monster must be to initiate
|
|
||||||
battle (when triggered by a monster targeting a player or entity in battle).
|
|
||||||
|
|
||||||
Some internal fixes and refactorings.
|
|
||||||
|
|
||||||
# Version 1.3
|
|
||||||
|
|
||||||
Added a battle-cooldown and related config option. Now, when leaving battle, a
|
|
||||||
cooldown timer (default 5 seconds) prevents entities from
|
|
||||||
attacking/being-attacked for the duration of the cooldown. Can be set to a
|
|
||||||
minimum of 1 second and maximum of 10 seconds.
|
|
||||||
|
|
||||||
"/tbm-enable-all" and "/tbm-disable-all" now notifies all players when they are
|
|
||||||
invoked by an OP.
|
|
||||||
|
|
||||||
Battles can now be started/joined by hostile mobs when they target a player or
|
|
||||||
other entity in battle, instead of just entering on attack. Old
|
|
||||||
battle-starting-behavior can be used by setting the related config option.
|
|
||||||
(This change was made to keep zombies from gathering around the player when
|
|
||||||
the config option for freezing entities in battle is enabled.)
|
|
||||||
|
|
||||||
Non-player entities in battle now primarily attack entities they are already
|
|
||||||
targeting (via a call to EntityLiving's "getAttackTarget()").
|
|
||||||
|
|
||||||
Note since config version is now 5, older config will be renamed and the new
|
|
||||||
config will take its place.
|
|
||||||
|
|
||||||
# Version 1.2
|
|
||||||
|
|
||||||
Fixed "/tbm-enable" and "/tbm-disable" not working in singleplayer.
|
|
||||||
|
|
||||||
Added commands:
|
|
||||||
- "/tbm-enable-all"
|
|
||||||
- "/tbm-disable-all"
|
|
||||||
|
|
||||||
Only OPs can use these new commands to enable or disable turn-based-battle for
|
|
||||||
everyone.
|
|
||||||
Note that if "/tbm-disable-all" is invoked, joining players will also have
|
|
||||||
turn-based-battle disabled for them. Invoking "/tbm-enable-all" will change this
|
|
||||||
back to the default, where turn-based-battle is enabled for joining players.
|
|
||||||
|
|
||||||
# Version 1.1
|
|
||||||
|
|
||||||
Added commands to enable/disable turn-based-battle on-demand.
|
|
||||||
|
|
||||||
Commands are:
|
|
||||||
- "/tbm-enable"
|
|
||||||
- "/tbm-disable"
|
|
||||||
- "/tbm-set \<player> \<true/false>"
|
|
||||||
|
|
||||||
There is a config option to allow anyone to use "/tbm-enable" and "/tbm-disable".
|
|
||||||
Only OPs can use "/tbm-set" (permission level 2).
|
|
||||||
|
|
||||||
Note that since config version has been updated, pre-existing config will be
|
|
||||||
renamed and the newer config will take its place.
|
|
||||||
|
|
||||||
# Version 1.0
|
|
||||||
|
|
||||||
Features:
|
|
||||||
- Turn based combat with hostile mobs (excluding passive and bosses) by default
|
|
||||||
- Config generated at ".minecraft/config/TurnBasedMinecraft/TBM_Config.xml
|
|
||||||
- Old config is renamed if new config exists with newer mod version
|
|
||||||
- Battle is very configurable per mob and also for all players in config
|
|
||||||
- Can add mobs unique to other mods in config (using full Java Class name of mob)
|
|
||||||
- Can set config on server/singleplayer to freeze mobs in combat
|
|
||||||
- Can add battle/silly music in ".minecraft/config/TurnBasedMinecraft/Music"
|
|
||||||
that activates depending on mob types in battle
|
|
||||||
- What determines battle or silly can be set client-side in config
|
|
||||||
- Unknown types defaults to battle music instead of silly music
|
|
||||||
- Can set max battle combatants in config
|
|
||||||
- Can use bow/arrows in battle (currently different projectile weapons provided
|
|
||||||
by different mods are not supported)
|
|
||||||
- Players in creative-mode will not enter turn-based battle
|
|
97
FAQ.md
|
@ -1,97 +0,0 @@
|
||||||
## How do I use this mod to have turn-based-battle with any mob (including mobs from other mods)?
|
|
||||||
|
|
||||||
To have turn-based-battle with a mob, it must have a config entry in the server
|
|
||||||
config. This can either be done manually or be [done in-game via a
|
|
||||||
command](https://www.youtube.com/watch?v=MK648OVHddE).
|
|
||||||
|
|
||||||
## Is it possible to have a mob's config applied to any mob with a specific name?
|
|
||||||
|
|
||||||
Yes, [this video explains this feature](https://www.youtube.com/watch?v=9lBETQFMd3A).
|
|
||||||
|
|
||||||
## Can the mod play music while a battle is happening?
|
|
||||||
|
|
||||||
Yes, you have to put the music (`.wav`, `.ogg`, or `.mp3`) in
|
|
||||||
`.minecraft/config/TurnBasedMinecraft/Music/battle` and
|
|
||||||
`.minecraft/config/TurnBasedMinecraft/Music/silly` . Note that `.wav`, `.ogg`,
|
|
||||||
and `.mp3` music files are supported, but `.mid` files are disabled due to lack
|
|
||||||
of volume control with the default Java library api. The config file can be
|
|
||||||
edited to change what categories of entities trigger what type of music, but
|
|
||||||
generally "passive" mobs trigger the "silly" music and everything else triggers
|
|
||||||
"battle" music. Note that the default server config has turn-based-battle
|
|
||||||
disabled for "passive" mobs.
|
|
||||||
|
|
||||||
**Note that while .ogg Vorbis files are supported, .ogg Opus files are NOT
|
|
||||||
supported.**
|
|
||||||
|
|
||||||
**It is recommended to use .ogg Vorbis files instead of .mp3 files.**
|
|
||||||
|
|
||||||
One can use FFmpeg to convert music files into .ogg Vorbis:
|
|
||||||
|
|
||||||
ffmpeg -i <music_file_to_convert> -map a:0 -c:a libvorbis output.ogg
|
|
||||||
|
|
||||||
## Why can't the mod play my mp3 files?
|
|
||||||
|
|
||||||
The third-party-library used to load mp3 files seems to have issues with
|
|
||||||
loading any mp3 file that isn't "barebones". Try removing the metadata of the
|
|
||||||
mp3 file. I've found that using mp3s without album art embedded in it seems to
|
|
||||||
work.
|
|
||||||
|
|
||||||
**It is recommended to use .ogg Vorbis files instead of .mp3 files.**
|
|
||||||
|
|
||||||
## How do I configure battle music?
|
|
||||||
|
|
||||||
There is a way to edit client-config that deals with music settings, like what
|
|
||||||
mob groups trigger battle/silly music and volume. This menu can be opened in two
|
|
||||||
ways.
|
|
||||||
|
|
||||||
- Run the command `/tbm-client-edit` to open the menu.
|
|
||||||
- Open the Mod list from the options screen, click on TBMM on the left column
|
|
||||||
and click on "Config". (Note that this way of opening the client-config-gui
|
|
||||||
is unavailable on Forge, and is only available on NeoForge.)
|
|
||||||
|
|
||||||
Note that "Accept" must be clicked on to save the client-config.
|
|
||||||
|
|
||||||
## Why do passive mobs don't start turn-based battle?
|
|
||||||
|
|
||||||
By default, the `passive` category is set to "ignore turn-based-battle" in the
|
|
||||||
server config. Use `/tbm-server-edit` to change this. (Click on
|
|
||||||
`ignore_battle_types` which should be dark-green. A list of "categories" will
|
|
||||||
appear at the bottom of the text. Click on `passive` to remove the "passive"
|
|
||||||
category.)
|
|
||||||
![Screenshot one of two showing how to unset passive category from ignore battle types list](https://seodisparate.com/static/uploads/TBMM_ignore_battle_types_screenshot0.png)
|
|
||||||
![Screenshot two of two showing how to unset passive category from ignore battle types list](https://seodisparate.com/static/uploads/TBMM_ignore_battle_types_screenshot1.png)
|
|
||||||
|
|
||||||
Alternatively, edit the [server config](https://github.com/Stephen-Seo/TurnBasedMinecraftMod/blob/ad78063a16c768f660dd086cba857a3be43a84b2/src/main/resources/assets/com_burnedkirby_turnbasedminecraft/TBM_Config.toml#L46)
|
|
||||||
and remove "passive" from the ignore\_battle\_types list.
|
|
||||||
|
|
||||||
## Why is the mod's config file missing?
|
|
||||||
|
|
||||||
The mod needs to be run once to generate the default config file and
|
|
||||||
directories for battle music. After running it once, you can now close
|
|
||||||
Minecraft and edit the config found at
|
|
||||||
`.minecraft/config/TurnBasedMinecraft/TBM_Config.toml` Note that some options
|
|
||||||
only apply to the server and some only to the client, as specified in the
|
|
||||||
config. This means that server config must be changed on the server side for it
|
|
||||||
to take effect (local singleplayer will use all of the local config, but
|
|
||||||
multiplayer setups will require the server config to be changed on the server
|
|
||||||
side). [You can edit the server-side config in game via the "/tbm-server-edit"
|
|
||||||
command](https://youtu.be/9xkbHNWkcIY).
|
|
||||||
|
|
||||||
## I updated the mod, but now my config changes are back to default, what happened?
|
|
||||||
|
|
||||||
*As of Version 1.26.5 and onwards, this should happen less often!*
|
|
||||||
Version 1.26.5 introduces more robust config updating such that entries that
|
|
||||||
exist in the default config, but not in the current config will be appended to
|
|
||||||
the current config.
|
|
||||||
|
|
||||||
Sometimes, I add new mob entries to the config, and increment the version
|
|
||||||
number of the config. When the server/client starts, it checks the default
|
|
||||||
config's version number with the existing config's version number. If the
|
|
||||||
existing config is determined to be outdated, then it is renamed to a different
|
|
||||||
name (which usually includes the date/time of when it was renamed), and the new
|
|
||||||
default config is placed in its place. There is a config option to prevent this
|
|
||||||
from happening, but it is strongly recommended to not disable this since this
|
|
||||||
will cause updates to the config to never be placed in the mod's config
|
|
||||||
directory. If you have changes you want to keep, but the mod renamed the
|
|
||||||
original config, you will have to edit the `TBM_Config.toml` to have the
|
|
||||||
changes you want from the renamed older config file.
|
|
21
LICENSE
|
@ -1,21 +0,0 @@
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2018-2024 Stephen Seo
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
107
README.md
|
@ -1,107 +0,0 @@
|
||||||
# TurnBasedMinecraftMod
|
|
||||||
|
|
||||||
This mod puts turn-based-combat of RPGs into Minecraft!
|
|
||||||
|
|
||||||
# Links/Downloads
|
|
||||||
|
|
||||||
Precompiled jars are available here:
|
|
||||||
https://seodisparate.com/static/tbm_releases/
|
|
||||||
https://burnedkirby.com/tbmm_downloads/
|
|
||||||
https://www.curseforge.com/minecraft/mc-mods/turnbasedminecraft/files
|
|
||||||
https://modrinth.com/mod/turnbasedmc
|
|
||||||
https://git.seodisparate.com/stephenseo/TurnBasedMinecraftMod/releases
|
|
||||||
|
|
||||||
# Documentation Page
|
|
||||||
|
|
||||||
https://stephen-seo.github.io/TurnBasedMinecraftMod/
|
|
||||||
|
|
||||||
# Forge or NeoForge
|
|
||||||
|
|
||||||
The `forge` branch tracks the version of the mod for Minecraft Forge.
|
|
||||||
|
|
||||||
The `neoforge` branch tracks the version of the mod for Minecraft NeoForge.
|
|
||||||
|
|
||||||
# What changed in what version
|
|
||||||
|
|
||||||
See the [Changelog](https://github.com/Stephen-Seo/TurnBasedMinecraftMod/blob/neoforge/Changelog.md)
|
|
||||||
|
|
||||||
# Things you may need to know about this mod
|
|
||||||
|
|
||||||
On first run, this mod will create a config file and some directories in your
|
|
||||||
Minecraft directory. They will typically be located at
|
|
||||||
`.minecraft/config/TurnBasedMinecraft`. (for the server they will be in the
|
|
||||||
`config` directory in the server directory.)
|
|
||||||
|
|
||||||
The config file `.minecraft/config/TurnBasedMinecraft/TBM_Config.toml` is commented
|
|
||||||
with info on what each option does. ~~It will also be moved if a newer version
|
|
||||||
of this mod has a newer version of the config file (usually renamed with a
|
|
||||||
timestamp).~~ ~~I will try my best to not move the previous version config, but rather
|
|
||||||
edit the previous version config to have new options.~~ ~~When a new config version is made,
|
|
||||||
usually because a new entry has been added, the existing config is renamed to a file with
|
|
||||||
a timestamp in the filename of when it was replaced. One can set a config option in the
|
|
||||||
config to prevent it being overwritten if necessary.~~
|
|
||||||
|
|
||||||
*As of version 1.26.5 of this mod, this should happen less frequently!*
|
|
||||||
Version 1.26.5 introduces changes that allow entries that exist in the default
|
|
||||||
config but not in the current config to be appended in the current config.
|
|
||||||
|
|
||||||
Some options in the config file only affect the Server, and ~~some only affect the Client~~.
|
|
||||||
Client config has been moved to a
|
|
||||||
[separate system provided by NeoForge](https://github.com/Stephen-Seo/TurnBasedMinecraftMod/blob/neoforge/FAQ.md#how-do-i-configure-battle-music).
|
|
||||||
When playing multiplayer, some configuration of the config on the server may be needed.
|
|
||||||
|
|
||||||
# Features
|
|
||||||
|
|
||||||
- Combat between players and mobs or other players will invoke a turn based battle
|
|
||||||
between them
|
|
||||||
- Supports use of the vanilla Minecraft bow and arrows (have bow selected when
|
|
||||||
in battle)
|
|
||||||
- Supports custom battle music to be played when fighting enemies. (They must
|
|
||||||
be placed in `.minecraft/config/TurnBasedMinecraft/Music/battle` or
|
|
||||||
`.minecraft/config/TurnBasedMinecraft/Music/silly`. Client-side config
|
|
||||||
determines which song plays in battle for the client. only `.wav`,
|
|
||||||
~~`.mid`~~, `.mp3`, and `.ogg` files supported. ~~Only `.mid` files are not
|
|
||||||
affected by volume options (master and music sliders))~~ Midi file playback
|
|
||||||
has been disabled for now due to lack of volume control issues. MP3 file
|
|
||||||
playback sometimes fails, but seems to work better when the file is as
|
|
||||||
"barebones" as possible (no album art metadata in the file).
|
|
||||||
- It is recommended to use `.ogg` files for music.
|
|
||||||
- Note that ogg Vorbis is supported, and NOT ogg Opus.
|
|
||||||
- One can convert to ogg Vorbis with ffmpeg like this: `ffmpeg -i
|
|
||||||
<my_music_file_to_convert> -map a:0 -c:a libvorbis output.ogg`.
|
|
||||||
- Config allows limiting number of combatants in turn-based battle.
|
|
||||||
- Config can be modified (server-side) to add entries of mobs from other mods.
|
|
||||||
(by default an unknown mob cannot enter turn-based battle, so the config must be
|
|
||||||
configured for them.)
|
|
||||||
- [Alternatively, the command "/tbm-edit" can be used in-game to add/edit
|
|
||||||
entities for the mod.](https://www.youtube.com/watch?v=MK648OVHddE)
|
|
||||||
- [Also, one can make entries for specific custom names](https://youtu.be/9lBETQFMd3A)
|
|
||||||
- [Server-side config can be edited in-game with the "/tbm-server-edit" command](https://youtu.be/9xkbHNWkcIY)
|
|
||||||
|
|
||||||
# Building
|
|
||||||
|
|
||||||
Simply invoke `./gradlew build` in the mod directory and after some time the
|
|
||||||
finished jar will be saved at
|
|
||||||
`build/libs/TurnBasedMinecraft-NeoForge-1.26.5-all.jar`
|
|
||||||
|
|
||||||
# Reproducibility
|
|
||||||
|
|
||||||
This mod should support reproducible builds. See `Reproducibility.md` to see
|
|
||||||
more details.
|
|
||||||
|
|
||||||
# Other notes
|
|
||||||
|
|
||||||
This mod uses [j-ogg-vorbis](https://github.com/stephengold/j-ogg-all)
|
|
||||||
available from [http://www.j-ogg.de](http://www.j-ogg.de) and copyrighted by
|
|
||||||
Tor-Einar Jarnbjo.
|
|
||||||
|
|
||||||
This mod also uses [JavaMP3](https://github.com/kevinstadler/JavaMP3)
|
|
||||||
which is licensed under the [MIT License](https://github.com/kevinstadler/JavaMP3/blob/master/LICENSE).
|
|
||||||
|
|
||||||
# Frequently Asked Questions
|
|
||||||
|
|
||||||
[See the FAQ page.](https://github.com/Stephen-Seo/TurnBasedMinecraftMod/blob/neoforge/FAQ.md)
|
|
||||||
|
|
||||||
# Related Videos
|
|
||||||
|
|
||||||
[See related videos here](https://burnedkirby.com/posts/tbmm/)
|
|
|
@ -1,304 +0,0 @@
|
||||||
# Reproducibility
|
|
||||||
|
|
||||||
Starting with version 1.24.0 of this mod, this file will list what version of
|
|
||||||
Java was used to compile the jars. In theory, using the same version of Java
|
|
||||||
should result in an identical jar due to reproducible builds.
|
|
||||||
|
|
||||||
## NeoForge 1.26.5
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.5 2024-10-15
|
|
||||||
OpenJDK Runtime Environment (build 21.0.5+11)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.5+11, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.5
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-NeoForge-1.26.5-all.jar
|
|
||||||
b02d0abf6f2fbc5c3b718b548309efacb159ec8f86c7d2d653fc0b73234e761a build/libs/TurnBasedMinecraft-NeoForge-1.26.5-all.jar
|
|
||||||
|
|
||||||
## NeoForge 1.26.5-MC-1.21.1
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.5 2024-10-15
|
|
||||||
OpenJDK Runtime Environment (build 21.0.5+11)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.5+11, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.5
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-NeoForge-1.26.5-MC-1.21.1-all.jar
|
|
||||||
c529ebe3dd48608afd27e3393b201036ce84d3be0a850cdf48039fbc4820629e build/libs/TurnBasedMinecraft-NeoForge-1.26.5-MC-1.21.1-all.jar
|
|
||||||
|
|
||||||
## Forge 1.26.5
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.5 2024-10-15
|
|
||||||
OpenJDK Runtime Environment (build 21.0.5+11)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.5+11, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.5
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-Forge-1.26.5-all.jar
|
|
||||||
c8ed6e2e9a433c40901d41ec604bc6260fc5b231f5d3859832ecbe76b0f5a9e2 build/libs/TurnBasedMinecraft-Forge-1.26.5-all.jar
|
|
||||||
|
|
||||||
## NeoForge 1.26.4
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.5 2024-10-15
|
|
||||||
OpenJDK Runtime Environment (build 21.0.5+11)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.5+11, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.5
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-NeoForge-1.26.4-all.jar
|
|
||||||
ddab3e58638ba70c7b10f84f4aa7ac81e8e5a63cb47d0ebf7e7aa4bcf3c0a1ba build/libs/TurnBasedMinecraft-NeoForge-1.26.4-all.jar
|
|
||||||
|
|
||||||
## NeoForge 1.26.4-MC-1.21.1
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.5 2024-10-15
|
|
||||||
OpenJDK Runtime Environment (build 21.0.5+11)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.5+11, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.5
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-NeoForge-1.26.4-MC-1.21.1-all.jar
|
|
||||||
e49665c67452cae8fab8f356d187b860893885afbe6dab1e3a869331a12f1cf5 build/libs/TurnBasedMinecraft-NeoForge-1.26.4-MC-1.21.1-all.jar
|
|
||||||
|
|
||||||
## Forge 1.26.4
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.5 2024-10-15
|
|
||||||
OpenJDK Runtime Environment (build 21.0.5+11)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.5+11, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.5
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-Forge-1.26.4-all.jar
|
|
||||||
2052b1e8f6a49374b6a9bbc0c0547c1972d5454ea9afa5f0455c534285d6cada build/libs/TurnBasedMinecraft-Forge-1.26.4-all.jar
|
|
||||||
|
|
||||||
## NeoForge 1.26.3
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.5 2024-10-15
|
|
||||||
OpenJDK Runtime Environment (build 21.0.5+11)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.5+11, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.5
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-NeoForge-1.26.3-all.jar
|
|
||||||
2c8f17499a475f22493244e16f499bed46ea6a32a20f6bd2be5b3151464b2225 build/libs/TurnBasedMinecraft-NeoForge-1.26.3-all.jar
|
|
||||||
|
|
||||||
## NeoForge 1.26.3-MC-1.21.1
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.5 2024-10-15
|
|
||||||
OpenJDK Runtime Environment (build 21.0.5+11)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.5+11, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.5
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-NeoForge-1.26.3-MC-1.21.1-all.jar
|
|
||||||
311018353109da4d9a49379d9ebc29dbac7e2aef3331ec177bd0edc300d15b89 /home/public/TurnBasedMC/TurnBasedMinecraft-NeoForge-1.26.3-MC-1.21.1-all.jar
|
|
||||||
|
|
||||||
## Forge 1.26.3
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.5 2024-10-15
|
|
||||||
OpenJDK Runtime Environment (build 21.0.5+11)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.5+11, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.5
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-Forge-1.26.3-all.jar
|
|
||||||
5fdaffd14f75c2340a410c37811a5f7644ade3c6852db4b982bf3161bab1aae7 build/libs/TurnBasedMinecraft-Forge-1.26.3-all.jar
|
|
||||||
|
|
||||||
## NeoForge 1.26.2
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.5 2024-10-15
|
|
||||||
OpenJDK Runtime Environment (build 21.0.5+11)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.5+11, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.5
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-NeoForge-1.26.2-all.jar
|
|
||||||
d55f516a2166d266c0d60e881b170cb734372ac01c8a25cf12e2f593f7b87004 build/libs/TurnBasedMinecraft-NeoForge-1.26.2-all.jar
|
|
||||||
|
|
||||||
## Forge 1.26.2
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.5 2024-10-15
|
|
||||||
OpenJDK Runtime Environment (build 21.0.5+11)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.5+11, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.5
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-Forge-1.26.2-all.jar
|
|
||||||
d06f3cc8e050aa4086dce187ffce2cc5049c67c401a0cd4608138880b0868e89 build/libs/TurnBasedMinecraft-Forge-1.26.2-all.jar
|
|
||||||
|
|
||||||
## Forge 1.26.1
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.5 2024-10-15
|
|
||||||
OpenJDK Runtime Environment (build 21.0.5+11)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.5+11, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.5
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-Forge-1.26.1-all.jar
|
|
||||||
0fc0f1ea49c726b06b7a353fee4e59eaadd608a4074245477d1ccd957467305c build/libs/TurnBasedMinecraft-Forge-1.26.1-all.jar
|
|
||||||
|
|
||||||
## NeoForge 1.26.1
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.5 2024-10-15
|
|
||||||
OpenJDK Runtime Environment (build 21.0.5+11)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.5+11, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.5
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-NeoForge-1.26.1-all.jar
|
|
||||||
ac3005191d9c23ad823e4ae33b750a0ac17518460fedc91242d031a8f1365101 build/libs/TurnBasedMinecraft-NeoForge-1.26.1-all.jar
|
|
||||||
|
|
||||||
## Forge 1.26.0
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.4 2024-07-16
|
|
||||||
OpenJDK Runtime Environment (build 21.0.4+7)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.4+7, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.4
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-Forge-1.26.0-all.jar
|
|
||||||
9a3bb24fef9348e620ab5bcc120d83e11c5289a046561fb4ef91d0ccade9b271 build/libs/TurnBasedMinecraft-Forge-1.26.0-all.jar
|
|
||||||
|
|
||||||
## NeoForge 1.26.0
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 21.0.4 2024-07-16
|
|
||||||
OpenJDK Runtime Environment (build 21.0.4+7)
|
|
||||||
OpenJDK 64-Bit Server VM (build 21.0.4+7, mixed mode, sharing)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 21.0.4
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-NeoForge-1.26.0-all.jar
|
|
||||||
a13e93df640eb3ce5577521421e760aa5d808d34d5cef9c5415ae7a699173ea9 build/libs/TurnBasedMinecraft-NeoForge-1.26.0-all.jar
|
|
||||||
|
|
||||||
## NeoForge 1.25.2
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 17.0.10 2024-01-16
|
|
||||||
OpenJDK Runtime Environment (build 17.0.10+7)
|
|
||||||
OpenJDK 64-Bit Server VM (build 17.0.10+7, mixed mode)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 17.0.10
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-NeoForge-1.25.2-all.jar
|
|
||||||
c59533059eb322a616f38ab40ccbc7d4d6c1667a651328a4c6eb187fe16d7a6f build/libs/TurnBasedMinecraft-NeoForge-1.25.2-all.jar
|
|
||||||
|
|
||||||
## Forge 1.25.2
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 17.0.10 2024-01-16
|
|
||||||
OpenJDK Runtime Environment (build 17.0.10+7)
|
|
||||||
OpenJDK 64-Bit Server VM (build 17.0.10+7, mixed mode)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 17.0.10
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-Forge-1.25.2-all.jar
|
|
||||||
00bc7958431e161b0a512ce32b41c1a97516b00e109195294ee18d4abf58dc26 build/libs/TurnBasedMinecraft-Forge-1.25.2-all.jar
|
|
||||||
|
|
||||||
## Forge 1.25.1
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 17.0.9 2023-10-17
|
|
||||||
OpenJDK Runtime Environment (build 17.0.9+8)
|
|
||||||
OpenJDK 64-Bit Server VM (build 17.0.9+8, mixed mode)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 17.0.9
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-Forge-1.25.1-all.jar
|
|
||||||
33711947eed8b24fa7fd65d36ecdb6ed78e144af8d7fff6e1bfa304cfe4a1d3d build/libs/TurnBasedMinecraft-Forge-1.25.1-all.jar
|
|
||||||
|
|
||||||
## NeoForge 1.25.1
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 17.0.9 2023-10-17
|
|
||||||
OpenJDK Runtime Environment (build 17.0.9+8)
|
|
||||||
OpenJDK 64-Bit Server VM (build 17.0.9+8, mixed mode)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 17.0.9
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-NeoForge-1.25.1-all.jar
|
|
||||||
b0ec086c356c4d3662dcea4bdd9aeb2b0786e4ef40e061599e81b529746e01ea build/libs/TurnBasedMinecraft-NeoForge-1.25.1-all.jar
|
|
||||||
|
|
||||||
## NeoForge 1.25.0
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 17.0.9 2023-10-17
|
|
||||||
OpenJDK Runtime Environment (build 17.0.9+8)
|
|
||||||
OpenJDK 64-Bit Server VM (build 17.0.9+8, mixed mode)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 17.0.9
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-NeoForge-1.25.0-all.jar
|
|
||||||
0e5eacc8aefd3b1a1c8e6c9657108172934fae2e727547ca7c12f9ff79ce4e8e build/libs/TurnBasedMinecraft-NeoForge-1.25.0-all.jar
|
|
||||||
|
|
||||||
## Forge 1.25.0
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 17.0.9 2023-10-17
|
|
||||||
OpenJDK Runtime Environment (build 17.0.9+8)
|
|
||||||
OpenJDK 64-Bit Server VM (build 17.0.9+8, mixed mode)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 17.0.9
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-Forge-1.25.0-all.jar
|
|
||||||
51ef854552b180df68969f4cec6fdc8716ef519b947948b9e5f4ce9953d00162 build/libs/TurnBasedMinecraft-Forge-1.25.0-all.jar
|
|
||||||
|
|
||||||
## NeoForge 1.24.0
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 17.0.9 2023-10-17
|
|
||||||
OpenJDK Runtime Environment (build 17.0.9+8)
|
|
||||||
OpenJDK 64-Bit Server VM (build 17.0.9+8, mixed mode)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 17.0.9
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-NeoForge-1.24.0-all.jar
|
|
||||||
584935b6e928ad141a55e4d1a21944cebff5152396782085d145bbe34c29286c build/libs/TurnBasedMinecraft-NeoForge-1.24.0-all.jar
|
|
||||||
|
|
||||||
## Forge 1.24.0
|
|
||||||
|
|
||||||
$ java --version
|
|
||||||
openjdk 17.0.9 2023-10-17
|
|
||||||
OpenJDK Runtime Environment (build 17.0.9+8)
|
|
||||||
OpenJDK 64-Bit Server VM (build 17.0.9+8, mixed mode)
|
|
||||||
|
|
||||||
$ javac --version
|
|
||||||
javac 17.0.9
|
|
||||||
|
|
||||||
$ sha256sum build/libs/TurnBasedMinecraft-Forge-1.24.0.jar
|
|
||||||
e17c370cdf347b053c7f55091afed77564dcd8f419615bd6ca87babe10329c07 build/libs/TurnBasedMinecraft-Forge-1.24.0.jar
|
|
225
build.gradle
|
@ -1,225 +0,0 @@
|
||||||
plugins {
|
|
||||||
id 'java-library'
|
|
||||||
id 'maven-publish'
|
|
||||||
id 'net.neoforged.moddev' version '1.0.21'
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named('wrapper', Wrapper).configure {
|
|
||||||
// Define wrapper values here so as to not have to always do so when updating gradlew.properties.
|
|
||||||
// Switching this to Wrapper.DistributionType.ALL will download the full gradle sources that comes with
|
|
||||||
// documentation attached on cursor hover of gradle classes and methods. However, this comes with increased
|
|
||||||
// file size for Gradle. If you do switch this to ALL, run the Gradle wrapper task twice afterwards.
|
|
||||||
// (Verify by checking gradle/wrapper/gradle-wrapper.properties to see if distributionUrl now points to `-all`)
|
|
||||||
distributionType = Wrapper.DistributionType.BIN
|
|
||||||
}
|
|
||||||
|
|
||||||
version = mod_version
|
|
||||||
group = mod_group_id
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenLocal()
|
|
||||||
|
|
||||||
flatDir {
|
|
||||||
dir 'libs'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
base {
|
|
||||||
archivesName = "TurnBasedMinecraft-NeoForge"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mojang ships Java 21 to end users starting in 1.20.5, so mods should target Java 21.
|
|
||||||
java.toolchain.languageVersion = JavaLanguageVersion.of(21)
|
|
||||||
println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
|
|
||||||
|
|
||||||
neoForge {
|
|
||||||
// Specify the version of NeoForge to use.
|
|
||||||
version = project.neo_version
|
|
||||||
|
|
||||||
parchment {
|
|
||||||
mappingsVersion = project.parchment_mappings_version
|
|
||||||
minecraftVersion = project.parchment_minecraft_version
|
|
||||||
}
|
|
||||||
|
|
||||||
// This line is optional. Access Transformers are automatically detected
|
|
||||||
// accessTransformers = project.files('src/main/resources/META-INF/accesstransformer.cfg')
|
|
||||||
|
|
||||||
// Default run configurations.
|
|
||||||
// These can be tweaked, removed, or duplicated as needed.
|
|
||||||
runs {
|
|
||||||
client {
|
|
||||||
client()
|
|
||||||
|
|
||||||
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
|
|
||||||
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
server()
|
|
||||||
programArgument '--nogui'
|
|
||||||
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
|
|
||||||
}
|
|
||||||
|
|
||||||
// This run config launches GameTestServer and runs all registered gametests, then exits.
|
|
||||||
// By default, the server will crash when no gametests are provided.
|
|
||||||
// The gametest system is also enabled by default for other run configs under the /test command.
|
|
||||||
gameTestServer {
|
|
||||||
type = "gameTestServer"
|
|
||||||
systemProperty 'neoforge.enabledGameTestNamespaces', project.mod_id
|
|
||||||
}
|
|
||||||
|
|
||||||
data {
|
|
||||||
data()
|
|
||||||
|
|
||||||
// example of overriding the workingDirectory set in configureEach above, uncomment if you want to use it
|
|
||||||
// gameDirectory = project.file('run-data')
|
|
||||||
|
|
||||||
// Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
|
|
||||||
programArguments.addAll '--mod', project.mod_id, '--all', '--output', file('src/generated/resources/').getAbsolutePath(), '--existing', file('src/main/resources/').getAbsolutePath()
|
|
||||||
}
|
|
||||||
|
|
||||||
// applies to all the run configs above
|
|
||||||
configureEach {
|
|
||||||
// Recommended logging data for a userdev environment
|
|
||||||
// The markers can be added/remove as needed separated by commas.
|
|
||||||
// "SCAN": For mods scan.
|
|
||||||
// "REGISTRIES": For firing of registry events.
|
|
||||||
// "REGISTRYDUMP": For getting the contents of all registries.
|
|
||||||
systemProperty 'forge.logging.markers', 'REGISTRIES'
|
|
||||||
|
|
||||||
// Recommended logging level for the console
|
|
||||||
// You can set various levels here.
|
|
||||||
// Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
|
|
||||||
logLevel = org.slf4j.event.Level.DEBUG
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mods {
|
|
||||||
// define mod <-> source bindings
|
|
||||||
// these are used to tell the game which sources are for which mod
|
|
||||||
// mostly optional in a single mod project
|
|
||||||
// but multi mod projects should define one per mod
|
|
||||||
"${mod_id}" {
|
|
||||||
sourceSet(sourceSets.main)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Include resources generated by data generators.
|
|
||||||
sourceSets.main.resources { srcDir 'src/generated/resources' }
|
|
||||||
|
|
||||||
// Sets up a dependency configuration called 'localRuntime'.
|
|
||||||
// This configuration should be used instead of 'runtimeOnly' to declare
|
|
||||||
// a dependency that will be present for runtime testing but that is
|
|
||||||
// "optional", meaning it will not be pulled by dependents of this mod.
|
|
||||||
configurations {
|
|
||||||
runtimeClasspath.extendsFrom localRuntime
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
// Example optional mod dependency with JEI
|
|
||||||
// The JEI API is declared for compile time use, while the full JEI artifact is used at runtime
|
|
||||||
// compileOnly "mezz.jei:jei-${mc_version}-common-api:${jei_version}"
|
|
||||||
// compileOnly "mezz.jei:jei-${mc_version}-neoforge-api:${jei_version}"
|
|
||||||
// We add the full version to localRuntime, not runtimeOnly, so that we do not publish a dependency on it
|
|
||||||
// localRuntime "mezz.jei:jei-${mc_version}-neoforge:${jei_version}"
|
|
||||||
|
|
||||||
// Example mod dependency using a mod jar from ./libs with a flat dir repository
|
|
||||||
// This maps to ./libs/coolmod-${mc_version}-${coolmod_version}.jar
|
|
||||||
// The group id is ignored when searching -- in this case, it is "blank"
|
|
||||||
// implementation "blank:coolmod-${mc_version}:${coolmod_version}"
|
|
||||||
|
|
||||||
// Example mod dependency using a file as dependency
|
|
||||||
// implementation files("libs/coolmod-${mc_version}-${coolmod_version}.jar")
|
|
||||||
|
|
||||||
// Example project dependency using a sister or child project:
|
|
||||||
// implementation project(":myproject")
|
|
||||||
|
|
||||||
// For more info:
|
|
||||||
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
|
|
||||||
// http://www.gradle.org/docs/current/userguide/dependency_management.html
|
|
||||||
|
|
||||||
|
|
||||||
// implementation "net.neoforged:neoforge:${neo_version}"
|
|
||||||
|
|
||||||
// implementation files('libs/javamp3-1.0.3.jar')
|
|
||||||
implementation 'fr.delthas:javamp3:1.0.3'
|
|
||||||
|
|
||||||
implementation 'com.github.stephengold:j-ogg-vorbis:1.0.4'
|
|
||||||
|
|
||||||
jarJar(implementation("fr.delthas:javamp3")) {
|
|
||||||
version {
|
|
||||||
strictly '[1.0.0,2.0.0)'
|
|
||||||
prefer '1.0.3'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jarJar(implementation("com.github.stephengold:j-ogg-vorbis")) {
|
|
||||||
version {
|
|
||||||
strictly '[1.0.4,2.0.0)'
|
|
||||||
prefer '1.0.4'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This block of code expands all declared replace properties in the specified resource targets.
|
|
||||||
// A missing property will result in an error. Properties are expanded using ${} Groovy notation.
|
|
||||||
var generateModMetadata = tasks.register("generateModMetadata", ProcessResources) {
|
|
||||||
var replaceProperties = [
|
|
||||||
minecraft_version : minecraft_version,
|
|
||||||
minecraft_version_range: minecraft_version_range,
|
|
||||||
neo_version : neo_version,
|
|
||||||
neo_version_range : neo_version_range,
|
|
||||||
loader_version_range : loader_version_range,
|
|
||||||
mod_id : mod_id,
|
|
||||||
mod_name : mod_name,
|
|
||||||
mod_license : mod_license,
|
|
||||||
mod_version : mod_version,
|
|
||||||
mod_authors : mod_authors,
|
|
||||||
mod_description : mod_description
|
|
||||||
]
|
|
||||||
inputs.properties replaceProperties
|
|
||||||
expand replaceProperties
|
|
||||||
from "src/main/templates"
|
|
||||||
into "build/generated/sources/modMetadata"
|
|
||||||
}
|
|
||||||
// Include the output of "generateModMetadata" as an input directory for the build
|
|
||||||
// this works with both building through Gradle and the IDE.
|
|
||||||
sourceSets.main.resources.srcDir generateModMetadata
|
|
||||||
// To avoid having to run "generateModMetadata" manually, make it run on every project reload
|
|
||||||
neoForge.ideSyncTask generateModMetadata
|
|
||||||
|
|
||||||
// Example for how to get properties into the manifest for reading by the runtime..
|
|
||||||
jar {
|
|
||||||
archiveClassifier = 'all'
|
|
||||||
manifest {
|
|
||||||
attributes([
|
|
||||||
"Specification-Title": "TurnBasedMinecraftMod",
|
|
||||||
"Specification-Vendor": "TurnBasedMinecraftMod_BK",
|
|
||||||
"Specification-Version": "1", // We are version 1 of ourselves
|
|
||||||
"Implementation-Title": "TurnBasedMinecraftMod",
|
|
||||||
"Implementation-Version": "${version}",
|
|
||||||
"Implementation-Vendor" :"TurnBasedMinecraftMod_BK",
|
|
||||||
// Do not place timestamp for the sake of reproducible builds
|
|
||||||
// "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
|
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reproducible Builds
|
|
||||||
tasks.withType(AbstractArchiveTask).configureEach {
|
|
||||||
preserveFileTimestamps = false
|
|
||||||
reproducibleFileOrder = true
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile).configureEach {
|
|
||||||
options.encoding = 'UTF-8' // Use the UTF-8 charset for Java compilation
|
|
||||||
}
|
|
||||||
|
|
||||||
// IDEA no longer automatically downloads sources/javadoc jars for dependencies, so we need to explicitly enable the behavior.
|
|
||||||
idea {
|
|
||||||
module {
|
|
||||||
downloadSources = true
|
|
||||||
downloadJavadoc = true
|
|
||||||
}
|
|
||||||
}
|
|
213
client_config/index.html
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" data-bs-theme="dark">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="../img/favicon.ico">
|
||||||
|
<title>Client-side Config - Documentation for TurnBasedMinecraftMod</title>
|
||||||
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="../css/fontawesome.min.css" rel="stylesheet">
|
||||||
|
<link href="../css/brands.min.css" rel="stylesheet">
|
||||||
|
<link href="../css/solid.min.css" rel="stylesheet">
|
||||||
|
<link href="../css/v4-font-face.min.css" rel="stylesheet">
|
||||||
|
<link href="../css/base.css" rel="stylesheet">
|
||||||
|
<link id="hljs-light" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css" disabled>
|
||||||
|
<link id="hljs-dark" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github-dark.min.css" >
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
|
||||||
|
<script>hljs.highlightAll();</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand" href="..">Documentation for TurnBasedMinecraftMod</a>
|
||||||
|
<!-- Expander button -->
|
||||||
|
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#navbar-collapse" aria-controls="navbar-collapse" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Expanded navigation -->
|
||||||
|
<div id="navbar-collapse" class="navbar-collapse collapse">
|
||||||
|
<!-- Main navigation -->
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href=".." class="nav-link">TurnBasedMinecraftMod</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="./" class="nav-link active" aria-current="page">Client-side Config</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="../server_config/" class="nav-link">Server-side Config</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="nav navbar-nav ms-md-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="#" class="nav-link" data-bs-toggle="modal" data-bs-target="#mkdocs_search_modal">
|
||||||
|
<i class="fa fa-search"></i> Search
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a rel="prev" href=".." class="nav-link">
|
||||||
|
<i class="fa fa-arrow-left"></i> Previous
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a rel="next" href="../server_config/" class="nav-link">
|
||||||
|
Next <i class="fa fa-arrow-right"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<button id="theme-menu" aria-expanded="false" data-bs-toggle="dropdown" data-bs-display="static" aria-label="Toggle theme" class="nav-link dropdown-toggle">
|
||||||
|
<i class="fa-solid fa-circle-half-stroke fa-fw"></i>
|
||||||
|
<span class="d-lg-none ms-2">Toggle theme</span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="light" aria-pressed="false">
|
||||||
|
<i class="fa-solid fa-sun fa-fw"></i>
|
||||||
|
<span class="ms-2">Light</span>
|
||||||
|
<i class="fa-solid fa-check ms-auto d-none"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="dark" aria-pressed="true">
|
||||||
|
<i class="fa-solid fa-moon fa-fw"></i>
|
||||||
|
<span class="ms-2">Dark</span>
|
||||||
|
<i class="fa-solid fa-check ms-auto"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="auto" aria-pressed="false">
|
||||||
|
<i class="fa-solid fa-circle-half-stroke fa-fw"></i>
|
||||||
|
<span class="ms-2">Auto</span>
|
||||||
|
<i class="fa-solid fa-check ms-auto d-none"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="../js/darkmode.js"></script>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3"><div class="navbar-expand-md bs-sidebar hidden-print affix" role="complementary">
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggler collapsed" data-bs-toggle="collapse" data-bs-target="#toc-collapse" title="Table of Contents">
|
||||||
|
<span class="fa fa-angle-down"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="toc-collapse" class="navbar-collapse collapse card bg-body-tertiary">
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
|
||||||
|
<li class="nav-item" data-bs-level="1"><a href="#client-side-config" class="nav-link">Client-side Config</a>
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
<div class="col-md-9" role="main">
|
||||||
|
|
||||||
|
<h1 id="client-side-config">Client-side Config</h1>
|
||||||
|
<p>The client config can be opened in two ways.</p>
|
||||||
|
<p>One way is via the mod-list (only works in NeoForge, not Forge).</p>
|
||||||
|
<p><img alt="Mod list config button" src="../tbm-client-edit-modlist.jpg" /></p>
|
||||||
|
<p>The other way is via the <code>/tbm-client-edit</code> command.</p>
|
||||||
|
<p><img alt="tbm-client-edit command" src="../tbm-client-edit-cmd.png" /></p>
|
||||||
|
<p>Currently, the client config allows for configuration for client-side music
|
||||||
|
playback.</p>
|
||||||
|
<p><img alt="client config" src="../tbm-client-edit-config.jpg" /></p>
|
||||||
|
<p>The "categories" settings are comma-separated words that define what "category"
|
||||||
|
triggers the "battle" music or the "silly" music.</p>
|
||||||
|
<p>"Silly Music Threshold" determines the percentage of silly-category-mobs in
|
||||||
|
battle required to play silly music. This means if the setting is 49%, and there
|
||||||
|
is one player, one zomibe, and two sheep in battle, then the game will play
|
||||||
|
silly music (since 50% of the combatants are sheep and is greater than 49%).</p></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="col-md-12">
|
||||||
|
<hr>
|
||||||
|
<p>Documentation built with <a href="https://www.mkdocs.org/">MkDocs</a>.</p>
|
||||||
|
</footer>
|
||||||
|
<script src="../js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script>
|
||||||
|
var base_url = "..",
|
||||||
|
shortcuts = {"help": 191, "next": 78, "previous": 80, "search": 83};
|
||||||
|
</script>
|
||||||
|
<script src="../js/base.js"></script>
|
||||||
|
<script src="../search/main.js"></script>
|
||||||
|
|
||||||
|
<div class="modal" id="mkdocs_search_modal" tabindex="-1" role="dialog" aria-labelledby="searchModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="searchModalLabel">Search</h4>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>From here you can search these documents. Enter your search terms below.</p>
|
||||||
|
<form>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="search" class="form-control" placeholder="Search..." id="mkdocs-search-query" title="Type search term here">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div id="mkdocs-search-results" data-no-results-text="No results found"></div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><div class="modal" id="mkdocs_keyboard_modal" tabindex="-1" role="dialog" aria-labelledby="keyboardModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="keyboardModalLabel">Keyboard Shortcuts</h4>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width: 20%;">Keys</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="help shortcut"><kbd>?</kbd></td>
|
||||||
|
<td>Open this help</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="next shortcut"><kbd>n</kbd></td>
|
||||||
|
<td>Next page</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="prev shortcut"><kbd>p</kbd></td>
|
||||||
|
<td>Previous page</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="search shortcut"><kbd>s</kbd></td>
|
||||||
|
<td>Search</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
366
css/base.css
Normal file
|
@ -0,0 +1,366 @@
|
||||||
|
html {
|
||||||
|
/* The nav header is 3.5rem high, plus 20px for the margin-top of the
|
||||||
|
main container. */
|
||||||
|
scroll-padding-top: calc(3.5rem + 20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Replacement for `body { background-attachment: fixed; }`, which has
|
||||||
|
performance issues when scrolling on large displays. See #1394. */
|
||||||
|
body::before {
|
||||||
|
content: ' ';
|
||||||
|
position: fixed;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: var(--bs-body-bg);
|
||||||
|
background: url(../img/grid.png) repeat-x;
|
||||||
|
will-change: transform;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
body > .container {
|
||||||
|
margin-top: 20px;
|
||||||
|
min-height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar.fixed-top {
|
||||||
|
position: -webkit-sticky;
|
||||||
|
position: sticky;
|
||||||
|
}
|
||||||
|
|
||||||
|
.source-links {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.col-md-9 img {
|
||||||
|
max-width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 4px;
|
||||||
|
line-height: 1.428571429;
|
||||||
|
background-color: var(--bs-secondary-bg-subtle);
|
||||||
|
border: 1px solid var(--bs-secondary-border-subtle);
|
||||||
|
border-radius: 4px;
|
||||||
|
margin: 20px auto 30px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: inherit;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2, h3, h4, h5, h6 {
|
||||||
|
color: inherit;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-top: 1px solid #aaa;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre, .rst-content tt {
|
||||||
|
max-width: 100%;
|
||||||
|
background-color: var(--bs-body-bg);
|
||||||
|
border: solid 1px var(--bs-border-color);
|
||||||
|
color: var(--bs-body-color);
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
code.code-large, .rst-content tt.code-large {
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
padding: 2px 5px;
|
||||||
|
background-color: rgba(var(--bs-body-bg-rgb), 0.75);
|
||||||
|
border: solid 1px var(--bs-border-color);
|
||||||
|
color: var(--bs-body-color);
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre code {
|
||||||
|
display: block;
|
||||||
|
border: none;
|
||||||
|
white-space: pre;
|
||||||
|
word-wrap: normal;
|
||||||
|
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
kbd {
|
||||||
|
padding: 2px 4px;
|
||||||
|
font-size: 90%;
|
||||||
|
color: var(--bs-secondary-text-emphasis);
|
||||||
|
background-color: var(--bs-secondary-bg-subtle);
|
||||||
|
border-radius: 3px;
|
||||||
|
-webkit-box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);
|
||||||
|
box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
a code {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover code, a:focus code {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
margin-top: 30px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-dialog {
|
||||||
|
margin-top: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Side navigation
|
||||||
|
*
|
||||||
|
* Scrollspy and affixed enhanced navigation to highlight sections and secondary
|
||||||
|
* sections of docs content.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.bs-sidebar.affix {
|
||||||
|
position: -webkit-sticky;
|
||||||
|
position: sticky;
|
||||||
|
/* The nav header is 3.5rem high, plus 20px for the margin-top of the
|
||||||
|
main container. */
|
||||||
|
top: calc(3.5rem + 20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bs-sidebar.card {
|
||||||
|
padding: 0;
|
||||||
|
max-height: 90%;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Toggle (vertically flip) sidebar collapse icon */
|
||||||
|
.bs-sidebar .navbar-toggler span {
|
||||||
|
-moz-transform: scale(1, -1);
|
||||||
|
-webkit-transform: scale(1, -1);
|
||||||
|
-o-transform: scale(1, -1);
|
||||||
|
-ms-transform: scale(1, -1);
|
||||||
|
transform: scale(1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bs-sidebar .navbar-toggler.collapsed span {
|
||||||
|
-moz-transform: scale(1, 1);
|
||||||
|
-webkit-transform: scale(1, 1);
|
||||||
|
-o-transform: scale(1, 1);
|
||||||
|
-ms-transform: scale(1, 1);
|
||||||
|
transform: scale(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First level of nav */
|
||||||
|
.bs-sidebar > .navbar-collapse > .nav {
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All levels of nav */
|
||||||
|
.bs-sidebar .nav > li > a {
|
||||||
|
display: block;
|
||||||
|
padding: 5px 20px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
.bs-sidebar .nav > li > a:hover,
|
||||||
|
.bs-sidebar .nav > li > a:focus {
|
||||||
|
text-decoration: none;
|
||||||
|
border-right: 1px solid;
|
||||||
|
}
|
||||||
|
.bs-sidebar .nav > li > a.active,
|
||||||
|
.bs-sidebar .nav > li > a.active:hover,
|
||||||
|
.bs-sidebar .nav > li > a.active:focus {
|
||||||
|
font-weight: bold;
|
||||||
|
background-color: transparent;
|
||||||
|
border-right: 1px solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bs-sidebar .nav .nav .nav {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bs-sidebar .nav > li > a {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bs-sidebar .nav .nav > li > a {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.headerlink {
|
||||||
|
font-family: FontAwesome;
|
||||||
|
font-size: 14px;
|
||||||
|
display: none;
|
||||||
|
padding-left: .5em;
|
||||||
|
text-decoration: none;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1:hover .headerlink, h2:hover .headerlink, h3:hover .headerlink, h4:hover .headerlink, h5:hover .headerlink, h6:hover .headerlink {
|
||||||
|
display:inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
padding-left: 10px;
|
||||||
|
border-left: 4px solid #e6e6e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition, details {
|
||||||
|
padding: 15px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 4px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition.note, details.note {
|
||||||
|
color: var(--bs-primary-text-emphasis);
|
||||||
|
background-color: var(--bs-primary-bg-subtle);
|
||||||
|
border-color: var(--bs-primary-border-subtle);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition.note h1, .admonition.note h2, .admonition.note h3,
|
||||||
|
.admonition.note h4, .admonition.note h5, .admonition.note h6,
|
||||||
|
details.note h1, details.note h2, details.note h3,
|
||||||
|
details.note h4, details.note h5, details.note h6 {
|
||||||
|
color: var(--bs-primary-text-emphasis);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition.info, details.info {
|
||||||
|
color: var(--bs-info-text-emphasis);
|
||||||
|
background-color: var(--bs-info-bg-subtle);
|
||||||
|
border-color: var(--bs-info-border-subtle);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition.info h1, .admonition.info h2, .admonition.info h3,
|
||||||
|
.admonition.info h4, .admonition.info h5, .admonition.info h6,
|
||||||
|
details.info h1, details.info h2, details.info h3,
|
||||||
|
details.info h4, details.info h5, details.info h6 {
|
||||||
|
color: var(--bs-info-text-emphasis);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition.warning, details.warning {
|
||||||
|
color: var(--bs-warning-text-emphasis);
|
||||||
|
background-color: var(--bs-warning-bg-subtle);
|
||||||
|
border-color: var(--bs-warning-border-subtle);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition.warning h1, .admonition.warning h2, .admonition.warning h3,
|
||||||
|
.admonition.warning h4, .admonition.warning h5, .admonition.warning h6,
|
||||||
|
details.warning h1, details.warning h2, details.warning h3,
|
||||||
|
details.warning h4, details.warning h5, details.warning h6 {
|
||||||
|
color: var(--bs-warning-text-emphasis);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition.danger, details.danger {
|
||||||
|
color: var(--bs-danger-text-emphasis);
|
||||||
|
background-color: var(--bs-danger-bg-subtle);
|
||||||
|
border-color: var(--bs-danger-border-subtle);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition.danger h1, .admonition.danger h2, .admonition.danger h3,
|
||||||
|
.admonition.danger h4, .admonition.danger h5, .admonition.danger h6,
|
||||||
|
details.danger h1, details.danger h2, details.danger h3,
|
||||||
|
details.danger h4, details.danger h5, details.danger h6 {
|
||||||
|
color: var(--bs-danger-text-emphasis);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition, details {
|
||||||
|
color: var(--bs-light-text-emphasis);
|
||||||
|
background-color: var(--bs-light-bg-subtle);
|
||||||
|
border-color: var(--bs-light-border-subtle);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition h1, .admonition h2, .admonition h3,
|
||||||
|
.admonition h4, .admonition h5, .admonition h6,
|
||||||
|
details h1, details h2, details h3,
|
||||||
|
details h4, details h5, details h6 {
|
||||||
|
color: var(--bs-light-text-emphasis);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition-title, summary {
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admonition>p:last-child, details>p:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 991.98px) {
|
||||||
|
.navbar-collapse.show {
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: calc(100vh - 3.5rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-item.open {
|
||||||
|
color: var(--bs-dropdown-link-active-color);
|
||||||
|
background-color: var(--bs-dropdown-link-active-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-submenu > .dropdown-menu {
|
||||||
|
margin: 0 0 0 1.5rem;
|
||||||
|
padding: 0;
|
||||||
|
border-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-submenu > a::after {
|
||||||
|
display: block;
|
||||||
|
content: " ";
|
||||||
|
float: right;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-color: transparent;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 5px 0 5px 5px;
|
||||||
|
border-left-color: var(--bs-dropdown-link-active-color);
|
||||||
|
margin-top: 5px;
|
||||||
|
margin-right: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-submenu:hover > a::after {
|
||||||
|
border-left-color: var(--bs-dropdown-link-active-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 992px) {
|
||||||
|
.dropdown-menu {
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: calc(100vh - 3.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-submenu {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-submenu > .dropdown-menu {
|
||||||
|
position: fixed !important;
|
||||||
|
margin-top: -9px;
|
||||||
|
margin-left: -2px;
|
||||||
|
border-width: 1px;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-submenu.pull-left {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-submenu.pull-left > .dropdown-menu {
|
||||||
|
left: -100%;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
/* Remove sidebar when print */
|
||||||
|
.col-md-3 { display: none; }
|
||||||
|
}
|
12
css/bootstrap.min.css
vendored
Normal file
1
css/bootstrap.min.css.map
Normal file
6
css/brands.min.css
vendored
Normal file
9
css/fontawesome.min.css
vendored
Normal file
6
css/solid.min.css
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2023 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900}
|
6
css/v4-font-face.min.css
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
/*!
|
||||||
|
* Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com
|
||||||
|
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
* Copyright 2023 Fonticons, Inc.
|
||||||
|
*/
|
||||||
|
@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a}
|
|
@ -1,48 +0,0 @@
|
||||||
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
|
|
||||||
org.gradle.jvmargs=-Xmx1G
|
|
||||||
org.gradle.daemon=false
|
|
||||||
org.gradle.parallel=true
|
|
||||||
org.gradle.caching=true
|
|
||||||
org.gradle.configuration-cache=true
|
|
||||||
|
|
||||||
#read more on this at https://github.com/neoforged/ModDevGradle?tab=readme-ov-file#better-minecraft-parameter-names--javadoc-parchment
|
|
||||||
# you can also find the latest versions at: https://parchmentmc.org/docs/getting-started
|
|
||||||
parchment_minecraft_version=1.21
|
|
||||||
parchment_mappings_version=2024.07.28
|
|
||||||
|
|
||||||
# Environment Properties
|
|
||||||
# You can find the latest versions here: https://projects.neoforged.net/neoforged/neoforge
|
|
||||||
# The Minecraft version must agree with the Neo version to get a valid artifact
|
|
||||||
minecraft_version=1.21.3
|
|
||||||
|
|
||||||
# The Minecraft version range can use any release version of Minecraft as bounds.
|
|
||||||
# Snapshots, pre-releases, and release candidates are not guaranteed to sort properly
|
|
||||||
# as they do not follow standard versioning conventions.
|
|
||||||
minecraft_version_range=[1.21.3, 1.22)
|
|
||||||
|
|
||||||
# The Neo version must agree with the Minecraft version to get a valid artifact
|
|
||||||
neo_version=21.3.11-beta
|
|
||||||
# The Neo version range can use any version of Neo as bounds
|
|
||||||
neo_version_range=[21.3.0,)
|
|
||||||
# The loader version range can only use the major version of FML as bounds
|
|
||||||
loader_version_range=[4,)
|
|
||||||
|
|
||||||
## Mod Properties
|
|
||||||
|
|
||||||
# The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63}
|
|
||||||
# Must match the String constant located in the main mod class annotated with @Mod.
|
|
||||||
mod_id=com_burnedkirby_turnbasedminecraft
|
|
||||||
# The human-readable display name for the mod.
|
|
||||||
mod_name=TurnBasedMinecraftMod
|
|
||||||
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
|
|
||||||
mod_license=MIT
|
|
||||||
# The mod version. See https://semver.org/
|
|
||||||
mod_version=1.26.5
|
|
||||||
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
|
|
||||||
# This should match the base package used for the mod sources.
|
|
||||||
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
|
|
||||||
mod_group_id=com.burnedkirby.TurnBasedMinecraft
|
|
||||||
# The authors of the mod. This is a simple text string that is used for display purposes in the mod list.
|
|
||||||
mod_authors=BurnedKirby a.k.a. Stephen Seo
|
|
||||||
# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list.
|
|
||||||
mod_description=Implements turn-based-battle in Minecraft.
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
7
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,7 +0,0 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
|
||||||
networkTimeout=10000
|
|
||||||
validateDistributionUrl=true
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
|
252
gradlew
vendored
|
@ -1,252 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright © 2015-2021 the original authors.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# Gradle start up script for POSIX generated by Gradle.
|
|
||||||
#
|
|
||||||
# Important for running:
|
|
||||||
#
|
|
||||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
|
||||||
# noncompliant, but you have some other compliant shell such as ksh or
|
|
||||||
# bash, then to run this script, type that shell name before the whole
|
|
||||||
# command line, like:
|
|
||||||
#
|
|
||||||
# ksh Gradle
|
|
||||||
#
|
|
||||||
# Busybox and similar reduced shells will NOT work, because this script
|
|
||||||
# requires all of these POSIX shell features:
|
|
||||||
# * functions;
|
|
||||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
|
||||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
|
||||||
# * compound commands having a testable exit status, especially «case»;
|
|
||||||
# * various built-in commands including «command», «set», and «ulimit».
|
|
||||||
#
|
|
||||||
# Important for patching:
|
|
||||||
#
|
|
||||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
|
||||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
|
||||||
#
|
|
||||||
# The "traditional" practice of packing multiple parameters into a
|
|
||||||
# space-separated string is a well documented source of bugs and security
|
|
||||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
|
||||||
# options in "$@", and eventually passing that to Java.
|
|
||||||
#
|
|
||||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
|
||||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
|
||||||
# see the in-line comments for details.
|
|
||||||
#
|
|
||||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
|
||||||
# Darwin, MinGW, and NonStop.
|
|
||||||
#
|
|
||||||
# (3) This script is generated from the Groovy template
|
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
|
||||||
# within the Gradle project.
|
|
||||||
#
|
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
|
||||||
|
|
||||||
# Resolve links: $0 may be a link
|
|
||||||
app_path=$0
|
|
||||||
|
|
||||||
# Need this for daisy-chained symlinks.
|
|
||||||
while
|
|
||||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
|
||||||
[ -h "$app_path" ]
|
|
||||||
do
|
|
||||||
ls=$( ls -ld "$app_path" )
|
|
||||||
link=${ls#*' -> '}
|
|
||||||
case $link in #(
|
|
||||||
/*) app_path=$link ;; #(
|
|
||||||
*) app_path=$APP_HOME$link ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# This is normally unused
|
|
||||||
# shellcheck disable=SC2034
|
|
||||||
APP_BASE_NAME=${0##*/}
|
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
|
||||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
|
||||||
' "$PWD" ) || exit
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
|
||||||
MAX_FD=maximum
|
|
||||||
|
|
||||||
warn () {
|
|
||||||
echo "$*"
|
|
||||||
} >&2
|
|
||||||
|
|
||||||
die () {
|
|
||||||
echo
|
|
||||||
echo "$*"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
} >&2
|
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
|
||||||
cygwin=false
|
|
||||||
msys=false
|
|
||||||
darwin=false
|
|
||||||
nonstop=false
|
|
||||||
case "$( uname )" in #(
|
|
||||||
CYGWIN* ) cygwin=true ;; #(
|
|
||||||
Darwin* ) darwin=true ;; #(
|
|
||||||
MSYS* | MINGW* ) msys=true ;; #(
|
|
||||||
NONSTOP* ) nonstop=true ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
|
||||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
|
||||||
else
|
|
||||||
JAVACMD=$JAVA_HOME/bin/java
|
|
||||||
fi
|
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
JAVACMD=java
|
|
||||||
if ! command -v java >/dev/null 2>&1
|
|
||||||
then
|
|
||||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
|
||||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|
||||||
case $MAX_FD in #(
|
|
||||||
max*)
|
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
|
||||||
# shellcheck disable=SC2039,SC3045
|
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
|
||||||
warn "Could not query maximum file descriptor limit"
|
|
||||||
esac
|
|
||||||
case $MAX_FD in #(
|
|
||||||
'' | soft) :;; #(
|
|
||||||
*)
|
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
|
||||||
# shellcheck disable=SC2039,SC3045
|
|
||||||
ulimit -n "$MAX_FD" ||
|
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Collect all arguments for the java command, stacking in reverse order:
|
|
||||||
# * args from the command line
|
|
||||||
# * the main class name
|
|
||||||
# * -classpath
|
|
||||||
# * -D...appname settings
|
|
||||||
# * --module-path (only if needed)
|
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
|
||||||
|
|
||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
|
||||||
if "$cygwin" || "$msys" ; then
|
|
||||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
|
||||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
|
||||||
|
|
||||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
|
||||||
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
for arg do
|
|
||||||
if
|
|
||||||
case $arg in #(
|
|
||||||
-*) false ;; # don't mess with options #(
|
|
||||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
|
||||||
[ -e "$t" ] ;; #(
|
|
||||||
*) false ;;
|
|
||||||
esac
|
|
||||||
then
|
|
||||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
|
||||||
fi
|
|
||||||
# Roll the args list around exactly as many times as the number of
|
|
||||||
# args, so each arg winds up back in the position where it started, but
|
|
||||||
# possibly modified.
|
|
||||||
#
|
|
||||||
# NB: a `for` loop captures its iteration list before it begins, so
|
|
||||||
# changing the positional parameters here affects neither the number of
|
|
||||||
# iterations, nor the values presented in `arg`.
|
|
||||||
shift # remove old arg
|
|
||||||
set -- "$@" "$arg" # push replacement arg
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|
||||||
|
|
||||||
# Collect all arguments for the java command:
|
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
|
||||||
# and any embedded shellness will be escaped.
|
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
|
||||||
# treated as '${Hostname}' itself on the command line.
|
|
||||||
|
|
||||||
set -- \
|
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
|
||||||
-classpath "$CLASSPATH" \
|
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
|
||||||
"$@"
|
|
||||||
|
|
||||||
# Stop when "xargs" is not available.
|
|
||||||
if ! command -v xargs >/dev/null 2>&1
|
|
||||||
then
|
|
||||||
die "xargs is not available"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Use "xargs" to parse quoted args.
|
|
||||||
#
|
|
||||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
|
||||||
#
|
|
||||||
# In Bash we could simply go:
|
|
||||||
#
|
|
||||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
|
||||||
# set -- "${ARGS[@]}" "$@"
|
|
||||||
#
|
|
||||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
|
||||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
|
||||||
# character that might be a shell metacharacter, then use eval to reverse
|
|
||||||
# that process (while maintaining the separation between arguments), and wrap
|
|
||||||
# the whole thing up as a single "set" statement.
|
|
||||||
#
|
|
||||||
# This will of course break if any of these variables contains a newline or
|
|
||||||
# an unmatched quote.
|
|
||||||
#
|
|
||||||
|
|
||||||
eval "set -- $(
|
|
||||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
|
||||||
xargs -n1 |
|
|
||||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
|
||||||
tr '\n' ' '
|
|
||||||
)" '"$@"'
|
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
|
94
gradlew.bat
vendored
|
@ -1,94 +0,0 @@
|
||||||
@rem
|
|
||||||
@rem Copyright 2015 the original author or authors.
|
|
||||||
@rem
|
|
||||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
@rem you may not use this file except in compliance with the License.
|
|
||||||
@rem You may obtain a copy of the License at
|
|
||||||
@rem
|
|
||||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
@rem
|
|
||||||
@rem Unless required by applicable law or agreed to in writing, software
|
|
||||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
@rem See the License for the specific language governing permissions and
|
|
||||||
@rem limitations under the License.
|
|
||||||
@rem
|
|
||||||
@rem SPDX-License-Identifier: Apache-2.0
|
|
||||||
@rem
|
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
|
||||||
@rem ##########################################################################
|
|
||||||
@rem
|
|
||||||
@rem Gradle startup script for Windows
|
|
||||||
@rem
|
|
||||||
@rem ##########################################################################
|
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
|
||||||
if "%DIRNAME%"=="" set DIRNAME=.
|
|
||||||
@rem This is normally unused
|
|
||||||
set APP_BASE_NAME=%~n0
|
|
||||||
set APP_HOME=%DIRNAME%
|
|
||||||
|
|
||||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
|
||||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
|
||||||
|
|
||||||
@rem Find java.exe
|
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
|
||||||
|
|
||||||
echo. 1>&2
|
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
|
||||||
echo. 1>&2
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
|
||||||
echo location of your Java installation. 1>&2
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
|
||||||
|
|
||||||
echo. 1>&2
|
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
|
||||||
echo. 1>&2
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
|
||||||
echo location of your Java installation. 1>&2
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:execute
|
|
||||||
@rem Setup the command line
|
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
|
||||||
|
|
||||||
:end
|
|
||||||
@rem End local scope for the variables with windows NT shell
|
|
||||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
|
||||||
|
|
||||||
:fail
|
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
||||||
rem the _cmd.exe /c_ return code!
|
|
||||||
set EXIT_CODE=%ERRORLEVEL%
|
|
||||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
|
||||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
|
||||||
exit /b %EXIT_CODE%
|
|
||||||
|
|
||||||
:mainEnd
|
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
|
||||||
|
|
||||||
:omega
|
|
BIN
img/favicon.ico
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
img/grid.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
213
index.html
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" data-bs-theme="dark">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="description" content="None">
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="img/favicon.ico">
|
||||||
|
<title>Documentation for TurnBasedMinecraftMod</title>
|
||||||
|
<link href="css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="css/fontawesome.min.css" rel="stylesheet">
|
||||||
|
<link href="css/brands.min.css" rel="stylesheet">
|
||||||
|
<link href="css/solid.min.css" rel="stylesheet">
|
||||||
|
<link href="css/v4-font-face.min.css" rel="stylesheet">
|
||||||
|
<link href="css/base.css" rel="stylesheet">
|
||||||
|
<link id="hljs-light" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css" disabled>
|
||||||
|
<link id="hljs-dark" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github-dark.min.css" >
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
|
||||||
|
<script>hljs.highlightAll();</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="homepage">
|
||||||
|
<div class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand" href=".">Documentation for TurnBasedMinecraftMod</a>
|
||||||
|
<!-- Expander button -->
|
||||||
|
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#navbar-collapse" aria-controls="navbar-collapse" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Expanded navigation -->
|
||||||
|
<div id="navbar-collapse" class="navbar-collapse collapse">
|
||||||
|
<!-- Main navigation -->
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="." class="nav-link active" aria-current="page">TurnBasedMinecraftMod</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="client_config/" class="nav-link">Client-side Config</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="server_config/" class="nav-link">Server-side Config</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="nav navbar-nav ms-md-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="#" class="nav-link" data-bs-toggle="modal" data-bs-target="#mkdocs_search_modal">
|
||||||
|
<i class="fa fa-search"></i> Search
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a rel="prev" class="nav-link disabled">
|
||||||
|
<i class="fa fa-arrow-left"></i> Previous
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a rel="next" href="client_config/" class="nav-link">
|
||||||
|
Next <i class="fa fa-arrow-right"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<button id="theme-menu" aria-expanded="false" data-bs-toggle="dropdown" data-bs-display="static" aria-label="Toggle theme" class="nav-link dropdown-toggle">
|
||||||
|
<i class="fa-solid fa-circle-half-stroke fa-fw"></i>
|
||||||
|
<span class="d-lg-none ms-2">Toggle theme</span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="light" aria-pressed="false">
|
||||||
|
<i class="fa-solid fa-sun fa-fw"></i>
|
||||||
|
<span class="ms-2">Light</span>
|
||||||
|
<i class="fa-solid fa-check ms-auto d-none"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="dark" aria-pressed="true">
|
||||||
|
<i class="fa-solid fa-moon fa-fw"></i>
|
||||||
|
<span class="ms-2">Dark</span>
|
||||||
|
<i class="fa-solid fa-check ms-auto"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="auto" aria-pressed="false">
|
||||||
|
<i class="fa-solid fa-circle-half-stroke fa-fw"></i>
|
||||||
|
<span class="ms-2">Auto</span>
|
||||||
|
<i class="fa-solid fa-check ms-auto d-none"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="js/darkmode.js"></script>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3"><div class="navbar-expand-md bs-sidebar hidden-print affix" role="complementary">
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggler collapsed" data-bs-toggle="collapse" data-bs-target="#toc-collapse" title="Table of Contents">
|
||||||
|
<span class="fa fa-angle-down"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="toc-collapse" class="navbar-collapse collapse card bg-body-tertiary">
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
|
||||||
|
<li class="nav-item" data-bs-level="1"><a href="#turnbasedminecraftmod" class="nav-link">TurnBasedMinecraftMod</a>
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
<li class="nav-item" data-bs-level="2"><a href="#pages" class="nav-link">Pages</a>
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
<div class="col-md-9" role="main">
|
||||||
|
|
||||||
|
<h1 id="turnbasedminecraftmod">TurnBasedMinecraftMod</h1>
|
||||||
|
<p><a href="https://github.com/Stephen-Seo/TurnBasedMinecraftMod">Main repository link.</a></p>
|
||||||
|
<p><a href="https://git.seodisparate.com/stephenseo/TurnBasedMinecraftMod">Alternate repository link.</a></p>
|
||||||
|
<h2 id="pages">Pages</h2>
|
||||||
|
<p><a href="client_config/">Client-side config</a></p>
|
||||||
|
<p><a href="server_config/">Server-side config</a></p></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="col-md-12">
|
||||||
|
<hr>
|
||||||
|
<p>Documentation built with <a href="https://www.mkdocs.org/">MkDocs</a>.</p>
|
||||||
|
</footer>
|
||||||
|
<script src="js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script>
|
||||||
|
var base_url = ".",
|
||||||
|
shortcuts = {"help": 191, "next": 78, "previous": 80, "search": 83};
|
||||||
|
</script>
|
||||||
|
<script src="js/base.js"></script>
|
||||||
|
<script src="search/main.js"></script>
|
||||||
|
|
||||||
|
<div class="modal" id="mkdocs_search_modal" tabindex="-1" role="dialog" aria-labelledby="searchModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="searchModalLabel">Search</h4>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>From here you can search these documents. Enter your search terms below.</p>
|
||||||
|
<form>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="search" class="form-control" placeholder="Search..." id="mkdocs-search-query" title="Type search term here">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div id="mkdocs-search-results" data-no-results-text="No results found"></div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><div class="modal" id="mkdocs_keyboard_modal" tabindex="-1" role="dialog" aria-labelledby="keyboardModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="keyboardModalLabel">Keyboard Shortcuts</h4>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width: 20%;">Keys</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="help shortcut"><kbd>?</kbd></td>
|
||||||
|
<td>Open this help</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="next shortcut"><kbd>n</kbd></td>
|
||||||
|
<td>Next page</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="prev shortcut"><kbd>p</kbd></td>
|
||||||
|
<td>Previous page</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="search shortcut"><kbd>s</kbd></td>
|
||||||
|
<td>Search</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
MkDocs version : 1.6.1
|
||||||
|
Build Date UTC : 2024-10-29 08:57:40.510050+00:00
|
||||||
|
-->
|
287
js/base.js
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
function getSearchTerm() {
|
||||||
|
var sPageURL = window.location.search.substring(1);
|
||||||
|
var sURLVariables = sPageURL.split('&');
|
||||||
|
for (var i = 0; i < sURLVariables.length; i++) {
|
||||||
|
var sParameterName = sURLVariables[i].split('=');
|
||||||
|
if (sParameterName[0] == 'q') {
|
||||||
|
return sParameterName[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyTopPadding() {
|
||||||
|
// Update various absolute positions to match where the main container
|
||||||
|
// starts. This is necessary for handling multi-line nav headers, since
|
||||||
|
// that pushes the main container down.
|
||||||
|
var container = document.querySelector('body > .container');
|
||||||
|
var offset = container.offsetTop;
|
||||||
|
|
||||||
|
document.documentElement.style.scrollPaddingTop = offset + 'px';
|
||||||
|
document.querySelectorAll('.bs-sidebar.affix').forEach(function(sidebar) {
|
||||||
|
sidebar.style.top = offset + 'px';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
var search_term = getSearchTerm();
|
||||||
|
var search_modal = new bootstrap.Modal(document.getElementById('mkdocs_search_modal'));
|
||||||
|
var keyboard_modal = new bootstrap.Modal(document.getElementById('mkdocs_keyboard_modal'));
|
||||||
|
|
||||||
|
if (search_term) {
|
||||||
|
search_modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// make sure search input gets autofocus every time modal opens.
|
||||||
|
document.getElementById('mkdocs_search_modal').addEventListener('shown.bs.modal', function() {
|
||||||
|
document.getElementById('mkdocs-search-query').focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Close search modal when result is selected
|
||||||
|
// The links get added later so listen to parent
|
||||||
|
document.getElementById('mkdocs-search-results').addEventListener('click', function(e) {
|
||||||
|
if (e.target.tagName === 'A') {
|
||||||
|
search_modal.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Populate keyboard modal with proper Keys
|
||||||
|
document.querySelector('.help.shortcut kbd').innerHTML = keyCodes[shortcuts.help];
|
||||||
|
document.querySelector('.prev.shortcut kbd').innerHTML = keyCodes[shortcuts.previous];
|
||||||
|
document.querySelector('.next.shortcut kbd').innerHTML = keyCodes[shortcuts.next];
|
||||||
|
document.querySelector('.search.shortcut kbd').innerHTML = keyCodes[shortcuts.search];
|
||||||
|
|
||||||
|
// Keyboard navigation
|
||||||
|
document.addEventListener("keydown", function(e) {
|
||||||
|
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return true;
|
||||||
|
var key = e.which || e.keyCode || window.event && window.event.keyCode;
|
||||||
|
var page;
|
||||||
|
switch (key) {
|
||||||
|
case shortcuts.next:
|
||||||
|
page = document.querySelector('.navbar a[rel="next"]');
|
||||||
|
break;
|
||||||
|
case shortcuts.previous:
|
||||||
|
page = document.querySelector('.navbar a[rel="prev"]');
|
||||||
|
break;
|
||||||
|
case shortcuts.search:
|
||||||
|
e.preventDefault();
|
||||||
|
keyboard_modal.hide();
|
||||||
|
search_modal.show();
|
||||||
|
document.getElementById('mkdocs-search-query').focus();
|
||||||
|
break;
|
||||||
|
case shortcuts.help:
|
||||||
|
search_modal.hide();
|
||||||
|
keyboard_modal.show();
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
if (page && page.hasAttribute('href')) {
|
||||||
|
keyboard_modal.hide();
|
||||||
|
window.location.href = page.getAttribute('href');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('table').forEach(function(table) {
|
||||||
|
table.classList.add('table', 'table-striped', 'table-hover');
|
||||||
|
});
|
||||||
|
|
||||||
|
function showInnerDropdown(item) {
|
||||||
|
var popup = item.nextElementSibling;
|
||||||
|
popup.classList.add('show');
|
||||||
|
item.classList.add('open');
|
||||||
|
|
||||||
|
// First, close any sibling dropdowns.
|
||||||
|
var container = item.parentElement.parentElement;
|
||||||
|
container.querySelectorAll(':scope > .dropdown-submenu > a').forEach(function(el) {
|
||||||
|
if (el !== item) {
|
||||||
|
hideInnerDropdown(el);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var popupMargin = 10;
|
||||||
|
var maxBottom = window.innerHeight - popupMargin;
|
||||||
|
var bounds = item.getBoundingClientRect();
|
||||||
|
|
||||||
|
popup.style.left = bounds.right + 'px';
|
||||||
|
if (bounds.top + popup.clientHeight > maxBottom &&
|
||||||
|
bounds.top > window.innerHeight / 2) {
|
||||||
|
popup.style.top = (bounds.bottom - popup.clientHeight) + 'px';
|
||||||
|
popup.style.maxHeight = (bounds.bottom - popupMargin) + 'px';
|
||||||
|
} else {
|
||||||
|
popup.style.top = bounds.top + 'px';
|
||||||
|
popup.style.maxHeight = (maxBottom - bounds.top) + 'px';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideInnerDropdown(item) {
|
||||||
|
var popup = item.nextElementSibling;
|
||||||
|
popup.classList.remove('show');
|
||||||
|
item.classList.remove('open');
|
||||||
|
|
||||||
|
popup.scrollTop = 0;
|
||||||
|
var menu = popup.querySelector('.dropdown-menu');
|
||||||
|
if (menu) {
|
||||||
|
menu.scrollTop = 0;
|
||||||
|
}
|
||||||
|
var dropdown = popup.querySelector('.dropdown-submenu > a');
|
||||||
|
if (dropdown) {
|
||||||
|
dropdown.classList.remove('open');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll('.dropdown-submenu > a').forEach(function(item) {
|
||||||
|
item.addEventListener('click', function(e) {
|
||||||
|
if (item.nextElementSibling.classList.contains('show')) {
|
||||||
|
hideInnerDropdown(item);
|
||||||
|
} else {
|
||||||
|
showInnerDropdown(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.dropdown-menu').forEach(function(menu) {
|
||||||
|
menu.parentElement.addEventListener('hide.bs.dropdown', function() {
|
||||||
|
menu.scrollTop = 0;
|
||||||
|
var dropdown = menu.querySelector('.dropdown-submenu > a');
|
||||||
|
if (dropdown) {
|
||||||
|
dropdown.classList.remove('open');
|
||||||
|
}
|
||||||
|
menu.querySelectorAll('.dropdown-menu .dropdown-menu').forEach(function(submenu) {
|
||||||
|
submenu.classList.remove('show');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
applyTopPadding();
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('resize', applyTopPadding);
|
||||||
|
|
||||||
|
var scrollSpy = new bootstrap.ScrollSpy(document.body, {
|
||||||
|
target: '.bs-sidebar'
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Prevent disabled links from causing a page reload */
|
||||||
|
document.querySelectorAll("li.disabled a").forEach(function(item) {
|
||||||
|
item.addEventListener("click", function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// See https://www.cambiaresearch.com/articles/15/javascript-char-codes-key-codes
|
||||||
|
// We only list common keys below. Obscure keys are omitted and their use is discouraged.
|
||||||
|
var keyCodes = {
|
||||||
|
8: 'backspace',
|
||||||
|
9: 'tab',
|
||||||
|
13: 'enter',
|
||||||
|
16: 'shift',
|
||||||
|
17: 'ctrl',
|
||||||
|
18: 'alt',
|
||||||
|
19: 'pause/break',
|
||||||
|
20: 'caps lock',
|
||||||
|
27: 'escape',
|
||||||
|
32: 'spacebar',
|
||||||
|
33: 'page up',
|
||||||
|
34: 'page down',
|
||||||
|
35: 'end',
|
||||||
|
36: 'home',
|
||||||
|
37: '←',
|
||||||
|
38: '↑',
|
||||||
|
39: '→',
|
||||||
|
40: '↓',
|
||||||
|
45: 'insert',
|
||||||
|
46: 'delete',
|
||||||
|
48: '0',
|
||||||
|
49: '1',
|
||||||
|
50: '2',
|
||||||
|
51: '3',
|
||||||
|
52: '4',
|
||||||
|
53: '5',
|
||||||
|
54: '6',
|
||||||
|
55: '7',
|
||||||
|
56: '8',
|
||||||
|
57: '9',
|
||||||
|
65: 'a',
|
||||||
|
66: 'b',
|
||||||
|
67: 'c',
|
||||||
|
68: 'd',
|
||||||
|
69: 'e',
|
||||||
|
70: 'f',
|
||||||
|
71: 'g',
|
||||||
|
72: 'h',
|
||||||
|
73: 'i',
|
||||||
|
74: 'j',
|
||||||
|
75: 'k',
|
||||||
|
76: 'l',
|
||||||
|
77: 'm',
|
||||||
|
78: 'n',
|
||||||
|
79: 'o',
|
||||||
|
80: 'p',
|
||||||
|
81: 'q',
|
||||||
|
82: 'r',
|
||||||
|
83: 's',
|
||||||
|
84: 't',
|
||||||
|
85: 'u',
|
||||||
|
86: 'v',
|
||||||
|
87: 'w',
|
||||||
|
88: 'x',
|
||||||
|
89: 'y',
|
||||||
|
90: 'z',
|
||||||
|
91: 'Left Windows Key / Left ⌘',
|
||||||
|
92: 'Right Windows Key',
|
||||||
|
93: 'Windows Menu / Right ⌘',
|
||||||
|
96: 'numpad 0',
|
||||||
|
97: 'numpad 1',
|
||||||
|
98: 'numpad 2',
|
||||||
|
99: 'numpad 3',
|
||||||
|
100: 'numpad 4',
|
||||||
|
101: 'numpad 5',
|
||||||
|
102: 'numpad 6',
|
||||||
|
103: 'numpad 7',
|
||||||
|
104: 'numpad 8',
|
||||||
|
105: 'numpad 9',
|
||||||
|
106: 'multiply',
|
||||||
|
107: 'add',
|
||||||
|
109: 'subtract',
|
||||||
|
110: 'decimal point',
|
||||||
|
111: 'divide',
|
||||||
|
112: 'f1',
|
||||||
|
113: 'f2',
|
||||||
|
114: 'f3',
|
||||||
|
115: 'f4',
|
||||||
|
116: 'f5',
|
||||||
|
117: 'f6',
|
||||||
|
118: 'f7',
|
||||||
|
119: 'f8',
|
||||||
|
120: 'f9',
|
||||||
|
121: 'f10',
|
||||||
|
122: 'f11',
|
||||||
|
123: 'f12',
|
||||||
|
124: 'f13',
|
||||||
|
125: 'f14',
|
||||||
|
126: 'f15',
|
||||||
|
127: 'f16',
|
||||||
|
128: 'f17',
|
||||||
|
129: 'f18',
|
||||||
|
130: 'f19',
|
||||||
|
131: 'f20',
|
||||||
|
132: 'f21',
|
||||||
|
133: 'f22',
|
||||||
|
134: 'f23',
|
||||||
|
135: 'f24',
|
||||||
|
144: 'num lock',
|
||||||
|
145: 'scroll lock',
|
||||||
|
186: ';',
|
||||||
|
187: '=',
|
||||||
|
188: ',',
|
||||||
|
189: '‐',
|
||||||
|
190: '.',
|
||||||
|
191: '?',
|
||||||
|
192: '`',
|
||||||
|
219: '[',
|
||||||
|
220: '\',
|
||||||
|
221: ']',
|
||||||
|
222: ''',
|
||||||
|
};
|
7
js/bootstrap.bundle.min.js
vendored
Normal file
1
js/bootstrap.bundle.min.js.map
Normal file
65
js/darkmode.js
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
function setColorMode(mode) {
|
||||||
|
// Switch between light/dark theme. `mode` is a string value of either 'dark' or 'light'.
|
||||||
|
var hljs_light = document.getElementById('hljs-light'),
|
||||||
|
hljs_dark = document.getElementById('hljs-dark');
|
||||||
|
document.documentElement.setAttribute('data-bs-theme', mode);
|
||||||
|
if (mode == 'dark') {
|
||||||
|
hljs_light.disabled = true;
|
||||||
|
hljs_dark.disabled = false;
|
||||||
|
} else {
|
||||||
|
hljs_dark.disabled = true;
|
||||||
|
hljs_light.disabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateModeToggle(mode) {
|
||||||
|
// Update icon and toggle checkmarks of color mode selector.
|
||||||
|
var menu = document.getElementById('theme-menu');
|
||||||
|
document.querySelectorAll('[data-bs-theme-value]')
|
||||||
|
.forEach(function(toggle) {
|
||||||
|
if (mode == toggle.getAttribute('data-bs-theme-value')) {
|
||||||
|
toggle.setAttribute('aria-pressed', 'true');
|
||||||
|
toggle.lastElementChild.classList.remove('d-none');
|
||||||
|
menu.firstElementChild.setAttribute('class', toggle.firstElementChild.getAttribute('class'));
|
||||||
|
} else {
|
||||||
|
toggle.setAttribute('aria-pressed', 'false');
|
||||||
|
toggle.lastElementChild.classList.add('d-none');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSystemColorSchemeChange(event) {
|
||||||
|
// Update site color mode to match system color mode.
|
||||||
|
setColorMode(event.matches ? 'dark' : 'light');
|
||||||
|
}
|
||||||
|
|
||||||
|
var mql = window.matchMedia('(prefers-color-scheme: dark)'),
|
||||||
|
defaultMode = document.documentElement.getAttribute('data-bs-theme'),
|
||||||
|
storedMode = localStorage.getItem('mkdocs-colormode');
|
||||||
|
if (storedMode && storedMode != 'auto') {
|
||||||
|
setColorMode(storedMode);
|
||||||
|
updateModeToggle(storedMode);
|
||||||
|
} else if (storedMode == 'auto' || defaultMode == 'auto') {
|
||||||
|
setColorMode(mql.matches ? 'dark' : 'light');
|
||||||
|
updateModeToggle('auto');
|
||||||
|
mql.addEventListener('change', onSystemColorSchemeChange);
|
||||||
|
} else {
|
||||||
|
setColorMode(defaultMode);
|
||||||
|
updateModeToggle(defaultMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll('[data-bs-theme-value]')
|
||||||
|
.forEach(function(toggle) {
|
||||||
|
toggle.addEventListener('click', function (e) {
|
||||||
|
var mode = e.currentTarget.getAttribute('data-bs-theme-value');
|
||||||
|
localStorage.setItem('mkdocs-colormode', mode);
|
||||||
|
if (mode == 'auto') {
|
||||||
|
setColorMode(mql.matches ? 'dark' : 'light');
|
||||||
|
mql.addEventListener('change', onSystemColorSchemeChange);
|
||||||
|
} else {
|
||||||
|
setColorMode(mode);
|
||||||
|
mql.removeEventListener('change', onSystemColorSchemeChange);
|
||||||
|
}
|
||||||
|
updateModeToggle(mode);
|
||||||
|
});
|
||||||
|
});
|
3475
search/lunr.js
Normal file
109
search/main.js
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
function getSearchTermFromLocation() {
|
||||||
|
var sPageURL = window.location.search.substring(1);
|
||||||
|
var sURLVariables = sPageURL.split('&');
|
||||||
|
for (var i = 0; i < sURLVariables.length; i++) {
|
||||||
|
var sParameterName = sURLVariables[i].split('=');
|
||||||
|
if (sParameterName[0] == 'q') {
|
||||||
|
return decodeURIComponent(sParameterName[1].replace(/\+/g, '%20'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function joinUrl (base, path) {
|
||||||
|
if (path.substring(0, 1) === "/") {
|
||||||
|
// path starts with `/`. Thus it is absolute.
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
if (base.substring(base.length-1) === "/") {
|
||||||
|
// base ends with `/`
|
||||||
|
return base + path;
|
||||||
|
}
|
||||||
|
return base + "/" + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeHtml (value) {
|
||||||
|
return value.replace(/&/g, '&')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>');
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatResult (location, title, summary) {
|
||||||
|
return '<article><h3><a href="' + joinUrl(base_url, location) + '">'+ escapeHtml(title) + '</a></h3><p>' + escapeHtml(summary) +'</p></article>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayResults (results) {
|
||||||
|
var search_results = document.getElementById("mkdocs-search-results");
|
||||||
|
while (search_results.firstChild) {
|
||||||
|
search_results.removeChild(search_results.firstChild);
|
||||||
|
}
|
||||||
|
if (results.length > 0){
|
||||||
|
for (var i=0; i < results.length; i++){
|
||||||
|
var result = results[i];
|
||||||
|
var html = formatResult(result.location, result.title, result.summary);
|
||||||
|
search_results.insertAdjacentHTML('beforeend', html);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var noResultsText = search_results.getAttribute('data-no-results-text');
|
||||||
|
if (!noResultsText) {
|
||||||
|
noResultsText = "No results found";
|
||||||
|
}
|
||||||
|
search_results.insertAdjacentHTML('beforeend', '<p>' + noResultsText + '</p>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSearch () {
|
||||||
|
var query = document.getElementById('mkdocs-search-query').value;
|
||||||
|
if (query.length > min_search_length) {
|
||||||
|
if (!window.Worker) {
|
||||||
|
displayResults(search(query));
|
||||||
|
} else {
|
||||||
|
searchWorker.postMessage({query: query});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Clear results for short queries
|
||||||
|
displayResults([]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initSearch () {
|
||||||
|
var search_input = document.getElementById('mkdocs-search-query');
|
||||||
|
if (search_input) {
|
||||||
|
search_input.addEventListener("keyup", doSearch);
|
||||||
|
}
|
||||||
|
var term = getSearchTermFromLocation();
|
||||||
|
if (term) {
|
||||||
|
search_input.value = term;
|
||||||
|
doSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onWorkerMessage (e) {
|
||||||
|
if (e.data.allowSearch) {
|
||||||
|
initSearch();
|
||||||
|
} else if (e.data.results) {
|
||||||
|
var results = e.data.results;
|
||||||
|
displayResults(results);
|
||||||
|
} else if (e.data.config) {
|
||||||
|
min_search_length = e.data.config.min_search_length-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!window.Worker) {
|
||||||
|
console.log('Web Worker API not supported');
|
||||||
|
// load index in main thread
|
||||||
|
$.getScript(joinUrl(base_url, "search/worker.js")).done(function () {
|
||||||
|
console.log('Loaded worker');
|
||||||
|
init();
|
||||||
|
window.postMessage = function (msg) {
|
||||||
|
onWorkerMessage({data: msg});
|
||||||
|
};
|
||||||
|
}).fail(function (jqxhr, settings, exception) {
|
||||||
|
console.error('Could not load worker.js');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Wrap search in a web worker
|
||||||
|
var searchWorker = new Worker(joinUrl(base_url, "search/worker.js"));
|
||||||
|
searchWorker.postMessage({init: true});
|
||||||
|
searchWorker.onmessage = onWorkerMessage;
|
||||||
|
}
|
1
search/search_index.json
Normal file
133
search/worker.js
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
var base_path = 'function' === typeof importScripts ? '.' : '/search/';
|
||||||
|
var allowSearch = false;
|
||||||
|
var index;
|
||||||
|
var documents = {};
|
||||||
|
var lang = ['en'];
|
||||||
|
var data;
|
||||||
|
|
||||||
|
function getScript(script, callback) {
|
||||||
|
console.log('Loading script: ' + script);
|
||||||
|
$.getScript(base_path + script).done(function () {
|
||||||
|
callback();
|
||||||
|
}).fail(function (jqxhr, settings, exception) {
|
||||||
|
console.log('Error: ' + exception);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getScriptsInOrder(scripts, callback) {
|
||||||
|
if (scripts.length === 0) {
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
getScript(scripts[0], function() {
|
||||||
|
getScriptsInOrder(scripts.slice(1), callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadScripts(urls, callback) {
|
||||||
|
if( 'function' === typeof importScripts ) {
|
||||||
|
importScripts.apply(null, urls);
|
||||||
|
callback();
|
||||||
|
} else {
|
||||||
|
getScriptsInOrder(urls, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onJSONLoaded () {
|
||||||
|
data = JSON.parse(this.responseText);
|
||||||
|
var scriptsToLoad = ['lunr.js'];
|
||||||
|
if (data.config && data.config.lang && data.config.lang.length) {
|
||||||
|
lang = data.config.lang;
|
||||||
|
}
|
||||||
|
if (lang.length > 1 || lang[0] !== "en") {
|
||||||
|
scriptsToLoad.push('lunr.stemmer.support.js');
|
||||||
|
if (lang.length > 1) {
|
||||||
|
scriptsToLoad.push('lunr.multi.js');
|
||||||
|
}
|
||||||
|
if (lang.includes("ja") || lang.includes("jp")) {
|
||||||
|
scriptsToLoad.push('tinyseg.js');
|
||||||
|
}
|
||||||
|
for (var i=0; i < lang.length; i++) {
|
||||||
|
if (lang[i] != 'en') {
|
||||||
|
scriptsToLoad.push(['lunr', lang[i], 'js'].join('.'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadScripts(scriptsToLoad, onScriptsLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onScriptsLoaded () {
|
||||||
|
console.log('All search scripts loaded, building Lunr index...');
|
||||||
|
if (data.config && data.config.separator && data.config.separator.length) {
|
||||||
|
lunr.tokenizer.separator = new RegExp(data.config.separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.index) {
|
||||||
|
index = lunr.Index.load(data.index);
|
||||||
|
data.docs.forEach(function (doc) {
|
||||||
|
documents[doc.location] = doc;
|
||||||
|
});
|
||||||
|
console.log('Lunr pre-built index loaded, search ready');
|
||||||
|
} else {
|
||||||
|
index = lunr(function () {
|
||||||
|
if (lang.length === 1 && lang[0] !== "en" && lunr[lang[0]]) {
|
||||||
|
this.use(lunr[lang[0]]);
|
||||||
|
} else if (lang.length > 1) {
|
||||||
|
this.use(lunr.multiLanguage.apply(null, lang)); // spread operator not supported in all browsers: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Browser_compatibility
|
||||||
|
}
|
||||||
|
this.field('title');
|
||||||
|
this.field('text');
|
||||||
|
this.ref('location');
|
||||||
|
|
||||||
|
for (var i=0; i < data.docs.length; i++) {
|
||||||
|
var doc = data.docs[i];
|
||||||
|
this.add(doc);
|
||||||
|
documents[doc.location] = doc;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log('Lunr index built, search ready');
|
||||||
|
}
|
||||||
|
allowSearch = true;
|
||||||
|
postMessage({config: data.config});
|
||||||
|
postMessage({allowSearch: allowSearch});
|
||||||
|
}
|
||||||
|
|
||||||
|
function init () {
|
||||||
|
var oReq = new XMLHttpRequest();
|
||||||
|
oReq.addEventListener("load", onJSONLoaded);
|
||||||
|
var index_path = base_path + '/search_index.json';
|
||||||
|
if( 'function' === typeof importScripts ){
|
||||||
|
index_path = 'search_index.json';
|
||||||
|
}
|
||||||
|
oReq.open("GET", index_path);
|
||||||
|
oReq.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function search (query) {
|
||||||
|
if (!allowSearch) {
|
||||||
|
console.error('Assets for search still loading');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultDocuments = [];
|
||||||
|
var results = index.search(query);
|
||||||
|
for (var i=0; i < results.length; i++){
|
||||||
|
var result = results[i];
|
||||||
|
doc = documents[result.ref];
|
||||||
|
doc.summary = doc.text.substring(0, 200);
|
||||||
|
resultDocuments.push(doc);
|
||||||
|
}
|
||||||
|
return resultDocuments;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( 'function' === typeof importScripts ) {
|
||||||
|
onmessage = function (e) {
|
||||||
|
if (e.data.init) {
|
||||||
|
init();
|
||||||
|
} else if (e.data.query) {
|
||||||
|
postMessage({ results: search(e.data.query) });
|
||||||
|
} else {
|
||||||
|
console.error("Worker - Unrecognized message: " + e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
271
server_config/index.html
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" data-bs-theme="dark">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<link rel="shortcut icon" href="../img/favicon.ico">
|
||||||
|
<title>Server-side Config - Documentation for TurnBasedMinecraftMod</title>
|
||||||
|
<link href="../css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<link href="../css/fontawesome.min.css" rel="stylesheet">
|
||||||
|
<link href="../css/brands.min.css" rel="stylesheet">
|
||||||
|
<link href="../css/solid.min.css" rel="stylesheet">
|
||||||
|
<link href="../css/v4-font-face.min.css" rel="stylesheet">
|
||||||
|
<link href="../css/base.css" rel="stylesheet">
|
||||||
|
<link id="hljs-light" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css" disabled>
|
||||||
|
<link id="hljs-dark" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github-dark.min.css" >
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
|
||||||
|
<script>hljs.highlightAll();</script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand" href="..">Documentation for TurnBasedMinecraftMod</a>
|
||||||
|
<!-- Expander button -->
|
||||||
|
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#navbar-collapse" aria-controls="navbar-collapse" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Expanded navigation -->
|
||||||
|
<div id="navbar-collapse" class="navbar-collapse collapse">
|
||||||
|
<!-- Main navigation -->
|
||||||
|
<ul class="nav navbar-nav">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href=".." class="nav-link">TurnBasedMinecraftMod</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="../client_config/" class="nav-link">Client-side Config</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="./" class="nav-link active" aria-current="page">Server-side Config</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<ul class="nav navbar-nav ms-md-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a href="#" class="nav-link" data-bs-toggle="modal" data-bs-target="#mkdocs_search_modal">
|
||||||
|
<i class="fa fa-search"></i> Search
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a rel="prev" href="../client_config/" class="nav-link">
|
||||||
|
<i class="fa fa-arrow-left"></i> Previous
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a rel="next" class="nav-link disabled">
|
||||||
|
Next <i class="fa fa-arrow-right"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<button id="theme-menu" aria-expanded="false" data-bs-toggle="dropdown" data-bs-display="static" aria-label="Toggle theme" class="nav-link dropdown-toggle">
|
||||||
|
<i class="fa-solid fa-circle-half-stroke fa-fw"></i>
|
||||||
|
<span class="d-lg-none ms-2">Toggle theme</span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="light" aria-pressed="false">
|
||||||
|
<i class="fa-solid fa-sun fa-fw"></i>
|
||||||
|
<span class="ms-2">Light</span>
|
||||||
|
<i class="fa-solid fa-check ms-auto d-none"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="dark" aria-pressed="true">
|
||||||
|
<i class="fa-solid fa-moon fa-fw"></i>
|
||||||
|
<span class="ms-2">Dark</span>
|
||||||
|
<i class="fa-solid fa-check ms-auto"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<button class="dropdown-item d-flex align-items-center" data-bs-theme-value="auto" aria-pressed="false">
|
||||||
|
<i class="fa-solid fa-circle-half-stroke fa-fw"></i>
|
||||||
|
<span class="ms-2">Auto</span>
|
||||||
|
<i class="fa-solid fa-check ms-auto d-none"></i>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="../js/darkmode.js"></script>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-3"><div class="navbar-expand-md bs-sidebar hidden-print affix" role="complementary">
|
||||||
|
<div class="navbar-header">
|
||||||
|
<button type="button" class="navbar-toggler collapsed" data-bs-toggle="collapse" data-bs-target="#toc-collapse" title="Table of Contents">
|
||||||
|
<span class="fa fa-angle-down"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="toc-collapse" class="navbar-collapse collapse card bg-body-tertiary">
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
|
||||||
|
<li class="nav-item" data-bs-level="1"><a href="#server-side-config" class="nav-link">Server-side Config</a>
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
<li class="nav-item" data-bs-level="2"><a href="#per-mob-settings" class="nav-link">Per-Mob Settings</a>
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" data-bs-level="2"><a href="#custom-name-settings" class="nav-link">Custom Name Settings</a>
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" data-bs-level="2"><a href="#other-things-to-know" class="nav-link">Other Things to Know</a>
|
||||||
|
<ul class="nav flex-column">
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
<div class="col-md-9" role="main">
|
||||||
|
|
||||||
|
<h1 id="server-side-config">Server-side Config</h1>
|
||||||
|
<p>Invoke <code>/tbm-server-edit</code> to print out server settings to the "chat" area.</p>
|
||||||
|
<p><img alt="tbm-server-edit output" src="../tbm-server-edit-full.png" /></p>
|
||||||
|
<p>In this text area, yellow texts are setting names, green texts are setting
|
||||||
|
values that can be set when clicked on, and dark-green texts are settings that
|
||||||
|
display more settings when clicked on.</p>
|
||||||
|
<p>You can hover/click these texts by pressing the "t" key to open the chatbox, and
|
||||||
|
using the mouse.</p>
|
||||||
|
<p><img alt="tbm-server-edit info when hovered" src="../tbm-server-edit-hover.png" /></p>
|
||||||
|
<p><img alt="tbm-server-edit output when haste-speed is set" src="../tbm-server-edit-set-haste.png" /></p>
|
||||||
|
<p>When clicking on the dark-green texts, a description and list is shown. You can
|
||||||
|
hover over the text to show what actions may occur when clicked.</p>
|
||||||
|
<p><img alt="tbm-server-edit ignore-damage-sources
|
||||||
|
output" src="../tbm-server-edit-damage-sources.png" /></p>
|
||||||
|
<p>On click, the action taken will be shown.</p>
|
||||||
|
<p><img alt="tbm-server-edit ignore-damage-sources
|
||||||
|
modified" src="../tbm-server-edit-damage-sources-set.png" /></p>
|
||||||
|
<p>It is also possible to set config settings via a command, but it is recommended
|
||||||
|
to use the "click-on-chat" interface for general server config settings.</p>
|
||||||
|
<h2 id="per-mob-settings">Per-Mob Settings</h2>
|
||||||
|
<p>To demonstrate setting "per-mob" settings, it will be shown how to do so with
|
||||||
|
sheep.</p>
|
||||||
|
<p><img alt="sheep" src="../tbm-edit-sheep.jpg" /></p>
|
||||||
|
<p>Invoke <code>/tbm-edit</code>. Some helpful text will show.</p>
|
||||||
|
<p><img alt="/tbm-edit output" src="../tbm-edit-output.jpg" /></p>
|
||||||
|
<p>At this point, TBMM (TurnBasedMinecraftMod) will be keeping track of who you
|
||||||
|
will attack next, so that you can edit their settings. Currently this only
|
||||||
|
applies to mobs like sheep, zombies, skeletons, bees, etc. This is done so that
|
||||||
|
you can physically select the mob you want to "edit".</p>
|
||||||
|
<p><img alt="mob settings" src="../tbm-edit-settings.jpg" /></p>
|
||||||
|
<p>In this example, the "AE" (attack effect) setting will be changed to
|
||||||
|
"levitation", which will cause the sheep to make the player levitate 50% of the
|
||||||
|
time.</p>
|
||||||
|
<p><img alt="mob setting attack effect levitation" src="../tbm-edit-levitation.png" /></p>
|
||||||
|
<p>Also, "DecisionAttack" will be set to 100%, so that the sheep will choose to
|
||||||
|
attack instead of fleeing battle.</p>
|
||||||
|
<p><img alt="mob setting decision attack 100%" src="../tbm-edit-decision-attack.png" /></p>
|
||||||
|
<p>Make sure to click on "Finished Editing" to save changes to the server-side
|
||||||
|
config.</p>
|
||||||
|
<p>Note that for sheep to enter battle, they must be removed from the "ignore
|
||||||
|
battle categories" setting (remove the "passive" category).</p>
|
||||||
|
<p><img alt="server edit remove passive from ignore
|
||||||
|
categories" src="../tbm-edit-server-edit-ignore-battle-types.png" /></p>
|
||||||
|
<p>Now, sheep will attack and cause "levitation" 50% of the time.</p>
|
||||||
|
<p><img alt="after battle with levitation effect" src="../tbm-edit-post-battle.jpg" /></p>
|
||||||
|
<h2 id="custom-name-settings">Custom Name Settings</h2>
|
||||||
|
<p>Additional entries can be added to the server-side config that applies to mobs
|
||||||
|
named with a specific name (like with a name-tag). Name a mob, then invoke
|
||||||
|
<code>/tbm-edit custom</code>.</p>
|
||||||
|
<p><img alt="tbm-edit custom command" src="../tbm-edit-custom.png" /></p>
|
||||||
|
<p>Hit the named mob to start the editing process.</p>
|
||||||
|
<p><img alt="tbm-edit custom editing" src="../tbm-edit-custom-editing.jpg" /></p>
|
||||||
|
<p>Make your changes and click on "Finished Editing", and any mob with that exact
|
||||||
|
name will have these battle settings applied. Note that these settings are also
|
||||||
|
in the server-side config.</p>
|
||||||
|
<h2 id="other-things-to-know">Other Things to Know</h2>
|
||||||
|
<p>Sometimes a mod update will "reset" the settings in the server-config to
|
||||||
|
defaults. This is due to new mob entries in the settings. Check the
|
||||||
|
<code>.minecraft/config</code> folder (or <code>config</code> folder on the server) to see that the
|
||||||
|
old settings file was renamed and the new settings file is in its place. You may
|
||||||
|
have to compare the files to keep the settings you want.</p></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer class="col-md-12">
|
||||||
|
<hr>
|
||||||
|
<p>Documentation built with <a href="https://www.mkdocs.org/">MkDocs</a>.</p>
|
||||||
|
</footer>
|
||||||
|
<script src="../js/bootstrap.bundle.min.js"></script>
|
||||||
|
<script>
|
||||||
|
var base_url = "..",
|
||||||
|
shortcuts = {"help": 191, "next": 78, "previous": 80, "search": 83};
|
||||||
|
</script>
|
||||||
|
<script src="../js/base.js"></script>
|
||||||
|
<script src="../search/main.js"></script>
|
||||||
|
|
||||||
|
<div class="modal" id="mkdocs_search_modal" tabindex="-1" role="dialog" aria-labelledby="searchModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="searchModalLabel">Search</h4>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p>From here you can search these documents. Enter your search terms below.</p>
|
||||||
|
<form>
|
||||||
|
<div class="form-group">
|
||||||
|
<input type="search" class="form-control" placeholder="Search..." id="mkdocs-search-query" title="Type search term here">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<div id="mkdocs-search-results" data-no-results-text="No results found"></div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div><div class="modal" id="mkdocs_keyboard_modal" tabindex="-1" role="dialog" aria-labelledby="keyboardModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title" id="keyboardModalLabel">Keyboard Shortcuts</h4>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width: 20%;">Keys</th>
|
||||||
|
<th>Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td class="help shortcut"><kbd>?</kbd></td>
|
||||||
|
<td>Open this help</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="next shortcut"><kbd>n</kbd></td>
|
||||||
|
<td>Next page</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="prev shortcut"><kbd>p</kbd></td>
|
||||||
|
<td>Previous page</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="search shortcut"><kbd>s</kbd></td>
|
||||||
|
<td>Search</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -1,15 +0,0 @@
|
||||||
pluginManagement {
|
|
||||||
repositories {
|
|
||||||
mavenLocal()
|
|
||||||
gradlePluginPortal()
|
|
||||||
maven {
|
|
||||||
url = 'https://maven.neoforged.net/releases'
|
|
||||||
}
|
|
||||||
jcenter()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.8.0'
|
|
||||||
}
|
|
3
sitemap.xml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
</urlset>
|
BIN
sitemap.xml.gz
Normal file
|
@ -1,439 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.client;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.Battle;
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.Combatant;
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.Config;
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketBattleDecision;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import net.minecraft.client.gui.components.AbstractButton;
|
|
||||||
import net.minecraft.client.gui.components.Button;
|
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
|
||||||
import net.minecraft.client.gui.screens.inventory.InventoryScreen;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
|
||||||
import net.neoforged.neoforge.network.PacketDistributor;
|
|
||||||
|
|
||||||
import java.util.ConcurrentModificationException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
public class BattleGui extends Screen {
|
|
||||||
private AtomicInteger timeRemaining;
|
|
||||||
|
|
||||||
private int timerMax;
|
|
||||||
private boolean turnTimerEnabled;
|
|
||||||
private long lastInstant;
|
|
||||||
private long elapsedTime;
|
|
||||||
private MenuState state;
|
|
||||||
private boolean stateChanged;
|
|
||||||
private String info;
|
|
||||||
private Long waitMissingBattleTicks;
|
|
||||||
private boolean showingEntities;
|
|
||||||
|
|
||||||
private enum MenuState {
|
|
||||||
MAIN_MENU(0), ATTACK_TARGET(1), ITEM_ACTION(2), WAITING(3), SWITCH_ITEM(4), USE_ITEM(5);
|
|
||||||
|
|
||||||
private int value;
|
|
||||||
|
|
||||||
MenuState(int value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Map<Integer, MenuState> map;
|
|
||||||
|
|
||||||
static {
|
|
||||||
map = new HashMap<Integer, MenuState>();
|
|
||||||
for (MenuState state : MenuState.values()) {
|
|
||||||
map.put(state.getValue(), state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MenuState valueOf(int value) {
|
|
||||||
return map.get(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private enum ButtonAction {
|
|
||||||
ATTACK(0), DEFEND(1), ITEM(2), FLEE(3), ATTACK_TARGET(4), SWITCH_HELD_ITEM(5), DECIDE_USE_ITEM(6), CANCEL(7),
|
|
||||||
DO_ITEM_SWITCH(8), DO_USE_ITEM(9);
|
|
||||||
|
|
||||||
private int value;
|
|
||||||
|
|
||||||
ButtonAction(int value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getValue() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Map<Integer, ButtonAction> map;
|
|
||||||
static {
|
|
||||||
map = new HashMap<Integer, ButtonAction>();
|
|
||||||
for (ButtonAction action : ButtonAction.values()) {
|
|
||||||
map.put(action.getValue(), action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ButtonAction valueOf(int value) {
|
|
||||||
return map.get(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BattleGui() {
|
|
||||||
super(Component.literal("Battle Gui"));
|
|
||||||
timeRemaining = new AtomicInteger((int) (Config.BATTLE_DECISION_DURATION_NANO_DEFAULT / 1000000000L));
|
|
||||||
timerMax = timeRemaining.get();
|
|
||||||
lastInstant = System.nanoTime();
|
|
||||||
elapsedTime = 0;
|
|
||||||
state = MenuState.MAIN_MENU;
|
|
||||||
stateChanged = true;
|
|
||||||
waitMissingBattleTicks = null;
|
|
||||||
showingEntities = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setState(MenuState state) {
|
|
||||||
this.state = state;
|
|
||||||
stateChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void turnBegin() {
|
|
||||||
if (TurnBasedMinecraftMod.proxy.getLocalBattle() != null) {
|
|
||||||
TurnBasedMinecraftMod.proxy.getLocalBattle().setState(Battle.State.ACTION);
|
|
||||||
}
|
|
||||||
setState(MenuState.WAITING);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void turnEnd() {
|
|
||||||
if (TurnBasedMinecraftMod.proxy.getLocalBattle() != null) {
|
|
||||||
TurnBasedMinecraftMod.proxy.getLocalBattle().setState(Battle.State.DECISION);
|
|
||||||
}
|
|
||||||
timeRemaining.set(timerMax);
|
|
||||||
elapsedTime = 0;
|
|
||||||
lastInstant = System.nanoTime();
|
|
||||||
setState(MenuState.MAIN_MENU);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void battleChanged() {
|
|
||||||
stateChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateState() {
|
|
||||||
if (!stateChanged) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
stateChanged = false;
|
|
||||||
showingEntities = false;
|
|
||||||
clearWidgets();
|
|
||||||
switch (state) {
|
|
||||||
case MAIN_MENU:
|
|
||||||
info = "What will you do?";
|
|
||||||
addRenderableWidget(Button.builder(Component.literal("Attack"), (button) -> {
|
|
||||||
buttonActionEvent(button, ButtonAction.ATTACK);
|
|
||||||
}).bounds(width * 3 / 7 - 25, 40, 50, 20).build());
|
|
||||||
addRenderableWidget(Button.builder(Component.literal("Defend"), (button) -> {
|
|
||||||
buttonActionEvent(button, ButtonAction.DEFEND);
|
|
||||||
}).bounds(width * 4 / 7 - 25, 40, 50, 20).build());
|
|
||||||
addRenderableWidget(Button.builder(Component.literal("Item"), (button) -> {
|
|
||||||
buttonActionEvent(button, ButtonAction.ITEM);
|
|
||||||
}).bounds(width * 3 / 7 - 25, 60, 50, 20).build());
|
|
||||||
addRenderableWidget(Button.builder(Component.literal("Flee"), (button) -> {
|
|
||||||
buttonActionEvent(button, ButtonAction.FLEE);
|
|
||||||
}).bounds(width * 4 / 7 - 25, 60, 50, 20).build());
|
|
||||||
break;
|
|
||||||
case ATTACK_TARGET:
|
|
||||||
info = "Who will you attack?";
|
|
||||||
int y = 30;
|
|
||||||
showingEntities = true;
|
|
||||||
try {
|
|
||||||
for (Map.Entry<Integer, Combatant> e : TurnBasedMinecraftMod.proxy.getLocalBattle()
|
|
||||||
.getSideAEntrySet()) {
|
|
||||||
if (e.getValue().entity != null) {
|
|
||||||
addRenderableWidget(new EntitySelectionButton(width / 4 - 60, y, 120, 20, e.getValue().entity.getDisplayName(), e.getKey(), true, (button) -> {
|
|
||||||
entityButtonActionEvent(button, ButtonAction.ATTACK_TARGET);
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
addRenderableWidget(new EntitySelectionButton(width / 4 - 60, y, 120, 20, "Unknown", e.getKey(), true, (button) -> {
|
|
||||||
entityButtonActionEvent(button, ButtonAction.ATTACK_TARGET);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
y += 20;
|
|
||||||
}
|
|
||||||
} catch (ConcurrentModificationException e) {
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
y = 30;
|
|
||||||
try {
|
|
||||||
for (Map.Entry<Integer, Combatant> e : TurnBasedMinecraftMod.proxy.getLocalBattle()
|
|
||||||
.getSideBEntrySet()) {
|
|
||||||
if (e.getValue().entity != null) {
|
|
||||||
addRenderableWidget(new EntitySelectionButton(width * 3 / 4 - 60, y, 120, 20, e.getValue().entity.getDisplayName(), e.getKey(), false, (button) -> {
|
|
||||||
entityButtonActionEvent(button, ButtonAction.ATTACK_TARGET);
|
|
||||||
}));
|
|
||||||
} else {
|
|
||||||
addRenderableWidget(new EntitySelectionButton(width * 3 / 4 - 60, y, 120, 20, "Unknown", e.getKey(), false, (button) -> {
|
|
||||||
entityButtonActionEvent(button, ButtonAction.ATTACK_TARGET);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
y += 20;
|
|
||||||
}
|
|
||||||
} catch (ConcurrentModificationException e) {
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
addRenderableWidget(Button.builder(Component.literal("Cancel"), (button) -> {
|
|
||||||
buttonActionEvent(button, ButtonAction.CANCEL);
|
|
||||||
}).bounds(width / 2 - 30, height - 120, 60, 20).build());
|
|
||||||
break;
|
|
||||||
case ITEM_ACTION:
|
|
||||||
info = "What will you do with an item?";
|
|
||||||
addRenderableWidget(Button.builder(Component.literal("Switch Held"), (button) -> {
|
|
||||||
buttonActionEvent(button, ButtonAction.SWITCH_HELD_ITEM);
|
|
||||||
}).bounds(width / 4 - 40, height - 120, 80, 20).build());
|
|
||||||
addRenderableWidget(Button.builder(Component.literal("Use"), (button) -> {
|
|
||||||
buttonActionEvent(button, ButtonAction.DECIDE_USE_ITEM);
|
|
||||||
}).bounds(width * 2 / 4 - 40, height - 120, 80, 20).build());
|
|
||||||
addRenderableWidget(Button.builder(Component.literal("Cancel"), (button) -> {
|
|
||||||
buttonActionEvent(button, ButtonAction.CANCEL);
|
|
||||||
}).bounds(width * 3 / 4 - 40, height - 120, 80, 20).build());
|
|
||||||
break;
|
|
||||||
case WAITING:
|
|
||||||
info = "Waiting...";
|
|
||||||
break;
|
|
||||||
case SWITCH_ITEM:
|
|
||||||
info = "To which item will you switch to?";
|
|
||||||
for (int i = 0; i < 9; ++i) {
|
|
||||||
addRenderableWidget(new ItemSelectionButton(width / 2 - 88 + i * 20, height - 19, 16, 16, i, (button) -> {
|
|
||||||
itemButtonActionEvent(button, ButtonAction.DO_ITEM_SWITCH);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
addRenderableWidget(Button.builder(Component.literal("Cancel"), (button) -> {
|
|
||||||
buttonActionEvent(button, ButtonAction.CANCEL);
|
|
||||||
}).bounds(width / 2 - 40, height - 120, 80, 20).build());
|
|
||||||
break;
|
|
||||||
case USE_ITEM:
|
|
||||||
info = "Which item will you use?";
|
|
||||||
for (int i = 0; i < 9; ++i) {
|
|
||||||
addRenderableWidget(new ItemSelectionButton(width / 2 - 88 + i * 20, height - 19, 16, 16, i, (button) -> {
|
|
||||||
itemButtonActionEvent(button, ButtonAction.DO_USE_ITEM);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
addRenderableWidget(Button.builder(Component.literal("Cancel"), (button) -> {
|
|
||||||
buttonActionEvent(button, ButtonAction.CANCEL);
|
|
||||||
}).bounds(width / 2 - 40, height - 120, 80, 20).build());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int colorFromTicks(final Long ticks) {
|
|
||||||
if (ticks < 20 * 10) {
|
|
||||||
double value = (20 * 10 - ticks.intValue()) / (20.0 * 10.0);
|
|
||||||
return 0xFF0000FF | (((int)(value * 255.0)) << 8) | (((int)(value * 255.0)) << 16);
|
|
||||||
} else {
|
|
||||||
return 0xFF0000FF;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) {
|
|
||||||
if (TurnBasedMinecraftMod.proxy.getLocalBattle() == null) {
|
|
||||||
if (waitMissingBattleTicks == null) {
|
|
||||||
waitMissingBattleTicks = 0L;
|
|
||||||
} else {
|
|
||||||
waitMissingBattleTicks += 1L;
|
|
||||||
}
|
|
||||||
// drawHoveringText("Waiting...", width / 2 - 50, height / 2);
|
|
||||||
drawString(guiGraphics, "Waiting...", width / 2 - 50, height / 2, colorFromTicks(waitMissingBattleTicks));
|
|
||||||
super.render(guiGraphics, mouseX, mouseY, partialTicks);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
waitMissingBattleTicks = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TurnBasedMinecraftMod.proxy.getLocalBattle().getState() == Battle.State.DECISION
|
|
||||||
&& timeRemaining.get() > 0) {
|
|
||||||
long nextInstant = System.nanoTime();
|
|
||||||
elapsedTime += nextInstant - lastInstant;
|
|
||||||
lastInstant = nextInstant;
|
|
||||||
while (elapsedTime > 1000000000) {
|
|
||||||
elapsedTime -= 1000000000;
|
|
||||||
timeRemaining.decrementAndGet();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
updateState();
|
|
||||||
if (showingEntities) {
|
|
||||||
int y = 30;
|
|
||||||
try {
|
|
||||||
for (Map.Entry<Integer, Combatant> e : TurnBasedMinecraftMod.proxy.getLocalBattle().getSideAEntrySet()) {
|
|
||||||
if (e.getValue().entity instanceof LivingEntity lEntity) {
|
|
||||||
InventoryScreen.renderEntityInInventoryFollowsMouse(guiGraphics, width / 4 - 60 - 20, y, width / 4 - 60, y + 20, 7, 0.0F, mouseX, mouseY, lEntity);
|
|
||||||
}
|
|
||||||
y += 20;
|
|
||||||
}
|
|
||||||
} catch(ConcurrentModificationException e) {}
|
|
||||||
y = 30;
|
|
||||||
try {
|
|
||||||
for (Map.Entry<Integer, Combatant> e : TurnBasedMinecraftMod.proxy.getLocalBattle().getSideBEntrySet()) {
|
|
||||||
if (e.getValue().entity instanceof LivingEntity lEntity) {
|
|
||||||
InventoryScreen.renderEntityInInventoryFollowsMouse(guiGraphics, width * 3 / 4 - 60 + 120, y, width * 3 / 4 - 60 + 140, y + 20, 7, 0.0F, mouseX, mouseY, lEntity);
|
|
||||||
}
|
|
||||||
y += 20;
|
|
||||||
}
|
|
||||||
} catch(ConcurrentModificationException e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.render(guiGraphics, mouseX, mouseY, partialTicks);
|
|
||||||
|
|
||||||
String timeRemainingString = "Time remaining: ";
|
|
||||||
int timeRemainingInt = timeRemaining.get();
|
|
||||||
if (timeRemainingInt > 8 || !turnTimerEnabled) {
|
|
||||||
timeRemainingString += "\u00A7a";
|
|
||||||
} else if (timeRemainingInt > 4) {
|
|
||||||
timeRemainingString += "\u00A7e";
|
|
||||||
} else {
|
|
||||||
timeRemainingString += "\u00A7c";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!turnTimerEnabled) {
|
|
||||||
timeRemainingString += "Infinity";
|
|
||||||
} else {
|
|
||||||
timeRemainingString += Integer.toString(timeRemainingInt);
|
|
||||||
}
|
|
||||||
int stringWidth = font.width(timeRemainingString);
|
|
||||||
guiGraphics.fill(width / 2 - stringWidth / 2, 5, width / 2 + stringWidth / 2, 15, 0x70000000);
|
|
||||||
drawString(guiGraphics, timeRemainingString, width / 2 - stringWidth / 2, 5, 0xFFFFFFFF);
|
|
||||||
stringWidth = font.width(info);
|
|
||||||
guiGraphics.fill(width / 2 - stringWidth / 2, 20, width / 2 + stringWidth / 2, 30, 0x70000000);
|
|
||||||
drawString(guiGraphics, info, width / 2 - stringWidth / 2, 20, 0xFFFFFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void buttonActionEvent(AbstractButton button, ButtonAction action) {
|
|
||||||
switch (action) {
|
|
||||||
case ATTACK:
|
|
||||||
setState(MenuState.ATTACK_TARGET);
|
|
||||||
break;
|
|
||||||
case DEFEND:
|
|
||||||
PacketDistributor.sendToServer(new PacketBattleDecision(
|
|
||||||
TurnBasedMinecraftMod.proxy.getLocalBattle().getId(), Battle.Decision.DEFEND.getValue(), 0));
|
|
||||||
setState(MenuState.WAITING);
|
|
||||||
break;
|
|
||||||
case ITEM:
|
|
||||||
setState(MenuState.ITEM_ACTION);
|
|
||||||
break;
|
|
||||||
case FLEE:
|
|
||||||
PacketDistributor.sendToServer(new PacketBattleDecision(
|
|
||||||
TurnBasedMinecraftMod.proxy.getLocalBattle().getId(), Battle.Decision.FLEE.getValue(), 0));
|
|
||||||
setState(MenuState.WAITING);
|
|
||||||
break;
|
|
||||||
case ATTACK_TARGET:
|
|
||||||
// Invalid, but set menu to main menu anyways.
|
|
||||||
setState(MenuState.MAIN_MENU);
|
|
||||||
break;
|
|
||||||
case SWITCH_HELD_ITEM:
|
|
||||||
setState(MenuState.SWITCH_ITEM);
|
|
||||||
break;
|
|
||||||
case DECIDE_USE_ITEM:
|
|
||||||
setState(MenuState.USE_ITEM);
|
|
||||||
break;
|
|
||||||
case CANCEL:
|
|
||||||
setState(MenuState.MAIN_MENU);
|
|
||||||
break;
|
|
||||||
case DO_ITEM_SWITCH:
|
|
||||||
// Invalid, but set menu to main menu anyways.
|
|
||||||
setState(MenuState.MAIN_MENU);
|
|
||||||
break;
|
|
||||||
case DO_USE_ITEM:
|
|
||||||
// Invalid, but set menu to main menu anyways.
|
|
||||||
setState(MenuState.MAIN_MENU);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void entityButtonActionEvent(EntitySelectionButton button, ButtonAction action) {
|
|
||||||
if (action.equals(ButtonAction.ATTACK_TARGET)) {
|
|
||||||
PacketDistributor.sendToServer(
|
|
||||||
new PacketBattleDecision(TurnBasedMinecraftMod.proxy.getLocalBattle().getId(),
|
|
||||||
Battle.Decision.ATTACK.getValue(), ((EntitySelectionButton) button).getID()));
|
|
||||||
setState(MenuState.WAITING);
|
|
||||||
} else {
|
|
||||||
setState(MenuState.MAIN_MENU);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void itemButtonActionEvent(ItemSelectionButton button, ButtonAction action) {
|
|
||||||
switch (action) {
|
|
||||||
case DO_ITEM_SWITCH:
|
|
||||||
PacketDistributor.sendToServer(
|
|
||||||
new PacketBattleDecision(TurnBasedMinecraftMod.proxy.getLocalBattle().getId(),
|
|
||||||
Battle.Decision.SWITCH_ITEM.getValue(), button.getID()));
|
|
||||||
if (button.getID() >= 0 && button.getID() < 9) {
|
|
||||||
Minecraft.getInstance().player.getInventory().selected = button.getID();
|
|
||||||
}
|
|
||||||
setState(MenuState.WAITING);
|
|
||||||
break;
|
|
||||||
case DO_USE_ITEM:
|
|
||||||
PacketDistributor.sendToServer(
|
|
||||||
new PacketBattleDecision(TurnBasedMinecraftMod.proxy.getLocalBattle().getId(),
|
|
||||||
Battle.Decision.USE_ITEM.getValue(), button.getID()));
|
|
||||||
setState(MenuState.WAITING);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
setState(MenuState.MAIN_MENU);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPauseScreen() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean keyPressed(int keyCode, int b, int c) {
|
|
||||||
if (getMinecraft().player.isCreative()) {
|
|
||||||
return super.keyPressed(keyCode, b, c);
|
|
||||||
} else if (keyCode == 256) {
|
|
||||||
getMinecraft().setScreen(null);
|
|
||||||
TurnBasedMinecraftMod.proxy.displayString("Leaving GUI, but the battle continues!");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false; // TODO verify return value
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean keyReleased(int a, int b, int c) {
|
|
||||||
if (getMinecraft().player.isCreative()) {
|
|
||||||
return super.keyReleased(a, b, c);
|
|
||||||
}
|
|
||||||
return false; // TODO verify return value
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTimeRemaining(int remaining) {
|
|
||||||
timeRemaining.set(remaining);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void drawString(GuiGraphics guiGraphics, String string, int x, int y, int color) {
|
|
||||||
guiGraphics.drawString(font, string, x, y, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTurnTimerEnabled(boolean enabled) {
|
|
||||||
turnTimerEnabled = enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTurnTimerMax(int timerMax) {
|
|
||||||
this.timerMax = timerMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderBackground(GuiGraphics p_283688_, int p_296369_, int p_296477_, float p_294317_) {
|
|
||||||
// Prevent graying of background.
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,597 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.client;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
|
|
||||||
import de.jarnbjo.vorbis.VorbisAudioFileReader;
|
|
||||||
import fr.delthas.javamp3.Sound;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
import javax.sound.midi.MidiChannel;
|
|
||||||
import javax.sound.midi.MidiSystem;
|
|
||||||
import javax.sound.midi.MidiUnavailableException;
|
|
||||||
import javax.sound.midi.Sequencer;
|
|
||||||
import javax.sound.sampled.*;
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
public class BattleMusic
|
|
||||||
{
|
|
||||||
private Logger logger;
|
|
||||||
private ArrayList<File> battleMusic;
|
|
||||||
private ArrayList<File> sillyMusic;
|
|
||||||
private boolean initialized;
|
|
||||||
private File nextBattle;
|
|
||||||
private File nextSilly;
|
|
||||||
private Sequencer sequencer;
|
|
||||||
private AudioInputStream wavInputStream;
|
|
||||||
private Clip clip;
|
|
||||||
private boolean playingIsSilly;
|
|
||||||
private boolean isPlaying;
|
|
||||||
private Thread mp3StreamThread;
|
|
||||||
private Thread oggVorbisStreamThread;
|
|
||||||
private MP3Streamer mp3StreamRunnable;
|
|
||||||
private OGGVorbisStreamer oggVorbisStreamRunnable;
|
|
||||||
|
|
||||||
public BattleMusic(Logger logger)
|
|
||||||
{
|
|
||||||
initialized = false;
|
|
||||||
this.logger = logger;
|
|
||||||
battleMusic = new ArrayList<File>();
|
|
||||||
sillyMusic = new ArrayList<File>();
|
|
||||||
isPlaying = false;
|
|
||||||
mp3StreamThread = null;
|
|
||||||
mp3StreamRunnable = null;
|
|
||||||
|
|
||||||
// try {
|
|
||||||
// sequencer = MidiSystem.getSequencer();
|
|
||||||
// sequencer.open();
|
|
||||||
// } catch (Throwable t) {
|
|
||||||
// logger.error("Failed to load midi sequencer");
|
|
||||||
// t.printStackTrace();
|
|
||||||
// sequencer = null;
|
|
||||||
// }
|
|
||||||
sequencer = null; // midi disabled
|
|
||||||
|
|
||||||
File battleMusicFolder = new File(TurnBasedMinecraftMod.MUSIC_BATTLE);
|
|
||||||
File sillyMusicFolder = new File(TurnBasedMinecraftMod.MUSIC_SILLY);
|
|
||||||
|
|
||||||
if(!battleMusicFolder.exists())
|
|
||||||
{
|
|
||||||
if(!battleMusicFolder.mkdirs())
|
|
||||||
{
|
|
||||||
logger.error("Failed to create " + TurnBasedMinecraftMod.MUSIC_BATTLE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!sillyMusicFolder.exists())
|
|
||||||
{
|
|
||||||
if(!sillyMusicFolder.mkdirs())
|
|
||||||
{
|
|
||||||
logger.error("Failed to create " + TurnBasedMinecraftMod.MUSIC_SILLY);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
File[] battleFiles = battleMusicFolder.listFiles(new FilenameFilter() {
|
|
||||||
@Override
|
|
||||||
public boolean accept(File dir, String name)
|
|
||||||
{
|
|
||||||
int extIndex = name.lastIndexOf(".");
|
|
||||||
if(extIndex == -1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String ext = name.substring(extIndex + 1).toLowerCase();
|
|
||||||
// return ext.equals("mid") || ext.equals("wav") || ext.equals("mp3");
|
|
||||||
return ext.equals("wav") || ext.equals("mp3") || ext.equals("ogg"); // midi disabled
|
|
||||||
}
|
|
||||||
});
|
|
||||||
for(File f : battleFiles)
|
|
||||||
{
|
|
||||||
battleMusic.add(f);
|
|
||||||
}
|
|
||||||
logger.info("Got " + battleMusic.size() + " battle music files");
|
|
||||||
|
|
||||||
File[] sillyFiles = sillyMusicFolder.listFiles(new FilenameFilter() {
|
|
||||||
@Override
|
|
||||||
public boolean accept(File dir, String name)
|
|
||||||
{
|
|
||||||
int extIndex = name.lastIndexOf(".");
|
|
||||||
if(extIndex == -1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String ext = name.substring(extIndex + 1).toLowerCase();
|
|
||||||
// return ext.equals("mid") || ext.equals("wav") || ext.equals("mp3");
|
|
||||||
return ext.equals("wav") || ext.equals("mp3") || ext.equals("ogg"); // midi disabled
|
|
||||||
}
|
|
||||||
});
|
|
||||||
for(File f : sillyFiles)
|
|
||||||
{
|
|
||||||
sillyMusic.add(f);
|
|
||||||
}
|
|
||||||
logger.info("Got " + sillyMusic.size() + " silly music files");
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
|
|
||||||
pickNextBattle();
|
|
||||||
pickNextSilly();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void pickNextBattle()
|
|
||||||
{
|
|
||||||
if(!initialized || battleMusic.isEmpty())
|
|
||||||
{
|
|
||||||
nextBattle = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nextBattle = battleMusic.get((int)(Math.random() * battleMusic.size()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void pickNextSilly()
|
|
||||||
{
|
|
||||||
if(!initialized || sillyMusic.isEmpty())
|
|
||||||
{
|
|
||||||
nextSilly = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nextSilly = sillyMusic.get((int)(Math.random() * sillyMusic.size()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void playBattle(float volume)
|
|
||||||
{
|
|
||||||
if(!initialized || volume <= 0.0f || battleMusic.isEmpty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if(volume > 1.0f)
|
|
||||||
{
|
|
||||||
volume = 1.0f;
|
|
||||||
}
|
|
||||||
play(nextBattle, volume, true);
|
|
||||||
pickNextBattle();
|
|
||||||
playingIsSilly = false;
|
|
||||||
isPlaying = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void playSilly(float volume)
|
|
||||||
{
|
|
||||||
if(!initialized || volume <= 0.0f || sillyMusic.isEmpty())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if(volume > 1.0f)
|
|
||||||
{
|
|
||||||
volume = 1.0f;
|
|
||||||
}
|
|
||||||
play(nextSilly, volume, false);
|
|
||||||
pickNextSilly();
|
|
||||||
playingIsSilly = true;
|
|
||||||
isPlaying = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void play(File next, float volume, boolean isBattleType)
|
|
||||||
{
|
|
||||||
if(initialized && next != null)
|
|
||||||
{
|
|
||||||
logger.debug("play called with file " + next.getName() + " and vol " + volume);
|
|
||||||
TurnBasedMinecraftMod.proxy.pauseMCMusic();
|
|
||||||
String suffix = next.getName().substring(next.getName().length() - 3).toLowerCase();
|
|
||||||
if(suffix.equals("mid") && sequencer != null)
|
|
||||||
{
|
|
||||||
if(sequencer.isRunning())
|
|
||||||
{
|
|
||||||
sequencer.stop();
|
|
||||||
}
|
|
||||||
if(clip != null && clip.isActive())
|
|
||||||
{
|
|
||||||
clip.stop();
|
|
||||||
clip.close();
|
|
||||||
}
|
|
||||||
if(mp3StreamThread != null && mp3StreamThread.isAlive())
|
|
||||||
{
|
|
||||||
mp3StreamRunnable.setKeepPlaying(false);
|
|
||||||
try { mp3StreamThread.join(); } catch (Throwable t) { /* ignored */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
sequencer.setSequence(new BufferedInputStream(new FileInputStream(next)));
|
|
||||||
} catch (Throwable t)
|
|
||||||
{
|
|
||||||
logger.error("Failed to play battle music (midi)");
|
|
||||||
t.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (MidiChannel channel : MidiSystem.getSynthesizer().getChannels()) {
|
|
||||||
channel.controlChange(7, (int)(volume * 127));
|
|
||||||
}
|
|
||||||
} catch (MidiUnavailableException e) {
|
|
||||||
logger.error("Failed to set Midi volume");
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sequencer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
|
|
||||||
sequencer.start();
|
|
||||||
|
|
||||||
logger.info("Played music (midi) " + next.getName());
|
|
||||||
}
|
|
||||||
else if(suffix.equals("wav"))
|
|
||||||
{
|
|
||||||
if(sequencer != null && sequencer.isRunning())
|
|
||||||
{
|
|
||||||
sequencer.stop();
|
|
||||||
}
|
|
||||||
if(clip != null && clip.isActive())
|
|
||||||
{
|
|
||||||
clip.stop();
|
|
||||||
clip.close();
|
|
||||||
}
|
|
||||||
if(mp3StreamThread != null && mp3StreamThread.isAlive())
|
|
||||||
{
|
|
||||||
mp3StreamRunnable.setKeepPlaying(false);
|
|
||||||
try { mp3StreamThread.join(); } catch (Throwable t) { /* ignored */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(wavInputStream != null) {
|
|
||||||
wavInputStream.close();
|
|
||||||
}
|
|
||||||
wavInputStream = AudioSystem.getAudioInputStream(next);
|
|
||||||
AudioFormat format = wavInputStream.getFormat();
|
|
||||||
DataLine.Info info = new DataLine.Info(Clip.class, format);
|
|
||||||
clip = (Clip) AudioSystem.getLine(info);
|
|
||||||
clip.open(wavInputStream);
|
|
||||||
} catch(Throwable t)
|
|
||||||
{
|
|
||||||
logger.error("Failed to play battle music (wav)");
|
|
||||||
t.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set volume
|
|
||||||
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
|
|
||||||
gainControl.setValue(BattleMusic.percentageToDecibels(volume));
|
|
||||||
|
|
||||||
clip.loop(Clip.LOOP_CONTINUOUSLY);
|
|
||||||
clip.start();
|
|
||||||
|
|
||||||
logger.info("Playing music (wav) " + next.getName());
|
|
||||||
}
|
|
||||||
else if(suffix.equals("mp3"))
|
|
||||||
{
|
|
||||||
if(sequencer != null && sequencer.isRunning())
|
|
||||||
{
|
|
||||||
sequencer.stop();
|
|
||||||
}
|
|
||||||
if(clip != null && clip.isActive())
|
|
||||||
{
|
|
||||||
clip.stop();
|
|
||||||
clip.close();
|
|
||||||
}
|
|
||||||
if(mp3StreamThread != null && mp3StreamThread.isAlive())
|
|
||||||
{
|
|
||||||
mp3StreamRunnable.setKeepPlaying(false);
|
|
||||||
try { mp3StreamThread.join(); } catch (Throwable t) { /* ignored */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(mp3StreamRunnable == null)
|
|
||||||
{
|
|
||||||
mp3StreamRunnable = new MP3Streamer(next, logger, volume);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mp3StreamRunnable.setMp3File(next);
|
|
||||||
mp3StreamRunnable.setVolume(volume);
|
|
||||||
}
|
|
||||||
mp3StreamThread = new Thread(mp3StreamRunnable);
|
|
||||||
mp3StreamThread.start();
|
|
||||||
|
|
||||||
logger.info("Started playing mp3 " + next.getName());
|
|
||||||
}
|
|
||||||
catch (Throwable t)
|
|
||||||
{
|
|
||||||
logger.error("Failed to play battle music (mp3)");
|
|
||||||
t.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (suffix.equals("ogg")) {
|
|
||||||
if(sequencer != null && sequencer.isRunning())
|
|
||||||
{
|
|
||||||
sequencer.stop();
|
|
||||||
}
|
|
||||||
if(clip != null && clip.isActive())
|
|
||||||
{
|
|
||||||
clip.stop();
|
|
||||||
clip.close();
|
|
||||||
}
|
|
||||||
if(mp3StreamThread != null && mp3StreamThread.isAlive())
|
|
||||||
{
|
|
||||||
mp3StreamRunnable.setKeepPlaying(false);
|
|
||||||
try { mp3StreamThread.join(); } catch (Throwable t) { /* ignored */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (oggVorbisStreamRunnable == null) {
|
|
||||||
oggVorbisStreamRunnable = new OGGVorbisStreamer(next, logger, volume);
|
|
||||||
} else {
|
|
||||||
oggVorbisStreamRunnable.setOggVorbisFile(next);
|
|
||||||
oggVorbisStreamRunnable.setVolume(volume);
|
|
||||||
}
|
|
||||||
|
|
||||||
oggVorbisStreamThread = new Thread(oggVorbisStreamRunnable);
|
|
||||||
oggVorbisStreamThread.start();
|
|
||||||
logger.info("Started playing OggVorbis " + next.getName());
|
|
||||||
} catch (Throwable t) {
|
|
||||||
logger.error("Failed to play battle music (ogg)");
|
|
||||||
t.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stopMusic(boolean resumeMCSounds)
|
|
||||||
{
|
|
||||||
if(sequencer != null) {
|
|
||||||
sequencer.stop();
|
|
||||||
}
|
|
||||||
if(clip != null) {
|
|
||||||
clip.stop();
|
|
||||||
clip.close();
|
|
||||||
}
|
|
||||||
if(mp3StreamThread != null && mp3StreamThread.isAlive())
|
|
||||||
{
|
|
||||||
mp3StreamRunnable.setKeepPlaying(false);
|
|
||||||
try { mp3StreamThread.join(); } catch (Throwable t) { /* ignored */ }
|
|
||||||
}
|
|
||||||
if (oggVorbisStreamThread != null && oggVorbisStreamThread.isAlive()) {
|
|
||||||
oggVorbisStreamRunnable.setKeepPlaying(false);
|
|
||||||
try { oggVorbisStreamThread.join(); } catch (Throwable t) { /* ignored */ }
|
|
||||||
}
|
|
||||||
if(resumeMCSounds)
|
|
||||||
{
|
|
||||||
TurnBasedMinecraftMod.proxy.resumeMCMusic();
|
|
||||||
}
|
|
||||||
isPlaying = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPlayingSilly()
|
|
||||||
{
|
|
||||||
return playingIsSilly;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPlaying()
|
|
||||||
{
|
|
||||||
return isPlaying || (sequencer != null && sequencer.isRunning()) || (clip != null && clip.isActive());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasBattleMusic()
|
|
||||||
{
|
|
||||||
return !battleMusic.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasSillyMusic()
|
|
||||||
{
|
|
||||||
return !sillyMusic.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Percentage must be between 0 and 1.
|
|
||||||
public static float percentageToDecibels(float percentage) {
|
|
||||||
if (percentage > 1.0F) {
|
|
||||||
return 0.0F;
|
|
||||||
} else if (percentage <= 0.0F) {
|
|
||||||
return Float.NEGATIVE_INFINITY;
|
|
||||||
} else {
|
|
||||||
return (float) (Math.log10(percentage) * 20.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class MP3Streamer implements Runnable
|
|
||||||
{
|
|
||||||
private AtomicBoolean keepPlaying;
|
|
||||||
private File mp3File;
|
|
||||||
private Logger logger;
|
|
||||||
private float volume;
|
|
||||||
|
|
||||||
public MP3Streamer(File mp3File, Logger logger, float volume)
|
|
||||||
{
|
|
||||||
keepPlaying = new AtomicBoolean(true);
|
|
||||||
this.mp3File = mp3File;
|
|
||||||
this.logger = logger;
|
|
||||||
this.volume = volume;
|
|
||||||
if(this.volume > 1.0f)
|
|
||||||
{
|
|
||||||
this.volume = 1.0f;
|
|
||||||
}
|
|
||||||
else if(this.volume < 0.0f)
|
|
||||||
{
|
|
||||||
this.volume = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKeepPlaying(boolean playing)
|
|
||||||
{
|
|
||||||
keepPlaying.set(playing);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMp3File(File mp3File)
|
|
||||||
{
|
|
||||||
this.mp3File = mp3File;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVolume(float volume)
|
|
||||||
{
|
|
||||||
this.volume = volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
keepPlaying.set(true);
|
|
||||||
SourceDataLine sdl = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Sound mp3Sound = new Sound(new FileInputStream(mp3File));
|
|
||||||
AudioFormat audioFormat = mp3Sound.getAudioFormat();
|
|
||||||
sdl = AudioSystem.getSourceDataLine(audioFormat);
|
|
||||||
sdl.open(audioFormat);
|
|
||||||
{
|
|
||||||
FloatControl volumeControl = (FloatControl) sdl.getControl(FloatControl.Type.MASTER_GAIN);
|
|
||||||
volumeControl.setValue(BattleMusic.percentageToDecibels(volume));
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
byte[] cached = null;
|
|
||||||
int cachedOffset = 0;
|
|
||||||
int cachedSize = 0;
|
|
||||||
byte[] buf = new byte[4096];
|
|
||||||
sdl.start();
|
|
||||||
int read = mp3Sound.read(buf, 0, 4096);
|
|
||||||
while(keepPlaying.get())
|
|
||||||
{
|
|
||||||
if(baos != null)
|
|
||||||
{
|
|
||||||
if(read != -1)
|
|
||||||
{
|
|
||||||
sdl.write(buf, 0, read);
|
|
||||||
baos.write(buf, 0, read);
|
|
||||||
read = mp3Sound.read(buf, 0, 4096);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mp3Sound.close();
|
|
||||||
mp3Sound = null;
|
|
||||||
cached = baos.toByteArray();
|
|
||||||
baos = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cachedSize = cached.length - cachedOffset;
|
|
||||||
if(cachedSize > 4096)
|
|
||||||
{
|
|
||||||
cachedSize = 4096;
|
|
||||||
}
|
|
||||||
sdl.write(cached, cachedOffset, cachedSize);
|
|
||||||
cachedOffset += cachedSize;
|
|
||||||
if(cachedOffset >= cached.length)
|
|
||||||
{
|
|
||||||
cachedOffset = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Throwable t)
|
|
||||||
{
|
|
||||||
logger.error("Stream play mp3", t);
|
|
||||||
}
|
|
||||||
if(sdl != null)
|
|
||||||
{
|
|
||||||
sdl.stop();
|
|
||||||
sdl.flush();
|
|
||||||
sdl.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class OGGVorbisStreamer implements Runnable {
|
|
||||||
private AtomicBoolean keepPlaying;
|
|
||||||
private File oggVorbisFile;
|
|
||||||
private Logger logger;
|
|
||||||
private float volume;
|
|
||||||
|
|
||||||
public OGGVorbisStreamer(File oggVorbisFile, Logger logger, float volume) {
|
|
||||||
keepPlaying = new AtomicBoolean(true);
|
|
||||||
this.oggVorbisFile = oggVorbisFile;
|
|
||||||
this.logger = logger;
|
|
||||||
this.volume = volume;
|
|
||||||
if (this.volume > 1.0F) {
|
|
||||||
this.volume = 1.0F;
|
|
||||||
} else if (this.volume < 0.0F) {
|
|
||||||
this.volume = 0.0F;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setKeepPlaying(boolean playing) {
|
|
||||||
keepPlaying.set(playing);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOggVorbisFile(File oggVorbisFile) {
|
|
||||||
this.oggVorbisFile = oggVorbisFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVolume(float volume) {
|
|
||||||
this.volume = volume;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
keepPlaying.set(true);
|
|
||||||
SourceDataLine sdl = null;
|
|
||||||
try {
|
|
||||||
VorbisAudioFileReader reader = new VorbisAudioFileReader();
|
|
||||||
AudioFormat audioFormat = reader.getAudioFileFormat(oggVorbisFile).getFormat();
|
|
||||||
sdl = AudioSystem.getSourceDataLine(audioFormat);
|
|
||||||
sdl.open(audioFormat);
|
|
||||||
{
|
|
||||||
FloatControl volumeControl = (FloatControl) sdl.getControl(FloatControl.Type.MASTER_GAIN);
|
|
||||||
volumeControl.setValue(BattleMusic.percentageToDecibels(volume));
|
|
||||||
}
|
|
||||||
|
|
||||||
AudioInputStream ais = reader.getAudioInputStream(oggVorbisFile);
|
|
||||||
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
byte[] cached = null;
|
|
||||||
int cachedOffset = 0;
|
|
||||||
int cachedSize = 0;
|
|
||||||
byte[] buf = new byte[4096];
|
|
||||||
sdl.start();
|
|
||||||
int read = ais.read(buf);
|
|
||||||
while (keepPlaying.get()) {
|
|
||||||
if (baos != null) {
|
|
||||||
if (read != -1) {
|
|
||||||
sdl.write(buf, 0, read);
|
|
||||||
baos.write(buf, 0, read);
|
|
||||||
read = ais.read(buf);
|
|
||||||
} else {
|
|
||||||
ais.close();
|
|
||||||
ais = null;
|
|
||||||
cached = baos.toByteArray();
|
|
||||||
baos = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cachedSize = cached.length - cachedOffset;
|
|
||||||
if (cachedSize > 4096) {
|
|
||||||
cachedSize = 4096;
|
|
||||||
}
|
|
||||||
sdl.write(cached, cachedOffset, cachedSize);
|
|
||||||
cachedOffset += cachedSize;
|
|
||||||
if (cachedOffset >= cached.length) {
|
|
||||||
cachedOffset = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
|
||||||
logger.error("Stream play oggVorbis", t);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sdl != null) {
|
|
||||||
sdl.stop();
|
|
||||||
sdl.flush();
|
|
||||||
sdl.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.client;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
|
|
||||||
import net.neoforged.neoforge.common.ModConfigSpec;
|
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ClientConfig {
|
|
||||||
public static final ClientConfig CLIENT;
|
|
||||||
public static final ModConfigSpec CLIENT_SPEC;
|
|
||||||
|
|
||||||
static {
|
|
||||||
Pair<ClientConfig, ModConfigSpec> pair =
|
|
||||||
new ModConfigSpec.Builder().configure(ClientConfig::new);
|
|
||||||
CLIENT = pair.getKey();
|
|
||||||
CLIENT_SPEC = pair.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final ModConfigSpec.ConfigValue<List<? extends String>> battleMusicList;
|
|
||||||
public final ModConfigSpec.ConfigValue<List<? extends String>> sillyMusicList;
|
|
||||||
public final ModConfigSpec.DoubleValue sillyMusicThreshold;
|
|
||||||
public final ModConfigSpec.BooleanValue volumeAffectedByMasterVolume;
|
|
||||||
public final ModConfigSpec.BooleanValue volumeAffectedByMusicVolume;
|
|
||||||
public final ModConfigSpec.DoubleValue musicVolume;
|
|
||||||
|
|
||||||
ClientConfig(ModConfigSpec.Builder builder) {
|
|
||||||
//builder.push("music");
|
|
||||||
|
|
||||||
List<String> battleMusicList = new ArrayList<String>(8);
|
|
||||||
battleMusicList.add("monster");
|
|
||||||
battleMusicList.add("animal");
|
|
||||||
battleMusicList.add("boss");
|
|
||||||
battleMusicList.add("player");
|
|
||||||
this.battleMusicList = builder.comment("What categories of mobs that play \"battle\" music")
|
|
||||||
.translation(TurnBasedMinecraftMod.MODID + ".clientconfig.battle_music_list")
|
|
||||||
.defineList("battleMusicList", battleMusicList, (v) -> v instanceof String);
|
|
||||||
|
|
||||||
List<String> sillyMusicList = new ArrayList<String>(4);
|
|
||||||
sillyMusicList.add("passive");
|
|
||||||
this.sillyMusicList = builder.comment("What categories of mobs that play \"silly\" music")
|
|
||||||
.translation(TurnBasedMinecraftMod.MODID + ".clientconfig.silly_music_list")
|
|
||||||
.defineList("sillyMusicList", sillyMusicList, (v) -> true);
|
|
||||||
|
|
||||||
this.sillyMusicThreshold =
|
|
||||||
builder.comment("Minimum percentage of silly entities in battle to use silly music")
|
|
||||||
.translation(TurnBasedMinecraftMod.MODID + ".clientconfig.silly_percentage")
|
|
||||||
.defineInRange("sillyMusicThreshold", 0.4, 0.0, 1.0);
|
|
||||||
|
|
||||||
this.volumeAffectedByMasterVolume = builder.comment(
|
|
||||||
"If \"true\", music volume will be affected by global Master volume setting")
|
|
||||||
.translation(TurnBasedMinecraftMod.MODID + ".clientconfig.volume_affected_by_master")
|
|
||||||
.define("volumeAffectedByMasterVolume", true);
|
|
||||||
|
|
||||||
this.volumeAffectedByMusicVolume = builder.comment(
|
|
||||||
"If \"true\", music volume will be affected by global Music volume setting")
|
|
||||||
.translation(TurnBasedMinecraftMod.MODID + ".clientconfig.volume_affected_by_volume")
|
|
||||||
.define("volumeAffectedByMusicVolume", true);
|
|
||||||
|
|
||||||
this.musicVolume =
|
|
||||||
builder.comment("Volume of battle/silly music as a percentage between 0.0 and 1.0")
|
|
||||||
.translation(TurnBasedMinecraftMod.MODID + ".clientconfig.music_volume")
|
|
||||||
.defineInRange("musicVolume", 0.7, 0.0, 1.0);
|
|
||||||
|
|
||||||
//builder.pop();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,267 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.client;
|
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import net.minecraft.client.gui.components.*;
|
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.neoforged.fml.ModContainer;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ClientConfigGui extends net.minecraft.client.gui.screens.Screen {
|
|
||||||
private final int widget_height = 20;
|
|
||||||
private boolean dirtyFlag;
|
|
||||||
private boolean accepted;
|
|
||||||
private EditBox battleListEditBox = null;
|
|
||||||
private EditBox sillyListEditBox = null;
|
|
||||||
private SliderPercentage sillyMusicThresholdSlider = null;
|
|
||||||
private Checkbox affectedByMasterVolCheckbox = null;
|
|
||||||
private Checkbox affectedByMusicVolCheckbox = null;
|
|
||||||
private SliderPercentage volumeSlider = null;
|
|
||||||
private Screen parentScreen = null;
|
|
||||||
|
|
||||||
public ClientConfigGui(ModContainer container, Screen parent) {
|
|
||||||
super(Component.literal("TurnBasedMC Client Config"));
|
|
||||||
|
|
||||||
dirtyFlag = true;
|
|
||||||
|
|
||||||
accepted = false;
|
|
||||||
|
|
||||||
this.parentScreen = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onDirty() {
|
|
||||||
clearWidgets();
|
|
||||||
|
|
||||||
// Initialize GUI elements.
|
|
||||||
int widget_x_offset = 5;
|
|
||||||
int widget_width = this.width / 2 - widget_x_offset * 2;
|
|
||||||
int top_offset = 5;
|
|
||||||
|
|
||||||
addRenderableWidget(
|
|
||||||
new StringWidget(this.width / 2 - widget_width + widget_x_offset, top_offset,
|
|
||||||
widget_width, widget_height, Component.literal("Battle Music Categories"),
|
|
||||||
font));
|
|
||||||
if (battleListEditBox == null) {
|
|
||||||
battleListEditBox =
|
|
||||||
new EditBox(font, this.width / 2 + widget_x_offset, top_offset, widget_width,
|
|
||||||
widget_height, Component.literal("Battle Music Categories Edit Box"));
|
|
||||||
} else {
|
|
||||||
battleListEditBox.setPosition(this.width / 2 + widget_x_offset, top_offset);
|
|
||||||
battleListEditBox.setSize(widget_width, widget_height);
|
|
||||||
}
|
|
||||||
String tempString = "";
|
|
||||||
for (String category : ClientConfig.CLIENT.battleMusicList.get()) {
|
|
||||||
if (tempString.isEmpty()) {
|
|
||||||
tempString = category;
|
|
||||||
} else {
|
|
||||||
tempString += "," + category;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
battleListEditBox.setMaxLength(128);
|
|
||||||
battleListEditBox.setValue(tempString);
|
|
||||||
addRenderableWidget(battleListEditBox);
|
|
||||||
|
|
||||||
top_offset += widget_height;
|
|
||||||
|
|
||||||
addRenderableWidget(
|
|
||||||
new StringWidget(this.width / 2 - widget_width + widget_x_offset, top_offset,
|
|
||||||
widget_width, widget_height, Component.literal("Silly Music Categories"),
|
|
||||||
font));
|
|
||||||
if (sillyListEditBox == null) {
|
|
||||||
sillyListEditBox =
|
|
||||||
new EditBox(font, this.width / 2 + widget_x_offset, top_offset, widget_width,
|
|
||||||
widget_height, Component.literal("Silly Music Categories Edit Box"));
|
|
||||||
} else {
|
|
||||||
sillyListEditBox.setPosition(this.width / 2 + widget_x_offset, top_offset);
|
|
||||||
sillyListEditBox.setSize(widget_width, widget_height);
|
|
||||||
}
|
|
||||||
tempString = "";
|
|
||||||
for (String category : ClientConfig.CLIENT.sillyMusicList.get()) {
|
|
||||||
if (tempString.isEmpty()) {
|
|
||||||
tempString = category;
|
|
||||||
} else {
|
|
||||||
tempString += "," + category;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sillyListEditBox.setMaxLength(128);
|
|
||||||
sillyListEditBox.setValue(tempString);
|
|
||||||
addRenderableWidget(sillyListEditBox);
|
|
||||||
|
|
||||||
top_offset += widget_height;
|
|
||||||
|
|
||||||
StringWidget stringWidget =
|
|
||||||
new StringWidget(this.width / 2 - widget_width + widget_x_offset, top_offset,
|
|
||||||
widget_width, widget_height, Component.literal("Silly Music Threshold"), font);
|
|
||||||
stringWidget.setTooltip(Tooltip.create(
|
|
||||||
Component.literal("Ratio of minimum of silly mobs in battle to play silly music")));
|
|
||||||
addRenderableWidget(stringWidget);
|
|
||||||
if (sillyMusicThresholdSlider == null) {
|
|
||||||
sillyMusicThresholdSlider =
|
|
||||||
new SliderPercentage(this.width / 2 + widget_x_offset, top_offset, widget_width,
|
|
||||||
widget_height, Component.literal("Silly Music Threshold: " +
|
|
||||||
String.format("%.1f%%", ClientConfig.CLIENT.sillyMusicThreshold.get() * 100.0)),
|
|
||||||
ClientConfig.CLIENT.sillyMusicThreshold.get(), "Silly Music Threshold: ");
|
|
||||||
} else {
|
|
||||||
sillyMusicThresholdSlider.setPosition(this.width / 2 + widget_x_offset, top_offset);
|
|
||||||
sillyMusicThresholdSlider.setSize(widget_width, widget_height);
|
|
||||||
}
|
|
||||||
addRenderableWidget(sillyMusicThresholdSlider);
|
|
||||||
|
|
||||||
top_offset += widget_height;
|
|
||||||
|
|
||||||
stringWidget =
|
|
||||||
new StringWidget(this.width / 2 - widget_width + widget_x_offset, top_offset,
|
|
||||||
widget_width, widget_height, Component.literal("Affected by Master Vol."),
|
|
||||||
font);
|
|
||||||
stringWidget.setTooltip(Tooltip.create(
|
|
||||||
Component.literal("If enabled, volume is affected by global master volume.")));
|
|
||||||
addRenderableWidget(stringWidget);
|
|
||||||
if (affectedByMasterVolCheckbox == null) {
|
|
||||||
affectedByMasterVolCheckbox = Checkbox.builder(Component.literal(""), font)
|
|
||||||
.pos(this.width / 2 + widget_x_offset, top_offset).build();
|
|
||||||
} else {
|
|
||||||
affectedByMasterVolCheckbox.setPosition(this.width / 2 + widget_x_offset,
|
|
||||||
top_offset);
|
|
||||||
}
|
|
||||||
if ((ClientConfig.CLIENT.volumeAffectedByMasterVolume.get() &&
|
|
||||||
!affectedByMasterVolCheckbox.selected()) ||
|
|
||||||
(!ClientConfig.CLIENT.volumeAffectedByMasterVolume.get() &&
|
|
||||||
affectedByMasterVolCheckbox.selected())) {
|
|
||||||
affectedByMasterVolCheckbox.onPress();
|
|
||||||
}
|
|
||||||
addRenderableWidget(affectedByMasterVolCheckbox);
|
|
||||||
|
|
||||||
top_offset += widget_height;
|
|
||||||
|
|
||||||
stringWidget =
|
|
||||||
new StringWidget(this.width / 2 - widget_width + widget_x_offset, top_offset,
|
|
||||||
widget_width, widget_height, Component.literal("Affected by Music Vol."), font);
|
|
||||||
stringWidget.setTooltip(Tooltip.create(
|
|
||||||
Component.literal("If enabled, volume is affected by global music volume.")));
|
|
||||||
addRenderableWidget(stringWidget);
|
|
||||||
if (affectedByMusicVolCheckbox == null) {
|
|
||||||
affectedByMusicVolCheckbox = Checkbox.builder(Component.literal(""), font)
|
|
||||||
.pos(this.width / 2 + widget_x_offset, top_offset).build();
|
|
||||||
} else {
|
|
||||||
affectedByMusicVolCheckbox.setPosition(this.width / 2 + widget_x_offset,
|
|
||||||
top_offset);
|
|
||||||
}
|
|
||||||
if ((ClientConfig.CLIENT.volumeAffectedByMusicVolume.get() &&
|
|
||||||
!affectedByMusicVolCheckbox.selected()) ||
|
|
||||||
(!ClientConfig.CLIENT.volumeAffectedByMusicVolume.get() &&
|
|
||||||
affectedByMusicVolCheckbox.selected())) {
|
|
||||||
affectedByMusicVolCheckbox.onPress();
|
|
||||||
}
|
|
||||||
addRenderableWidget(affectedByMusicVolCheckbox);
|
|
||||||
|
|
||||||
top_offset += widget_height;
|
|
||||||
|
|
||||||
stringWidget =
|
|
||||||
new StringWidget(this.width / 2 - widget_width + widget_x_offset, top_offset,
|
|
||||||
widget_width, widget_height, Component.literal("Music Volume"), font);
|
|
||||||
stringWidget.setTooltip(
|
|
||||||
Tooltip.create(Component.literal("Volume of battle/silly music")));
|
|
||||||
addRenderableWidget(stringWidget);
|
|
||||||
if (volumeSlider == null) {
|
|
||||||
volumeSlider =
|
|
||||||
new SliderPercentage(this.width / 2 + widget_x_offset, top_offset, widget_width,
|
|
||||||
widget_height, Component.literal(
|
|
||||||
"Volume: " + String.format("%.1f%%", ClientConfig.CLIENT.musicVolume.get() * 100.0)),
|
|
||||||
ClientConfig.CLIENT.musicVolume.get(), "Volume: ");
|
|
||||||
} else {
|
|
||||||
volumeSlider.setPosition(this.width / 2 + widget_x_offset, top_offset);
|
|
||||||
volumeSlider.setSize(widget_width, widget_height);
|
|
||||||
}
|
|
||||||
addRenderableWidget(volumeSlider);
|
|
||||||
|
|
||||||
addRenderableWidget(Button.builder(Component.literal("Cancel"),
|
|
||||||
(b) -> Minecraft.getInstance().setScreen(this.parentScreen))
|
|
||||||
.bounds(this.width / 2 - widget_width + widget_x_offset,
|
|
||||||
this.height - widget_height, widget_width, widget_height).build());
|
|
||||||
addRenderableWidget(Button.builder(Component.literal("Accept"), (b) -> {
|
|
||||||
accepted = true;
|
|
||||||
}).bounds(this.width / 2 + widget_x_offset, this.height - widget_height, widget_width,
|
|
||||||
widget_height).build());
|
|
||||||
|
|
||||||
dirtyFlag = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void doAccepted() {
|
|
||||||
String temp = battleListEditBox.getValue();
|
|
||||||
{
|
|
||||||
List<String> battleList = new ArrayList<String>();
|
|
||||||
for (String category : temp.split(",")) {
|
|
||||||
battleList.add(category.strip());
|
|
||||||
}
|
|
||||||
ClientConfig.CLIENT.battleMusicList.set(battleList);
|
|
||||||
}
|
|
||||||
|
|
||||||
temp = sillyListEditBox.getValue();
|
|
||||||
{
|
|
||||||
List<String> sillyList = new ArrayList<String>();
|
|
||||||
for (String category : temp.split(",")) {
|
|
||||||
sillyList.add(category.strip());
|
|
||||||
}
|
|
||||||
ClientConfig.CLIENT.sillyMusicList.set(sillyList);
|
|
||||||
}
|
|
||||||
|
|
||||||
ClientConfig.CLIENT.sillyMusicThreshold.set(sillyMusicThresholdSlider.percentage);
|
|
||||||
|
|
||||||
ClientConfig.CLIENT.volumeAffectedByMasterVolume.set(affectedByMasterVolCheckbox.selected());
|
|
||||||
|
|
||||||
ClientConfig.CLIENT.volumeAffectedByMusicVolume.set(affectedByMusicVolCheckbox.selected());
|
|
||||||
|
|
||||||
ClientConfig.CLIENT.musicVolume.set(volumeSlider.percentage);
|
|
||||||
|
|
||||||
ClientConfig.CLIENT_SPEC.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isPauseScreen() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(GuiGraphics pGuiGraphics, int pMouseX, int pMouseY, float pPartialTick) {
|
|
||||||
if (accepted) {
|
|
||||||
doAccepted();
|
|
||||||
Minecraft.getInstance().setScreen(this.parentScreen);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (dirtyFlag) {
|
|
||||||
onDirty();
|
|
||||||
}
|
|
||||||
super.render(pGuiGraphics, pMouseX, pMouseY, pPartialTick);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void resize(Minecraft pMinecraft, int pWidth, int pHeight) {
|
|
||||||
dirtyFlag = true;
|
|
||||||
super.resize(pMinecraft, pWidth, pHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class SliderPercentage extends AbstractSliderButton {
|
|
||||||
private final String messagePrefix;
|
|
||||||
private double percentage;
|
|
||||||
|
|
||||||
public SliderPercentage(int x, int y, int width, int height, Component message, double percentage, String messagePrefix) {
|
|
||||||
super(x, y, width, height, message, percentage);
|
|
||||||
this.percentage = percentage;
|
|
||||||
this.messagePrefix = messagePrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void updateMessage() {
|
|
||||||
setMessage(
|
|
||||||
Component.literal(messagePrefix + String.format("%.1f%%", percentage * 100.0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void applyValue() {
|
|
||||||
percentage = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,141 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.client;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import net.minecraft.client.gui.components.Button;
|
|
||||||
import net.minecraft.client.gui.components.Renderable;
|
|
||||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
|
||||||
import net.minecraft.client.gui.narration.NarratableEntry;
|
|
||||||
import net.minecraft.client.gui.narration.NarratedElementType;
|
|
||||||
import net.minecraft.client.gui.narration.NarrationElementOutput;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
|
||||||
|
|
||||||
public class EntitySelectionButton implements Renderable, GuiEventListener, NarratableEntry {
|
|
||||||
private int x;
|
|
||||||
private int y;
|
|
||||||
private int width;
|
|
||||||
private int height;
|
|
||||||
private boolean focused;
|
|
||||||
private Button nestedButton;
|
|
||||||
TBMEntityButtonPress onPress;
|
|
||||||
private int entityID;
|
|
||||||
private boolean isSideA;
|
|
||||||
|
|
||||||
public EntitySelectionButton(int x, int y, int widthIn, int heightIn, String buttonText, int entityID, boolean isSideA, TBMEntityButtonPress onPress) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.width = widthIn;
|
|
||||||
this.height = heightIn;
|
|
||||||
this.onPress = onPress;
|
|
||||||
this.entityID = entityID;
|
|
||||||
this.isSideA = isSideA;
|
|
||||||
this.nestedButton = Button.builder(Component.literal(buttonText), (unused) -> {}).pos(x, y).size(widthIn, heightIn).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntitySelectionButton(int x, int y, int widthIn, int heightIn, Component buttonTextComponent, int entityID, boolean isSideA, TBMEntityButtonPress onPress) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.width = widthIn;
|
|
||||||
this.height = heightIn;
|
|
||||||
this.onPress = onPress;
|
|
||||||
this.entityID = entityID;
|
|
||||||
this.isSideA = isSideA;
|
|
||||||
this.nestedButton = Button.builder(buttonTextComponent, (unused) -> {}).pos(x, y).size(widthIn, heightIn).build();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getID() {
|
|
||||||
return entityID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getIsSideA() {
|
|
||||||
return isSideA;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) {
|
|
||||||
this.nestedButton.render(guiGraphics, mouseX, mouseY, partialTicks);
|
|
||||||
Entity e = Minecraft.getInstance().level.getEntity(entityID);
|
|
||||||
if (e != null && e instanceof LivingEntity && ((LivingEntity) e).isAlive()) {
|
|
||||||
int health = (int) (((LivingEntity) e).getHealth() + 0.5f);
|
|
||||||
int xpos = this.x;
|
|
||||||
int xoffset;
|
|
||||||
if (isSideA) {
|
|
||||||
xpos += this.width + 4;
|
|
||||||
xoffset = 4;
|
|
||||||
} else {
|
|
||||||
xpos -= 6;
|
|
||||||
xoffset = -4;
|
|
||||||
}
|
|
||||||
if (health > 200) {
|
|
||||||
guiGraphics.fill(xpos, this.y + this.height * 4 / 5, xpos + 2, this.y + this.height, 0xFFFF0000);
|
|
||||||
guiGraphics.fill(xpos, this.y + this.height * 3 / 5, xpos + 2, this.y + this.height * 4 / 5, 0xFFFFFF00);
|
|
||||||
guiGraphics.fill(xpos, this.y + this.height * 2 / 5, xpos + 2, this.y + this.height * 3 / 5, 0xFF00FF00);
|
|
||||||
guiGraphics.fill(xpos, this.y + this.height / 5, xpos + 2, this.y + this.height * 2 / 5, 0xFF00FFFF);
|
|
||||||
guiGraphics.fill(xpos, this.y, xpos + 2, this.y + this.height / 5, 0xFF0000FF);
|
|
||||||
int healthHeight = ((health - 200) * this.height / 100);
|
|
||||||
guiGraphics.fill(xpos + xoffset, this.y + this.height - healthHeight, xpos + xoffset + 2, this.y + this.height, 0xFFFFFFFF);
|
|
||||||
} else if (health > 100) {
|
|
||||||
guiGraphics.fill(xpos, this.y + this.height * 4 / 5, xpos + 2, this.y + this.height, 0xFFFF0000);
|
|
||||||
guiGraphics.fill(xpos, this.y + this.height * 3 / 5, xpos + 2, this.y + this.height * 4 / 5, 0xFFFFFF00);
|
|
||||||
guiGraphics.fill(xpos, this.y + this.height * 2 / 5, xpos + 2, this.y + this.height * 3 / 5, 0xFF00FF00);
|
|
||||||
guiGraphics.fill(xpos, this.y + this.height / 5, xpos + 2, this.y + this.height * 2 / 5, 0xFF00FFFF);
|
|
||||||
int healthHeight = ((health - 100) * this.height / 100);
|
|
||||||
guiGraphics.fill(xpos + xoffset, this.y + this.height - healthHeight, xpos + xoffset + 2, this.y + this.height, 0xFF0000FF);
|
|
||||||
} else if (health > 50) {
|
|
||||||
guiGraphics.fill(xpos, this.y + this.height * 4 / 5, xpos + 2, this.y + this.height, 0xFFFF0000);
|
|
||||||
guiGraphics.fill(xpos, this.y + this.height * 3 / 5, xpos + 2, this.y + this.height * 4 / 5, 0xFFFFFF00);
|
|
||||||
guiGraphics.fill(xpos, this.y + this.height * 2 / 5, xpos + 2, this.y + this.height * 3 / 5, 0xFF00FF00);
|
|
||||||
int healthHeight = ((health - 50) * this.height / 50);
|
|
||||||
guiGraphics.fill(xpos + xoffset, this.y + this.height - healthHeight, xpos + xoffset + 2, this.y + this.height, 0xFF00FFFF);
|
|
||||||
} else if (health > 20) {
|
|
||||||
guiGraphics.fill(xpos, this.y + this.height * 4 / 5, xpos + 2, this.y + this.height, 0xFFFF0000);
|
|
||||||
guiGraphics.fill(xpos, this.y + this.height * 3 / 5, xpos + 2, this.y + this.height * 4 / 5, 0xFFFFFF00);
|
|
||||||
int healthHeight = ((health - 20) * this.height / 30);
|
|
||||||
guiGraphics.fill(xpos + xoffset, this.y + this.height - healthHeight, xpos + xoffset + 2, this.y + this.height, 0xFF00FF00);
|
|
||||||
} else if (health > 10) {
|
|
||||||
guiGraphics.fill(xpos, this.y + this.height * 4 / 5, xpos + 2, this.y + this.height, 0xFFFF0000);
|
|
||||||
int healthHeight = ((health - 10) * this.height / 10);
|
|
||||||
guiGraphics.fill(xpos + xoffset, this.y + this.height - healthHeight, xpos + xoffset + 2, this.y + this.height, 0xFFFFFF00);
|
|
||||||
} else {
|
|
||||||
int healthHeight = (health * this.height / 10);
|
|
||||||
guiGraphics.fill(xpos + xoffset, this.y + this.height - healthHeight, xpos + xoffset + 2, this.y + this.height, 0xFFFF0000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onPress() {
|
|
||||||
onPress.onPress(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFocused(boolean b) {
|
|
||||||
this.focused = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isFocused() {
|
|
||||||
return focused;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public NarrationPriority narrationPriority() {
|
|
||||||
return NarrationPriority.FOCUSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateNarration(NarrationElementOutput narrationElementOutput) {
|
|
||||||
narrationElementOutput.add(NarratedElementType.HINT, TurnBasedMinecraftMod.proxy.getEntity(entityID, Minecraft.getInstance().level.dimension()).getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean mouseClicked(double x, double y, int unknown) {
|
|
||||||
if (unknown == 0 && x >= this.x && y >= this.y && x <= (double)(this.x + this.width) && y <= (double)(this.y + this.height)) {
|
|
||||||
onPress();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.client;
|
|
||||||
|
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
|
||||||
import net.minecraft.client.gui.components.Renderable;
|
|
||||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
|
||||||
import net.minecraft.client.gui.narration.NarratableEntry;
|
|
||||||
import net.minecraft.client.gui.narration.NarratedElementType;
|
|
||||||
import net.minecraft.client.gui.narration.NarrationElementOutput;
|
|
||||||
|
|
||||||
public class ItemSelectionButton implements Renderable, GuiEventListener, NarratableEntry {
|
|
||||||
private int x;
|
|
||||||
private int y;
|
|
||||||
private int width;
|
|
||||||
private int height;
|
|
||||||
TBMItemButtonPress onPress;
|
|
||||||
private int itemStackID;
|
|
||||||
private boolean focused;
|
|
||||||
|
|
||||||
public ItemSelectionButton(int x, int y, int widthIn, int heightIn, int itemStackID, TBMItemButtonPress onPress) {
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.width = widthIn;
|
|
||||||
this.height = heightIn;
|
|
||||||
this.onPress = onPress;
|
|
||||||
this.itemStackID = itemStackID;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getID() {
|
|
||||||
return itemStackID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float unk) {
|
|
||||||
boolean hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height;
|
|
||||||
if (hovered) {
|
|
||||||
guiGraphics.fill(this.x, this.y, this.x + this.width, this.y + this.height, 0x80FFFFFF);
|
|
||||||
} else {
|
|
||||||
guiGraphics.fill(this.x, this.y, this.x + this.width, this.y + this.height, 0x20707070);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onPress() {
|
|
||||||
onPress.onPress(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setFocused(boolean b) {
|
|
||||||
focused = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isFocused() {
|
|
||||||
return focused;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public NarrationPriority narrationPriority() {
|
|
||||||
return NarrationPriority.FOCUSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateNarration(NarrationElementOutput narrationElementOutput) {
|
|
||||||
narrationElementOutput.add(NarratedElementType.HINT, "Item " + this.itemStackID);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean mouseClicked(double x, double y, int unknown) {
|
|
||||||
if (unknown == 0 && x >= this.x && y >= this.y && x <= (double)(this.x + this.width) && y <= (double)(this.y + this.height)) {
|
|
||||||
onPress();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.client;
|
|
||||||
|
|
||||||
import net.minecraft.client.gui.components.AbstractButton;
|
|
||||||
|
|
||||||
public interface TBMButtonPress {
|
|
||||||
void onPress(AbstractButton button);
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.client;
|
|
||||||
|
|
||||||
public interface TBMEntityButtonPress {
|
|
||||||
void onPress(EntitySelectionButton button);
|
|
||||||
}
|
|
|
@ -1,5 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.client;
|
|
||||||
|
|
||||||
public interface TBMItemButtonPress {
|
|
||||||
void onPress(ItemSelectionButton button);
|
|
||||||
}
|
|
|
@ -1,170 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketBattleMessage;
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketEditingMessage;
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketGeneralMessage;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraft.world.damagesource.DamageTypes;
|
|
||||||
import net.minecraft.world.entity.monster.Creeper;
|
|
||||||
import net.neoforged.bus.api.SubscribeEvent;
|
|
||||||
import net.neoforged.neoforge.event.entity.living.LivingChangeTargetEvent;
|
|
||||||
import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent;
|
|
||||||
import net.neoforged.neoforge.network.PacketDistributor;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
public class AttackEventHandler
|
|
||||||
{
|
|
||||||
private boolean isAttackerValid(LivingIncomingDamageEvent event)
|
|
||||||
{
|
|
||||||
if(event.getSource().getEntity() == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if(event.getSource().getEntity().equals(TurnBasedMinecraftMod.proxy.getAttackingEntity()))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
final long now = System.nanoTime();
|
|
||||||
boolean isValid = false;
|
|
||||||
synchronized(TurnBasedMinecraftMod.proxy.getAttackerViaBowSet())
|
|
||||||
{
|
|
||||||
for(Iterator<AttackerViaBow> iter = TurnBasedMinecraftMod.proxy.getAttackerViaBowSet().iterator(); iter.hasNext();)
|
|
||||||
{
|
|
||||||
AttackerViaBow attacker = iter.next();
|
|
||||||
if(now - attacker.attackTime >= AttackerViaBow.ATTACK_TIMEOUT)
|
|
||||||
{
|
|
||||||
iter.remove();
|
|
||||||
}
|
|
||||||
else if(event.getSource().getEntity().equals(attacker.entity) && event.getSource().is(DamageTypes.ARROW))
|
|
||||||
{
|
|
||||||
iter.remove();
|
|
||||||
if(!isValid)
|
|
||||||
{
|
|
||||||
Battle b = TurnBasedMinecraftMod.proxy.getBattleManager().getBattleByID(attacker.battleID);
|
|
||||||
if(b != null)
|
|
||||||
{
|
|
||||||
b.sendMessageToAllPlayers(PacketBattleMessage.MessageType.ARROW_HIT, attacker.entity.getId(), event.getEntity().getId(), 0);
|
|
||||||
}
|
|
||||||
isValid = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return isValid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void entityAttacked(LivingIncomingDamageEvent event)
|
|
||||||
{
|
|
||||||
if(event.getEntity().level().isClientSide)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CommonProxy proxy = TurnBasedMinecraftMod.proxy;
|
|
||||||
Config config = proxy.getConfig();
|
|
||||||
BattleManager battleManager = proxy.getBattleManager();
|
|
||||||
// handle edit entity, pick entity via attack
|
|
||||||
{
|
|
||||||
if(event.getSource().getEntity() != null && event.getEntity() != null)
|
|
||||||
{
|
|
||||||
final EditingInfo editingInfo = proxy.getEditingInfo(event.getSource().getEntity().getId());
|
|
||||||
if(editingInfo != null && editingInfo.isPendingEntitySelection)
|
|
||||||
{
|
|
||||||
editingInfo.isPendingEntitySelection = false;
|
|
||||||
event.setCanceled(true);
|
|
||||||
if(editingInfo.isEditingCustomName)
|
|
||||||
{
|
|
||||||
if(!event.getEntity().hasCustomName())
|
|
||||||
{
|
|
||||||
TurnBasedMinecraftMod.logger.error("Cannot edit custom name from entity without custom name");
|
|
||||||
PacketDistributor.sendToPlayer((ServerPlayer)editingInfo.editor, new PacketGeneralMessage("Cannot edit custom name from entity without custom name"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
editingInfo.entityInfo = config.getCustomEntityInfo(event.getEntity().getCustomName().getString());
|
|
||||||
if(editingInfo.entityInfo == null)
|
|
||||||
{
|
|
||||||
editingInfo.entityInfo = new EntityInfo();
|
|
||||||
editingInfo.entityInfo.customName = event.getEntity().getCustomName().getString();
|
|
||||||
}
|
|
||||||
PacketDistributor.sendToPlayer((ServerPlayer)editingInfo.editor, new PacketGeneralMessage("Editing custom name \"" + event.getEntity().getCustomName().getString() + "\""));
|
|
||||||
TurnBasedMinecraftMod.logger.info("Begin editing custom \"" + event.getEntity().getCustomName().getString() + "\"");
|
|
||||||
PacketDistributor.sendToPlayer((ServerPlayer)editingInfo.editor, new PacketEditingMessage(PacketEditingMessage.Type.PICK_EDIT, editingInfo.entityInfo));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
editingInfo.entityInfo = config.getMatchingEntityInfo(event.getEntity());
|
|
||||||
if(editingInfo.entityInfo == null)
|
|
||||||
{
|
|
||||||
editingInfo.entityInfo = new EntityInfo();
|
|
||||||
editingInfo.entityInfo.classType = event.getEntity().getClass();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
editingInfo.entityInfo = editingInfo.entityInfo.clone();
|
|
||||||
}
|
|
||||||
PacketDistributor.sendToPlayer((ServerPlayer)editingInfo.editor, new PacketGeneralMessage("Editing entity \"" + editingInfo.entityInfo.classType.getName() + "\""));
|
|
||||||
TurnBasedMinecraftMod.logger.info("Begin editing \"" + editingInfo.entityInfo.classType.getName() + "\"");
|
|
||||||
PacketDistributor.sendToPlayer((ServerPlayer)editingInfo.editor, new PacketEditingMessage(PacketEditingMessage.Type.PICK_EDIT, editingInfo.entityInfo));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(event.getEntity() != null && event.getSource().getEntity() != null && (battleManager.isRecentlyLeftBattle(event.getEntity().getId()) || battleManager.isRecentlyLeftBattle(event.getSource().getEntity().getId())))
|
|
||||||
{
|
|
||||||
if(event.getSource().getEntity() instanceof Creeper && TurnBasedMinecraftMod.proxy.getConfig().getCreeperAlwaysAllowDamage()) {
|
|
||||||
event.setCanceled(false);
|
|
||||||
} else {
|
|
||||||
// TurnBasedMinecraftMod.logger.debug("Canceled attack");
|
|
||||||
event.setCanceled(true);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if(!isAttackerValid(event)
|
|
||||||
&& event.getEntity() != null
|
|
||||||
&& event.getSource().getEntity() != null
|
|
||||||
&& event.getEntity() != event.getSource().getEntity()
|
|
||||||
&& !config.getBattleIgnoringPlayers().contains(event.getSource().getEntity().getId())
|
|
||||||
&& !config.getBattleIgnoringPlayers().contains(event.getEntity().getId())
|
|
||||||
&& event.getEntity().level().dimension().equals(event.getSource().getEntity().level().dimension())
|
|
||||||
&& battleManager.checkAttack(event))
|
|
||||||
{
|
|
||||||
// TurnBasedMinecraftMod.logger.debug("Canceled LivingAttackEvent between " + TurnBasedMinecraftMod.proxy.getAttackingEntity() + " and " + event.getEntity());
|
|
||||||
event.setCanceled(true);
|
|
||||||
} else {
|
|
||||||
// TurnBasedMinecraftMod.logger.debug("Did not cancel attack");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(TurnBasedMinecraftMod.proxy.getAttackingDamage() < (int) event.getAmount())
|
|
||||||
{
|
|
||||||
TurnBasedMinecraftMod.proxy.setAttackingDamage((int) event.getAmount());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void entityTargeted(LivingChangeTargetEvent event)
|
|
||||||
{
|
|
||||||
Config config = TurnBasedMinecraftMod.proxy.getConfig();
|
|
||||||
BattleManager battleManager = TurnBasedMinecraftMod.proxy.getBattleManager();
|
|
||||||
if(event.getEntity().level().isClientSide
|
|
||||||
|| config.isOldBattleBehaviorEnabled()
|
|
||||||
|| (event.getEntity() != null && battleManager.isRecentlyLeftBattle(event.getEntity().getId()))
|
|
||||||
|| (event.getNewAboutToBeSetTarget() != null && battleManager.isRecentlyLeftBattle(event.getNewAboutToBeSetTarget().getId()))
|
|
||||||
|| (event.getEntity() != null && event.getNewAboutToBeSetTarget() != null && Utility.distanceBetweenEntities(event.getEntity(), event.getNewAboutToBeSetTarget()) > (double)config.getAggroStartBattleDistance()))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if(event.getEntity() != null
|
|
||||||
&& event.getNewAboutToBeSetTarget() != null
|
|
||||||
&& !config.getBattleIgnoringPlayers().contains(event.getEntity().getId())
|
|
||||||
&& !config.getBattleIgnoringPlayers().contains(event.getNewAboutToBeSetTarget().getId())
|
|
||||||
&& event.getEntity().level().dimension().equals(event.getNewAboutToBeSetTarget().level().dimension()))
|
|
||||||
{
|
|
||||||
TurnBasedMinecraftMod.proxy.getBattleManager().checkTargeted(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common;
|
|
||||||
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
|
|
||||||
public class AttackerViaBow
|
|
||||||
{
|
|
||||||
public static long ATTACK_TIMEOUT = 10000000000L;
|
|
||||||
|
|
||||||
public Entity entity;
|
|
||||||
public long attackTime;
|
|
||||||
public int battleID;
|
|
||||||
|
|
||||||
public AttackerViaBow()
|
|
||||||
{
|
|
||||||
entity = null;
|
|
||||||
attackTime = 0;
|
|
||||||
battleID = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttackerViaBow(Entity entity, int battleID)
|
|
||||||
{
|
|
||||||
this.entity = entity;
|
|
||||||
attackTime = System.nanoTime();
|
|
||||||
this.battleID = battleID;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,372 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketGeneralMessage;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.monster.Creeper;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.neoforged.neoforge.common.NeoForge;
|
|
||||||
import net.neoforged.neoforge.event.entity.living.LivingChangeTargetEvent;
|
|
||||||
import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent;
|
|
||||||
import net.neoforged.neoforge.network.PacketDistributor;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class BattleManager
|
|
||||||
{
|
|
||||||
private int IDCounter = 0;
|
|
||||||
protected Map<Integer, Battle> battleMap;
|
|
||||||
private Logger logger;
|
|
||||||
private Map<Integer, Combatant> recentlyLeftBattle;
|
|
||||||
private BattleUpdater battleUpdater;
|
|
||||||
private Map<EntityIDDimPair, Integer> entityToBattleMap;
|
|
||||||
private EntityIDDimPair tempIDPair;
|
|
||||||
|
|
||||||
public BattleManager(Logger logger)
|
|
||||||
{
|
|
||||||
this.logger = logger;
|
|
||||||
battleMap = new HashMap<Integer, Battle>();
|
|
||||||
recentlyLeftBattle = new HashMap<Integer, Combatant>();
|
|
||||||
battleUpdater = new BattleUpdater(this);
|
|
||||||
entityToBattleMap = new HashMap<EntityIDDimPair, Integer>();
|
|
||||||
NeoForge.EVENT_BUS.register(battleUpdater);
|
|
||||||
tempIDPair = new EntityIDDimPair();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Either creates a new Battle, adds a combatant to an existing Battle, or does
|
|
||||||
* nothing, depending on if a player is involved and/or an entity is currently
|
|
||||||
* in battle.
|
|
||||||
*
|
|
||||||
* @param event
|
|
||||||
* @return True if event should be canceled
|
|
||||||
*/
|
|
||||||
public boolean checkAttack(final LivingIncomingDamageEvent event)
|
|
||||||
{
|
|
||||||
Config config = TurnBasedMinecraftMod.proxy.getConfig();
|
|
||||||
String receiverClassName = event.getEntity().getClass().getName();
|
|
||||||
String receiverCustomName;
|
|
||||||
|
|
||||||
try {
|
|
||||||
receiverCustomName = event.getEntity().getCustomName().getString();
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
receiverCustomName = null;
|
|
||||||
}
|
|
||||||
String attackerClassName;
|
|
||||||
try {
|
|
||||||
attackerClassName = event.getSource().getEntity().getClass().getName();
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
attackerClassName = null;
|
|
||||||
}
|
|
||||||
String attackerCustomName;
|
|
||||||
try {
|
|
||||||
attackerCustomName = event.getSource().getEntity().getCustomName().getString();
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
attackerCustomName = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that both entities are EntityPlayer and not in creative or has a corresponding EntityInfo.
|
|
||||||
// Also check if "player_only_battles" is enabled and both entities are players.
|
|
||||||
if(!((event.getEntity() instanceof Player && !((Player)event.getEntity()).isCreative())
|
|
||||||
|| (config.getEntityInfoReference(receiverClassName) != null || config.getCustomEntityInfoReference(receiverCustomName) != null))
|
|
||||||
|| !((event.getSource().getEntity() instanceof Player && !((Player)event.getSource().getEntity()).isCreative())
|
|
||||||
|| (config.getEntityInfoReference(attackerClassName) != null || config.getCustomEntityInfoReference(attackerCustomName) != null))
|
|
||||||
|| (TurnBasedMinecraftMod.proxy.getConfig().isPlayerOnlyBattlesEnabled() &&
|
|
||||||
(!(event.getEntity() instanceof Player) || !(event.getSource().getEntity() instanceof Player))))
|
|
||||||
{
|
|
||||||
// logger.debug("BattleManager: Failed first check, attacker is \"" + attackerClassName + "\", defender is \"" + receiverClassName + "\"");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if ignore battle in config
|
|
||||||
EntityInfo entityInfo = config.getCustomEntityInfoReference(receiverCustomName);
|
|
||||||
if(entityInfo == null)
|
|
||||||
{
|
|
||||||
entityInfo = config.getMatchingEntityInfo(event.getEntity());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(entityInfo != null && (config.isIgnoreBattleType(entityInfo.category) || entityInfo.ignoreBattle))
|
|
||||||
{
|
|
||||||
// attacked entity ignores battle
|
|
||||||
Battle battle = battleMap.get(entityToBattleMap.get(new EntityIDDimPair(event.getSource().getEntity())));
|
|
||||||
if(battle != null && battle.hasCombatant(event.getSource().getEntity().getId())) {
|
|
||||||
logger.debug("Attack Canceled: attacked ignores battle but attacker in battle");
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
logger.debug("Attack Not Canceled: attacked ignores battle");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entityInfo = config.getCustomEntityInfoReference(attackerCustomName);
|
|
||||||
if(entityInfo == null)
|
|
||||||
{
|
|
||||||
entityInfo = config.getMatchingEntityInfo(event.getSource().getEntity());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(entityInfo != null && (config.isIgnoreBattleType(entityInfo.category) || entityInfo.ignoreBattle))
|
|
||||||
{
|
|
||||||
// attacker entity ignores battle
|
|
||||||
Battle battle = battleMap.get(entityToBattleMap.get(new EntityIDDimPair(event.getEntity())));
|
|
||||||
if(battle != null && battle.hasCombatant(event.getEntity().getId())) {
|
|
||||||
logger.debug("Attack Canceled: attacker ignores battle but attacked in battle");
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
logger.debug("Attack Not Canceled: attacker ignores battle");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if one is in battle
|
|
||||||
Battle attackerBattle = battleMap.get(entityToBattleMap.get(new EntityIDDimPair(event.getSource().getEntity())));
|
|
||||||
if(attackerBattle != null && !attackerBattle.hasCombatant(event.getSource().getEntity().getId())) {
|
|
||||||
attackerBattle = null;
|
|
||||||
}
|
|
||||||
Battle defenderBattle = battleMap.get(entityToBattleMap.get(new EntityIDDimPair(event.getEntity())));
|
|
||||||
if(defenderBattle != null && !defenderBattle.hasCombatant(event.getEntity().getId())) {
|
|
||||||
defenderBattle = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(attackerBattle != null && defenderBattle != null) {
|
|
||||||
// both in battle, attack canceled
|
|
||||||
return true;
|
|
||||||
} else if(attackerBattle == null && defenderBattle == null) {
|
|
||||||
// neither entity is in battle
|
|
||||||
if(event.getEntity() instanceof Player || event.getSource().getEntity() instanceof Player)
|
|
||||||
{
|
|
||||||
// at least one of the entities is a player, create Battle
|
|
||||||
Collection<Entity> sideA = new ArrayList<Entity>(1);
|
|
||||||
Collection<Entity> sideB = new ArrayList<Entity>(1);
|
|
||||||
sideA.add(event.getEntity());
|
|
||||||
sideB.add(event.getSource().getEntity());
|
|
||||||
createBattle(sideA, sideB, event.getEntity().level().dimension());
|
|
||||||
logger.debug("Attack Not Canceled: new battle created");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logger.debug("Attack Not Canceled: neither are in battle or players");
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
// at this point only one entity is in battle, so add entity to other side
|
|
||||||
if(attackerBattle != null) {
|
|
||||||
if (attackerBattle.getSize() >= config.getMaxInBattle()) {
|
|
||||||
// battle limit reached, cannot add to battle
|
|
||||||
return true;
|
|
||||||
} else if (attackerBattle.hasCombatantInSideA(event.getSource().getEntity().getId())) {
|
|
||||||
attackerBattle.addCombatantToSideB(event.getEntity());
|
|
||||||
} else {
|
|
||||||
attackerBattle.addCombatantToSideA(event.getEntity());
|
|
||||||
}
|
|
||||||
entityToBattleMap.put(new EntityIDDimPair(event.getEntity()), attackerBattle.getId());
|
|
||||||
} else {
|
|
||||||
if (defenderBattle.getSize() >= config.getMaxInBattle()) {
|
|
||||||
// battle limit reached, cannot add to battle
|
|
||||||
return true;
|
|
||||||
} else if (defenderBattle.hasCombatantInSideA(event.getEntity().getId())) {
|
|
||||||
defenderBattle.addCombatantToSideB(event.getSource().getEntity());
|
|
||||||
} else {
|
|
||||||
defenderBattle.addCombatantToSideA(event.getSource().getEntity());
|
|
||||||
}
|
|
||||||
entityToBattleMap.put(new EntityIDDimPair(event.getSource().getEntity()), defenderBattle.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("Attack Canceled: one is in battle");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void checkTargeted(LivingChangeTargetEvent event)
|
|
||||||
{
|
|
||||||
// Check if "player_only_battles" is enabled and if both entities are players.
|
|
||||||
if (TurnBasedMinecraftMod.proxy.getConfig().isPlayerOnlyBattlesEnabled() &&
|
|
||||||
(!(event.getEntity() instanceof Player) || !(event.getNewAboutToBeSetTarget() instanceof Player))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String targetedCustomName;
|
|
||||||
try {
|
|
||||||
targetedCustomName = event.getNewAboutToBeSetTarget().getCustomName().getString();
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
targetedCustomName = null;
|
|
||||||
}
|
|
||||||
String attackerCustomName;
|
|
||||||
try {
|
|
||||||
attackerCustomName = event.getEntity().getCustomName().getString();
|
|
||||||
} catch (NullPointerException e) {
|
|
||||||
attackerCustomName = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityInfo attackerInfo = TurnBasedMinecraftMod.proxy.getConfig().getCustomEntityInfoReference(attackerCustomName);
|
|
||||||
if(attackerInfo == null)
|
|
||||||
{
|
|
||||||
attackerInfo = TurnBasedMinecraftMod.proxy.getConfig().getMatchingEntityInfo(event.getEntity());
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityInfo targetedInfo;
|
|
||||||
if(event.getNewAboutToBeSetTarget() instanceof Player)
|
|
||||||
{
|
|
||||||
targetedInfo = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
targetedInfo = TurnBasedMinecraftMod.proxy.getConfig().getCustomEntityInfoReference(targetedCustomName);
|
|
||||||
if(targetedInfo == null)
|
|
||||||
{
|
|
||||||
targetedInfo = TurnBasedMinecraftMod.proxy.getConfig().getMatchingEntityInfo(event.getNewAboutToBeSetTarget());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if((event.getNewAboutToBeSetTarget() instanceof Player && ((Player)event.getNewAboutToBeSetTarget()).isCreative())
|
|
||||||
|| attackerInfo == null
|
|
||||||
|| attackerInfo.ignoreBattle
|
|
||||||
|| TurnBasedMinecraftMod.proxy.getConfig().isIgnoreBattleType(attackerInfo.category)
|
|
||||||
|| (targetedInfo != null
|
|
||||||
&& (targetedInfo.ignoreBattle
|
|
||||||
|| TurnBasedMinecraftMod.proxy.getConfig().isIgnoreBattleType(targetedInfo.category))))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if one is in battle
|
|
||||||
Battle attackerBattle = battleMap.get(entityToBattleMap.get(new EntityIDDimPair(event.getEntity())));
|
|
||||||
if(attackerBattle != null && !attackerBattle.hasCombatant(event.getEntity().getId())) {
|
|
||||||
attackerBattle = null;
|
|
||||||
}
|
|
||||||
Battle defenderBattle = battleMap.get(entityToBattleMap.get(new EntityIDDimPair(event.getNewAboutToBeSetTarget())));
|
|
||||||
if(defenderBattle != null && !defenderBattle.hasCombatant(event.getNewAboutToBeSetTarget().getId())) {
|
|
||||||
defenderBattle = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(attackerBattle != null && defenderBattle != null) {
|
|
||||||
return;
|
|
||||||
} else if(attackerBattle == null && defenderBattle == null) {
|
|
||||||
// neither in battle
|
|
||||||
if(event.getEntity() instanceof Player || event.getNewAboutToBeSetTarget() instanceof Player)
|
|
||||||
{
|
|
||||||
// at least one is a player, create battle
|
|
||||||
Collection<Entity> sideA = new ArrayList<Entity>(1);
|
|
||||||
Collection<Entity> sideB = new ArrayList<Entity>(1);
|
|
||||||
sideA.add(event.getEntity());
|
|
||||||
sideB.add(event.getNewAboutToBeSetTarget());
|
|
||||||
createBattle(sideA, sideB, event.getEntity().level().dimension());
|
|
||||||
logger.debug("neither in battle, at least one is player, creating new battle");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// add entity to battle
|
|
||||||
if(attackerBattle != null) {
|
|
||||||
if (attackerBattle.getSize() >= TurnBasedMinecraftMod.proxy.getConfig().getMaxInBattle()) {
|
|
||||||
// battle max reached, cannot add to battle
|
|
||||||
return;
|
|
||||||
} else if (attackerBattle.hasCombatantInSideA(event.getEntity().getId())) {
|
|
||||||
attackerBattle.addCombatantToSideB(event.getNewAboutToBeSetTarget());
|
|
||||||
} else {
|
|
||||||
attackerBattle.addCombatantToSideA(event.getNewAboutToBeSetTarget());
|
|
||||||
}
|
|
||||||
entityToBattleMap.put(new EntityIDDimPair(event.getNewAboutToBeSetTarget()), attackerBattle.getId());
|
|
||||||
} else {
|
|
||||||
if (defenderBattle.getSize() >= TurnBasedMinecraftMod.proxy.getConfig().getMaxInBattle()) {
|
|
||||||
// battle max reached, cannot add to battle
|
|
||||||
return;
|
|
||||||
} else if (defenderBattle.hasCombatantInSideA(event.getNewAboutToBeSetTarget().getId())) {
|
|
||||||
defenderBattle.addCombatantToSideB(event.getEntity());
|
|
||||||
} else {
|
|
||||||
defenderBattle.addCombatantToSideA(event.getEntity());
|
|
||||||
}
|
|
||||||
entityToBattleMap.put(new EntityIDDimPair(event.getEntity()), defenderBattle.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Battle createBattle(Collection<Entity> sideA, Collection<Entity> sideB, ResourceKey<Level> dimension)
|
|
||||||
{
|
|
||||||
Battle newBattle = null;
|
|
||||||
while(battleMap.containsKey(IDCounter))
|
|
||||||
{
|
|
||||||
++IDCounter;
|
|
||||||
}
|
|
||||||
newBattle = new Battle(this, IDCounter, sideA, sideB, true, dimension);
|
|
||||||
battleMap.put(IDCounter, newBattle);
|
|
||||||
for(Entity e : sideA) {
|
|
||||||
entityToBattleMap.put(new EntityIDDimPair(e), newBattle.getId());
|
|
||||||
}
|
|
||||||
for(Entity e : sideB) {
|
|
||||||
entityToBattleMap.put(new EntityIDDimPair(e), newBattle.getId());
|
|
||||||
}
|
|
||||||
newBattle.notifyPlayersBattleInfo();
|
|
||||||
return newBattle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Battle getBattleByID(int id)
|
|
||||||
{
|
|
||||||
return battleMap.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cleanup()
|
|
||||||
{
|
|
||||||
battleUpdater.setRunning(false);
|
|
||||||
NeoForge.EVENT_BUS.unregister(battleUpdater);
|
|
||||||
battleMap.clear();
|
|
||||||
battleUpdater = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void addRecentlyLeftBattle(Combatant c)
|
|
||||||
{
|
|
||||||
c.time = System.nanoTime();
|
|
||||||
Config config = TurnBasedMinecraftMod.proxy.getConfig();
|
|
||||||
if(c.entity instanceof ServerPlayer) {
|
|
||||||
PacketDistributor.sendToPlayer((ServerPlayer)c.entity, new PacketGeneralMessage("You just left battle! " + config.getLeaveBattleCooldownSeconds() + " seconds until you can attack/be-attacked again!"));
|
|
||||||
}
|
|
||||||
recentlyLeftBattle.put(c.entity.getId(), c);
|
|
||||||
entityToBattleMap.remove(new EntityIDDimPair(c.entity));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void updateRecentlyLeftBattle()
|
|
||||||
{
|
|
||||||
long current = System.nanoTime();
|
|
||||||
for(Iterator<Map.Entry<Integer, Combatant>> iter = recentlyLeftBattle.entrySet().iterator(); iter.hasNext();)
|
|
||||||
{
|
|
||||||
Map.Entry<Integer, Combatant> entry = iter.next();
|
|
||||||
if(entry.getValue().entity instanceof Creeper && TurnBasedMinecraftMod.proxy.getConfig().getCreeperStopExplodeOnLeaveBattle()) {
|
|
||||||
((Creeper)entry.getValue().entity).setSwellDir(-10);
|
|
||||||
}
|
|
||||||
if(current - entry.getValue().time > TurnBasedMinecraftMod.proxy.getConfig().getLeaveBattleCooldownNanos())
|
|
||||||
{
|
|
||||||
iter.remove();
|
|
||||||
if(entry.getValue().entity instanceof ServerPlayer)
|
|
||||||
{
|
|
||||||
PacketDistributor.sendToPlayer((ServerPlayer)entry.getValue().entity, new PacketGeneralMessage("Timer ended, you can now attack/be-attacked again."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRecentlyLeftBattle(int entityID)
|
|
||||||
{
|
|
||||||
return recentlyLeftBattle.containsKey(entityID);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean forceLeaveBattle(EntityIDDimPair entityInfo) {
|
|
||||||
boolean result = false;
|
|
||||||
Integer battleID = entityToBattleMap.get(entityInfo);
|
|
||||||
if(battleID != null) {
|
|
||||||
Battle battle = battleMap.get(battleID);
|
|
||||||
if (battle != null && battle.hasCombatant(entityInfo.id)) {
|
|
||||||
battle.forceRemoveCombatant(entityInfo);
|
|
||||||
result = true;
|
|
||||||
}
|
|
||||||
entityToBattleMap.remove(entityInfo);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isInBattle(Entity entity) {
|
|
||||||
synchronized(tempIDPair) {
|
|
||||||
tempIDPair.id = entity.getId();
|
|
||||||
tempIDPair.dim = entity.level().dimension();
|
|
||||||
return entityToBattleMap.keySet().contains(tempIDPair);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common;
|
|
||||||
|
|
||||||
|
|
||||||
import net.neoforged.bus.api.SubscribeEvent;
|
|
||||||
import net.neoforged.neoforge.event.tick.ServerTickEvent;
|
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
|
|
||||||
public class BattleUpdater
|
|
||||||
{
|
|
||||||
private BattleManager manager;
|
|
||||||
private AtomicBoolean isRunning;
|
|
||||||
private int tick;
|
|
||||||
private final int tickLimit = 3;
|
|
||||||
|
|
||||||
public BattleUpdater(BattleManager manager)
|
|
||||||
{
|
|
||||||
this.manager = manager;
|
|
||||||
isRunning = new AtomicBoolean(true);
|
|
||||||
tick = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setRunning(boolean isRunning) {
|
|
||||||
this.isRunning.set(isRunning);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SubscribeEvent
|
|
||||||
public void update(ServerTickEvent.Post tickEvent) {
|
|
||||||
//if(tickEvent.phase != TickEvent.Phase.START && isRunning.get() && ++tick > tickLimit) {
|
|
||||||
if(isRunning.get() && ++tick > tickLimit && tickEvent.hasTime()) {
|
|
||||||
tick = 0;
|
|
||||||
manager.battleMap.entrySet().removeIf(entry -> entry.getValue().update());
|
|
||||||
manager.updateRecentlyLeftBattle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,138 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common;
|
|
||||||
|
|
||||||
import net.minecraft.world.effect.MobEffectInstance;
|
|
||||||
import net.minecraft.world.effect.MobEffects;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
public class Combatant
|
|
||||||
{
|
|
||||||
public Entity entity;
|
|
||||||
public Battle.Decision decision;
|
|
||||||
public int itemToUse;
|
|
||||||
public EntityInfo entityInfo;
|
|
||||||
public boolean recalcSpeedOnCompare;
|
|
||||||
public int targetEntityID;
|
|
||||||
public boolean isSideA;
|
|
||||||
public int remainingDefenses;
|
|
||||||
public int battleID;
|
|
||||||
public double x;
|
|
||||||
//public double y; // y is ignored to prevent perpetual fall damage when FreezeBattleCombatants is enabled
|
|
||||||
public double z;
|
|
||||||
public float yaw;
|
|
||||||
public float pitch;
|
|
||||||
public long time;
|
|
||||||
public int creeperTurns;
|
|
||||||
|
|
||||||
public Combatant()
|
|
||||||
{
|
|
||||||
decision = Battle.Decision.UNDECIDED;
|
|
||||||
recalcSpeedOnCompare = false;
|
|
||||||
remainingDefenses = 0;
|
|
||||||
creeperTurns = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Combatant(Entity e, EntityInfo entityInfo)
|
|
||||||
{
|
|
||||||
entity = e;
|
|
||||||
decision = Battle.Decision.UNDECIDED;
|
|
||||||
this.entityInfo = entityInfo;
|
|
||||||
recalcSpeedOnCompare = false;
|
|
||||||
remainingDefenses = 0;
|
|
||||||
creeperTurns = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provided in reverse order of speed because PriorityQueue has least first.
|
|
||||||
*/
|
|
||||||
public static class CombatantComparator implements Comparator<Combatant>
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public int compare(Combatant c0, Combatant c1)
|
|
||||||
{
|
|
||||||
if(c0.entity instanceof Player && c0.recalcSpeedOnCompare)
|
|
||||||
{
|
|
||||||
LivingEntity c0Entity = (LivingEntity)c0.entity;
|
|
||||||
boolean isHaste = false;
|
|
||||||
boolean isSlow = false;
|
|
||||||
for(MobEffectInstance e : c0Entity.getActiveEffects())
|
|
||||||
{
|
|
||||||
if(e.getEffect().equals(MobEffects.MOVEMENT_SPEED) || e.getEffect().equals(MobEffects.DIG_SPEED))
|
|
||||||
{
|
|
||||||
isHaste = true;
|
|
||||||
}
|
|
||||||
else if(e.getEffect().equals(MobEffects.MOVEMENT_SLOWDOWN) || e.getEffect().equals(MobEffects.DIG_SLOWDOWN))
|
|
||||||
{
|
|
||||||
isSlow = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(c0.entityInfo == null)
|
|
||||||
{
|
|
||||||
c0.entityInfo = new EntityInfo();
|
|
||||||
}
|
|
||||||
if(isHaste && !isSlow)
|
|
||||||
{
|
|
||||||
c0.entityInfo.speed = TurnBasedMinecraftMod.proxy.getConfig().getPlayerHasteSpeed();
|
|
||||||
}
|
|
||||||
else if(isSlow && !isHaste)
|
|
||||||
{
|
|
||||||
c0.entityInfo.speed = TurnBasedMinecraftMod.proxy.getConfig().getPlayerSlowSpeed();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
c0.entityInfo.speed = TurnBasedMinecraftMod.proxy.getConfig().getPlayerSpeed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(c1.entity instanceof Player && c1.recalcSpeedOnCompare)
|
|
||||||
{
|
|
||||||
LivingEntity c1Entity = (LivingEntity)c1.entity;
|
|
||||||
boolean isHaste = false;
|
|
||||||
boolean isSlow = false;
|
|
||||||
for(MobEffectInstance e : c1Entity.getActiveEffects())
|
|
||||||
{
|
|
||||||
if(e.getEffect().equals(MobEffects.MOVEMENT_SPEED))
|
|
||||||
{
|
|
||||||
isHaste = true;
|
|
||||||
}
|
|
||||||
else if(e.getEffect().equals(MobEffects.MOVEMENT_SLOWDOWN))
|
|
||||||
{
|
|
||||||
isSlow = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(c1.entityInfo == null)
|
|
||||||
{
|
|
||||||
c1.entityInfo = new EntityInfo();
|
|
||||||
}
|
|
||||||
if(isHaste && !isSlow)
|
|
||||||
{
|
|
||||||
c1.entityInfo.speed = TurnBasedMinecraftMod.proxy.getConfig().getPlayerHasteSpeed();
|
|
||||||
}
|
|
||||||
else if(isSlow && !isHaste)
|
|
||||||
{
|
|
||||||
c1.entityInfo.speed = TurnBasedMinecraftMod.proxy.getConfig().getPlayerSlowSpeed();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
c1.entityInfo.speed = TurnBasedMinecraftMod.proxy.getConfig().getPlayerSpeed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(c0.entityInfo.speed > c1.entityInfo.speed)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else if(c0.entityInfo.speed < c1.entityInfo.speed)
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,183 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common;
|
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
|
||||||
import net.minecraft.network.codec.StreamCodec;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
|
||||||
import net.neoforged.neoforge.server.ServerLifecycleHooks;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class CommonProxy
|
|
||||||
{
|
|
||||||
private Set<AttackerViaBow> attackerViaBow = null;
|
|
||||||
private BattleManager battleManager = null;
|
|
||||||
private Entity attackingEntity = null;
|
|
||||||
private int attackingDamage = 0;
|
|
||||||
private Config config = null;
|
|
||||||
protected Logger logger = null;
|
|
||||||
private Map<Integer, EditingInfo> editingPlayers;
|
|
||||||
|
|
||||||
public final void initialize()
|
|
||||||
{
|
|
||||||
attackerViaBow = new HashSet<AttackerViaBow>();
|
|
||||||
editingPlayers = new Hashtable<Integer, EditingInfo>();
|
|
||||||
initializeClient();
|
|
||||||
logger.debug("Init proxy for com_burnedkirby_turnbasedminecraft");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void initializeClient() {}
|
|
||||||
|
|
||||||
public final boolean initializeBattleManager()
|
|
||||||
{
|
|
||||||
if(battleManager == null)
|
|
||||||
{
|
|
||||||
battleManager = new BattleManager(TurnBasedMinecraftMod.logger);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean cleanupBattleManager ()
|
|
||||||
{
|
|
||||||
if(battleManager != null)
|
|
||||||
{
|
|
||||||
battleManager.cleanup();
|
|
||||||
battleManager = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBattleGuiTime(int timeRemaining) {}
|
|
||||||
|
|
||||||
public void setBattleGuiBattleChanged() {}
|
|
||||||
|
|
||||||
public void setBattleGuiAsGui() {}
|
|
||||||
|
|
||||||
public void setBattleGuiTurnTimerEnabled(boolean enabled) {}
|
|
||||||
|
|
||||||
public void setBattleGuiTurnTimerMax(int timeMax) {}
|
|
||||||
|
|
||||||
public void battleGuiTurnBegin() {}
|
|
||||||
|
|
||||||
public void battleGuiTurnEnd() {}
|
|
||||||
|
|
||||||
public void battleStarted() {}
|
|
||||||
|
|
||||||
public void battleEnded() {}
|
|
||||||
|
|
||||||
public final void postInit()
|
|
||||||
{
|
|
||||||
config = new Config(logger);
|
|
||||||
postInitClient();
|
|
||||||
logger.debug("postInit proxy for com_burnedkirby_turnbasedminecraft");
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void postInitClient() {}
|
|
||||||
|
|
||||||
public final void setLogger(Logger logger)
|
|
||||||
{
|
|
||||||
this.logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void playBattleMusic() {}
|
|
||||||
|
|
||||||
public void playSillyMusic() {}
|
|
||||||
|
|
||||||
public void stopMusic(boolean resumeMCSounds) {}
|
|
||||||
|
|
||||||
public void typeEnteredBattle(String type) {}
|
|
||||||
|
|
||||||
public void typeLeftBattle(String type) {}
|
|
||||||
|
|
||||||
public void displayString(String message) {}
|
|
||||||
|
|
||||||
public void displayComponent(Component textComponent) {}
|
|
||||||
|
|
||||||
public final boolean isServerRunning()
|
|
||||||
{
|
|
||||||
return battleManager != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Battle getLocalBattle()
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createLocalBattle(int id) {}
|
|
||||||
|
|
||||||
public final Set<AttackerViaBow> getAttackerViaBowSet()
|
|
||||||
{
|
|
||||||
return attackerViaBow;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final BattleManager getBattleManager()
|
|
||||||
{
|
|
||||||
return battleManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final void setAttackingEntity(Entity entity)
|
|
||||||
{
|
|
||||||
attackingEntity = entity;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final Entity getAttackingEntity()
|
|
||||||
{
|
|
||||||
return attackingEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final void setAttackingDamage(int damage)
|
|
||||||
{
|
|
||||||
attackingDamage = damage;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final int getAttackingDamage()
|
|
||||||
{
|
|
||||||
return attackingDamage;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final Logger getLogger()
|
|
||||||
{
|
|
||||||
return logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final Config getConfig()
|
|
||||||
{
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final EditingInfo getEditingInfo(int id)
|
|
||||||
{
|
|
||||||
return editingPlayers.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final EditingInfo setEditingPlayer(Player player)
|
|
||||||
{
|
|
||||||
return editingPlayers.put(player.getId(), new EditingInfo(player));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final EditingInfo removeEditingInfo(int id)
|
|
||||||
{
|
|
||||||
return editingPlayers.remove(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Entity getEntity(int id, ResourceKey<Level> dim) {
|
|
||||||
return ServerLifecycleHooks.getCurrentServer().getLevel(dim).getEntity(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <MSG> void handlePacket(final MSG msg, final IPayloadContext ctx) {}
|
|
||||||
|
|
||||||
public static final StreamCodec<ByteBuf, Collection<Integer>> COLLECTION_INT_CODEC = ByteBufCodecs.INT.apply(ByteBufCodecs.collection(ArrayList::new));
|
|
||||||
|
|
||||||
public void showClientConfigGui() {}
|
|
||||||
|
|
||||||
public void pauseMCMusic() {}
|
|
||||||
public void resumeMCMusic() {}
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketGeneralMessage;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.neoforged.bus.api.SubscribeEvent;
|
|
||||||
import net.neoforged.neoforge.event.entity.EntityTravelToDimensionEvent;
|
|
||||||
import net.neoforged.neoforge.network.PacketDistributor;
|
|
||||||
|
|
||||||
public class DimensionChangedHandler {
|
|
||||||
@SubscribeEvent
|
|
||||||
public void dimensionChanged(EntityTravelToDimensionEvent event) {
|
|
||||||
if(event.getEntity().level().isClientSide) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(TurnBasedMinecraftMod.proxy.getBattleManager().forceLeaveBattle(new EntityIDDimPair(event.getEntity()))
|
|
||||||
&& event.getEntity() instanceof ServerPlayer) {
|
|
||||||
PacketDistributor.sendToPlayer((ServerPlayer)event.getEntity(), new PacketGeneralMessage("Left battle due to moving to a different dimension"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common;
|
|
||||||
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
|
|
||||||
public class EditingInfo
|
|
||||||
{
|
|
||||||
public Player editor;
|
|
||||||
public EntityInfo entityInfo;
|
|
||||||
public boolean isPendingEntitySelection;
|
|
||||||
public boolean isEditingCustomName;
|
|
||||||
public boolean isEditingPlayer;
|
|
||||||
|
|
||||||
public EditingInfo()
|
|
||||||
{
|
|
||||||
editor = null;
|
|
||||||
entityInfo = null;
|
|
||||||
isPendingEntitySelection = true;
|
|
||||||
isEditingCustomName = false;
|
|
||||||
isEditingPlayer = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EditingInfo(Player player)
|
|
||||||
{
|
|
||||||
editor = player;
|
|
||||||
entityInfo = null;
|
|
||||||
isPendingEntitySelection = true;
|
|
||||||
isEditingCustomName = false;
|
|
||||||
isEditingPlayer = false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common;
|
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
|
|
||||||
public class EntityIDDimPair {
|
|
||||||
public int id;
|
|
||||||
public ResourceKey<Level> dim;
|
|
||||||
|
|
||||||
EntityIDDimPair() {
|
|
||||||
id = 0;
|
|
||||||
// dim = Minecraft.getInstance().world.dimension();
|
|
||||||
dim = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityIDDimPair(int id, ResourceKey<Level> dim) {
|
|
||||||
this.id = id;
|
|
||||||
this.dim = dim;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityIDDimPair(Entity entity) {
|
|
||||||
id = entity.getId();
|
|
||||||
dim = entity.level().dimension();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Entity getEntity() {
|
|
||||||
return TurnBasedMinecraftMod.proxy.getEntity(id, dim);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return (id + dim.toString()).hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object other) {
|
|
||||||
if(other instanceof EntityIDDimPair) {
|
|
||||||
EntityIDDimPair otherPair = (EntityIDDimPair) other;
|
|
||||||
return otherPair.id == id && otherPair.dim == dim;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,543 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common;
|
|
||||||
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import net.minecraft.world.effect.MobEffectInstance;
|
|
||||||
import net.minecraft.world.effect.MobEffects;
|
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
public class EntityInfo
|
|
||||||
{
|
|
||||||
public Class classType;
|
|
||||||
public boolean ignoreBattle;
|
|
||||||
public int attackPower;
|
|
||||||
public int attackProbability;
|
|
||||||
public int attackVariance;
|
|
||||||
public Effect attackEffect;
|
|
||||||
public int attackEffectProbability;
|
|
||||||
public int defenseDamage;
|
|
||||||
public int defenseDamageProbability;
|
|
||||||
public int evasion;
|
|
||||||
public int speed;
|
|
||||||
public int hasteSpeed;
|
|
||||||
public int slowSpeed;
|
|
||||||
public String category;
|
|
||||||
public int decisionAttack;
|
|
||||||
public int decisionDefend;
|
|
||||||
public int decisionFlee;
|
|
||||||
public String customName;
|
|
||||||
public String playerName;
|
|
||||||
|
|
||||||
public enum Effect
|
|
||||||
{
|
|
||||||
SPEED,
|
|
||||||
SLOW,
|
|
||||||
HASTE,
|
|
||||||
MINING_FATIGUE,
|
|
||||||
STRENGTH,
|
|
||||||
JUMP_BOOST,
|
|
||||||
NAUSEA,
|
|
||||||
REGENERATION,
|
|
||||||
RESISTANCE,
|
|
||||||
FIRE_RESISTANCE,
|
|
||||||
WATER_BREATHING,
|
|
||||||
INVISIBILITY,
|
|
||||||
BLINDNESS,
|
|
||||||
NIGHT_VISION,
|
|
||||||
HUNGER,
|
|
||||||
WEAKNESS,
|
|
||||||
POISON,
|
|
||||||
WITHER,
|
|
||||||
HEALTH_BOOST,
|
|
||||||
ABSORPTION,
|
|
||||||
SATURATION,
|
|
||||||
GLOWING,
|
|
||||||
LEVITATION,
|
|
||||||
LUCK,
|
|
||||||
UNLUCK,
|
|
||||||
SLOW_FALLING,
|
|
||||||
CONDUIT_POWER,
|
|
||||||
DOLPHINS_GRACE,
|
|
||||||
BAD_OMEN,
|
|
||||||
FIRE,
|
|
||||||
UNKNOWN;
|
|
||||||
|
|
||||||
public static Effect fromString(String c)
|
|
||||||
{
|
|
||||||
c = c.toLowerCase();
|
|
||||||
if(c.equals("speed")) {
|
|
||||||
return SPEED;
|
|
||||||
} else if(c.equals("slow")) {
|
|
||||||
return SLOW;
|
|
||||||
} else if(c.equals("haste")) {
|
|
||||||
return HASTE;
|
|
||||||
} else if(c.equals("mining_fatigue") || c.equals("fatigue")) {
|
|
||||||
return MINING_FATIGUE;
|
|
||||||
} else if(c.equals("strength")) {
|
|
||||||
return STRENGTH;
|
|
||||||
} else if(c.equals("jump_boost")) {
|
|
||||||
return JUMP_BOOST;
|
|
||||||
} else if(c.equals("nausea")) {
|
|
||||||
return NAUSEA;
|
|
||||||
} else if(c.equals("regeneration")) {
|
|
||||||
return REGENERATION;
|
|
||||||
} else if(c.equals("resistance")) {
|
|
||||||
return RESISTANCE;
|
|
||||||
} else if(c.equals("fire_resistance")) {
|
|
||||||
return FIRE_RESISTANCE;
|
|
||||||
} else if(c.equals("water_breathing")) {
|
|
||||||
return WATER_BREATHING;
|
|
||||||
} else if(c.equals("invisibility")) {
|
|
||||||
return INVISIBILITY;
|
|
||||||
} else if(c.equals("blindness") || c.equals("blind")) {
|
|
||||||
return BLINDNESS;
|
|
||||||
} else if(c.equals("night_vision")) {
|
|
||||||
return NIGHT_VISION;
|
|
||||||
} else if(c.equals("hunger")) {
|
|
||||||
return HUNGER;
|
|
||||||
} else if(c.equals("weakness")) {
|
|
||||||
return WEAKNESS;
|
|
||||||
} else if(c.equals("poison")) {
|
|
||||||
return POISON;
|
|
||||||
} else if(c.equals("wither")) {
|
|
||||||
return WITHER;
|
|
||||||
} else if(c.equals("health_boost")) {
|
|
||||||
return HEALTH_BOOST;
|
|
||||||
} else if(c.equals("absorption")) {
|
|
||||||
return ABSORPTION;
|
|
||||||
} else if(c.equals("saturation")) {
|
|
||||||
return SATURATION;
|
|
||||||
} else if(c.equals("glowing")) {
|
|
||||||
return GLOWING;
|
|
||||||
} else if(c.equals("levitation")) {
|
|
||||||
return LEVITATION;
|
|
||||||
} else if(c.equals("luck")) {
|
|
||||||
return LUCK;
|
|
||||||
} else if(c.equals("unluck")) {
|
|
||||||
return UNLUCK;
|
|
||||||
} else if(c.equals("slow_falling")) {
|
|
||||||
return SLOW_FALLING;
|
|
||||||
} else if(c.equals("conduit_power")) {
|
|
||||||
return CONDUIT_POWER;
|
|
||||||
} else if(c.equals("dolphins_grace")) {
|
|
||||||
return DOLPHINS_GRACE;
|
|
||||||
} else if(c.equals("bad_omen")) {
|
|
||||||
return BAD_OMEN;
|
|
||||||
} else if(c.equals("fire")) {
|
|
||||||
return FIRE;
|
|
||||||
} else {
|
|
||||||
return UNKNOWN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
switch(this)
|
|
||||||
{
|
|
||||||
case SPEED:
|
|
||||||
return "speed";
|
|
||||||
case SLOW:
|
|
||||||
return "slow";
|
|
||||||
case HASTE:
|
|
||||||
return "haste";
|
|
||||||
case MINING_FATIGUE:
|
|
||||||
return "mining_fatigue";
|
|
||||||
case STRENGTH:
|
|
||||||
return "strength";
|
|
||||||
case JUMP_BOOST:
|
|
||||||
return "jump_boost";
|
|
||||||
case NAUSEA:
|
|
||||||
return "nausea";
|
|
||||||
case REGENERATION:
|
|
||||||
return "regeneration";
|
|
||||||
case RESISTANCE:
|
|
||||||
return "resistance";
|
|
||||||
case FIRE_RESISTANCE:
|
|
||||||
return "fire_resistance";
|
|
||||||
case WATER_BREATHING:
|
|
||||||
return "water_breathing";
|
|
||||||
case INVISIBILITY:
|
|
||||||
return "invisibility";
|
|
||||||
case BLINDNESS:
|
|
||||||
return "blindness";
|
|
||||||
case NIGHT_VISION:
|
|
||||||
return "night_vision";
|
|
||||||
case HUNGER:
|
|
||||||
return "hunger";
|
|
||||||
case WEAKNESS:
|
|
||||||
return "weakness";
|
|
||||||
case POISON:
|
|
||||||
return "poison";
|
|
||||||
case WITHER:
|
|
||||||
return "wither";
|
|
||||||
case HEALTH_BOOST:
|
|
||||||
return "health_boost";
|
|
||||||
case ABSORPTION:
|
|
||||||
return "absorption";
|
|
||||||
case SATURATION:
|
|
||||||
return "saturation";
|
|
||||||
case GLOWING:
|
|
||||||
return "glowing";
|
|
||||||
case LEVITATION:
|
|
||||||
return "levitation";
|
|
||||||
case LUCK:
|
|
||||||
return "luck";
|
|
||||||
case UNLUCK:
|
|
||||||
return "unluck";
|
|
||||||
case SLOW_FALLING:
|
|
||||||
return "slow_falling";
|
|
||||||
case CONDUIT_POWER:
|
|
||||||
return "conduit_power";
|
|
||||||
case DOLPHINS_GRACE:
|
|
||||||
return "dolphins_grace";
|
|
||||||
case BAD_OMEN:
|
|
||||||
return "bad_omen";
|
|
||||||
case FIRE:
|
|
||||||
return "fire";
|
|
||||||
default:
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public MobEffectInstance getPotionEffect()
|
|
||||||
{
|
|
||||||
return getPotionEffect(20 * 7, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MobEffectInstance getPotionEffect(int duration, int amplifier) {
|
|
||||||
switch(this) {
|
|
||||||
case SPEED:
|
|
||||||
return new MobEffectInstance(MobEffects.MOVEMENT_SPEED, duration, amplifier);
|
|
||||||
case SLOW:
|
|
||||||
return new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, duration, amplifier);
|
|
||||||
case HASTE:
|
|
||||||
return new MobEffectInstance(MobEffects.DIG_SPEED, duration, amplifier);
|
|
||||||
case MINING_FATIGUE:
|
|
||||||
return new MobEffectInstance(MobEffects.DIG_SLOWDOWN, duration, amplifier);
|
|
||||||
case STRENGTH:
|
|
||||||
return new MobEffectInstance(MobEffects.DAMAGE_BOOST, duration, amplifier);
|
|
||||||
case JUMP_BOOST:
|
|
||||||
return new MobEffectInstance(MobEffects.JUMP, duration, amplifier);
|
|
||||||
case NAUSEA:
|
|
||||||
return new MobEffectInstance(MobEffects.CONFUSION, duration, amplifier);
|
|
||||||
case REGENERATION:
|
|
||||||
return new MobEffectInstance(MobEffects.REGENERATION, duration, amplifier);
|
|
||||||
case RESISTANCE:
|
|
||||||
return new MobEffectInstance(MobEffects.DAMAGE_RESISTANCE, duration, amplifier);
|
|
||||||
case FIRE_RESISTANCE:
|
|
||||||
return new MobEffectInstance(MobEffects.FIRE_RESISTANCE, duration, amplifier);
|
|
||||||
case WATER_BREATHING:
|
|
||||||
return new MobEffectInstance(MobEffects.WATER_BREATHING, duration, amplifier);
|
|
||||||
case INVISIBILITY:
|
|
||||||
return new MobEffectInstance(MobEffects.INVISIBILITY, duration, amplifier);
|
|
||||||
case BLINDNESS:
|
|
||||||
return new MobEffectInstance(MobEffects.BLINDNESS, duration, amplifier);
|
|
||||||
case NIGHT_VISION:
|
|
||||||
return new MobEffectInstance(MobEffects.NIGHT_VISION, duration, amplifier);
|
|
||||||
case HUNGER:
|
|
||||||
return new MobEffectInstance(MobEffects.HUNGER, duration, amplifier);
|
|
||||||
case WEAKNESS:
|
|
||||||
return new MobEffectInstance(MobEffects.WEAKNESS, duration, amplifier);
|
|
||||||
case POISON:
|
|
||||||
return new MobEffectInstance(MobEffects.POISON, duration, amplifier);
|
|
||||||
case WITHER:
|
|
||||||
return new MobEffectInstance(MobEffects.WITHER, duration, amplifier);
|
|
||||||
case HEALTH_BOOST:
|
|
||||||
return new MobEffectInstance(MobEffects.HEALTH_BOOST, duration, amplifier);
|
|
||||||
case ABSORPTION:
|
|
||||||
return new MobEffectInstance(MobEffects.ABSORPTION, duration, amplifier);
|
|
||||||
case SATURATION:
|
|
||||||
return new MobEffectInstance(MobEffects.SATURATION, duration, amplifier);
|
|
||||||
case GLOWING:
|
|
||||||
return new MobEffectInstance(MobEffects.GLOWING, duration, amplifier);
|
|
||||||
case LEVITATION:
|
|
||||||
return new MobEffectInstance(MobEffects.LEVITATION, duration, amplifier);
|
|
||||||
case LUCK:
|
|
||||||
return new MobEffectInstance(MobEffects.LUCK, duration, amplifier);
|
|
||||||
case UNLUCK:
|
|
||||||
return new MobEffectInstance(MobEffects.UNLUCK, duration, amplifier);
|
|
||||||
case SLOW_FALLING:
|
|
||||||
return new MobEffectInstance(MobEffects.SLOW_FALLING, duration, amplifier);
|
|
||||||
case CONDUIT_POWER:
|
|
||||||
return new MobEffectInstance(MobEffects.CONDUIT_POWER, duration, amplifier);
|
|
||||||
case DOLPHINS_GRACE:
|
|
||||||
return new MobEffectInstance(MobEffects.DOLPHINS_GRACE, duration, amplifier);
|
|
||||||
case BAD_OMEN:
|
|
||||||
return new MobEffectInstance(MobEffects.BAD_OMEN, duration, amplifier);
|
|
||||||
case FIRE:
|
|
||||||
// FIRE is not a PotionEffect and must be applied directly to the Entity
|
|
||||||
return null;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void applyEffectToEntity(LivingEntity entity)
|
|
||||||
{
|
|
||||||
applyEffectToEntity(entity, 20 * 12, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void applyEffectToEntity(LivingEntity entity, int duration, int amplifier)
|
|
||||||
{
|
|
||||||
if(this == FIRE)
|
|
||||||
{
|
|
||||||
entity.setRemainingFireTicks(duration / 2);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if(this != UNKNOWN)
|
|
||||||
{
|
|
||||||
entity.addEffect(getPotionEffect(duration, amplifier));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAffectedString()
|
|
||||||
{
|
|
||||||
switch(this)
|
|
||||||
{
|
|
||||||
case SPEED:
|
|
||||||
return "made faster";
|
|
||||||
case SLOW:
|
|
||||||
return "made slower";
|
|
||||||
case HASTE:
|
|
||||||
return "made hastier";
|
|
||||||
case MINING_FATIGUE:
|
|
||||||
return "fatigued";
|
|
||||||
case STRENGTH:
|
|
||||||
return "strengthened";
|
|
||||||
case JUMP_BOOST:
|
|
||||||
return "jump boosted";
|
|
||||||
case NAUSEA:
|
|
||||||
return "made nauseous";
|
|
||||||
case REGENERATION:
|
|
||||||
return "given regeneration";
|
|
||||||
case RESISTANCE:
|
|
||||||
return "given resistance";
|
|
||||||
case FIRE_RESISTANCE:
|
|
||||||
return "given fire resistance";
|
|
||||||
case WATER_BREATHING:
|
|
||||||
return "made able to breathe underwater";
|
|
||||||
case INVISIBILITY:
|
|
||||||
return "given invisibility";
|
|
||||||
case BLINDNESS:
|
|
||||||
return "made blind";
|
|
||||||
case NIGHT_VISION:
|
|
||||||
return "given night vision";
|
|
||||||
case HUNGER:
|
|
||||||
return "made hungry";
|
|
||||||
case WEAKNESS:
|
|
||||||
return "made weak";
|
|
||||||
case POISON:
|
|
||||||
return "poisoned";
|
|
||||||
case WITHER:
|
|
||||||
return "withered";
|
|
||||||
case HEALTH_BOOST:
|
|
||||||
return "given more health";
|
|
||||||
case ABSORPTION:
|
|
||||||
return "given absorption";
|
|
||||||
case SATURATION:
|
|
||||||
return "given saturation";
|
|
||||||
case GLOWING:
|
|
||||||
return "made to glow";
|
|
||||||
case LEVITATION:
|
|
||||||
return "made to levitate";
|
|
||||||
case LUCK:
|
|
||||||
return "given luck";
|
|
||||||
case UNLUCK:
|
|
||||||
return "made unlucky";
|
|
||||||
case SLOW_FALLING:
|
|
||||||
return "falls slower";
|
|
||||||
case CONDUIT_POWER:
|
|
||||||
return "made able to live underwater";
|
|
||||||
case BAD_OMEN:
|
|
||||||
return "feels a bad omen";
|
|
||||||
case FIRE:
|
|
||||||
return "set on fire";
|
|
||||||
default:
|
|
||||||
return "given unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityInfo()
|
|
||||||
{
|
|
||||||
classType = null;
|
|
||||||
ignoreBattle = false;
|
|
||||||
attackPower = 0;
|
|
||||||
attackProbability = 70;
|
|
||||||
attackVariance = 0;
|
|
||||||
attackEffect = Effect.UNKNOWN;
|
|
||||||
attackEffectProbability = 50;
|
|
||||||
defenseDamage = 0;
|
|
||||||
defenseDamageProbability = 0;
|
|
||||||
evasion = 15;
|
|
||||||
speed = 50;
|
|
||||||
hasteSpeed = 80;
|
|
||||||
slowSpeed = 20;
|
|
||||||
category = "unknown";
|
|
||||||
decisionAttack = 70;
|
|
||||||
decisionDefend = 20;
|
|
||||||
decisionFlee = 10;
|
|
||||||
customName = new String();
|
|
||||||
playerName = new String();
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityInfo(Class classType, boolean ignoreBattle, int attackPower, int attackProbability, int attackVariance,
|
|
||||||
Effect attackEffect, int attackEffectProbability, int defenseDamage, int defenseDamageProbability,
|
|
||||||
int evasion, int speed, int hasteSpeed, int slowSpeed, String category, int decisionAttack, int decisionDefend, int decisionFlee,
|
|
||||||
String customName, String playerName) {
|
|
||||||
this.classType = classType;
|
|
||||||
this.ignoreBattle = ignoreBattle;
|
|
||||||
this.attackPower = attackPower;
|
|
||||||
this.attackProbability = attackProbability;
|
|
||||||
this.attackVariance = attackVariance;
|
|
||||||
this.attackEffect = attackEffect;
|
|
||||||
this.attackEffectProbability = attackEffectProbability;
|
|
||||||
this.defenseDamage = defenseDamage;
|
|
||||||
this.defenseDamageProbability = defenseDamageProbability;
|
|
||||||
this.evasion = evasion;
|
|
||||||
this.speed = speed;
|
|
||||||
this.hasteSpeed = hasteSpeed;
|
|
||||||
this.slowSpeed = slowSpeed;
|
|
||||||
this.category = category;
|
|
||||||
this.decisionAttack = decisionAttack;
|
|
||||||
this.decisionDefend = decisionDefend;
|
|
||||||
this.decisionFlee = decisionFlee;
|
|
||||||
this.customName = customName;
|
|
||||||
this.playerName = playerName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityInfo clone()
|
|
||||||
{
|
|
||||||
EntityInfo newEntityInfo = new EntityInfo();
|
|
||||||
newEntityInfo.classType = classType;
|
|
||||||
newEntityInfo.ignoreBattle = ignoreBattle;
|
|
||||||
newEntityInfo.attackPower = attackPower;
|
|
||||||
newEntityInfo.attackProbability = attackProbability;
|
|
||||||
newEntityInfo.attackVariance = attackVariance;
|
|
||||||
newEntityInfo.attackEffect = attackEffect;
|
|
||||||
newEntityInfo.attackEffectProbability = attackEffectProbability;
|
|
||||||
newEntityInfo.defenseDamage = defenseDamage;
|
|
||||||
newEntityInfo.defenseDamageProbability = defenseDamageProbability;
|
|
||||||
newEntityInfo.evasion = evasion;
|
|
||||||
newEntityInfo.speed = speed;
|
|
||||||
newEntityInfo.hasteSpeed = hasteSpeed;
|
|
||||||
newEntityInfo.slowSpeed = slowSpeed;
|
|
||||||
newEntityInfo.category = category;
|
|
||||||
newEntityInfo.decisionAttack = decisionAttack;
|
|
||||||
newEntityInfo.decisionDefend = decisionDefend;
|
|
||||||
newEntityInfo.decisionFlee = decisionFlee;
|
|
||||||
newEntityInfo.customName = customName;
|
|
||||||
newEntityInfo.playerName = playerName;
|
|
||||||
return newEntityInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityInfo(ByteBuf buffer) {
|
|
||||||
int name_bytes_len = buffer.readInt();
|
|
||||||
if (name_bytes_len > 0) {
|
|
||||||
ByteBuf name_bytes = buffer.readBytes(name_bytes_len);
|
|
||||||
try {
|
|
||||||
classType = Class.forName(name_bytes.toString(StandardCharsets.UTF_8));
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
TurnBasedMinecraftMod.logger.warn("Failed to decode EntityInfo.classType", e);
|
|
||||||
classType = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
classType = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ignoreBattle = buffer.readBoolean();
|
|
||||||
attackPower = buffer.readInt();
|
|
||||||
attackProbability = buffer.readInt();
|
|
||||||
attackVariance = buffer.readInt();
|
|
||||||
|
|
||||||
int effect_len = buffer.readInt();
|
|
||||||
ByteBuf effect_bytes = buffer.readBytes(effect_len);
|
|
||||||
attackEffect = Effect.fromString(effect_bytes.toString(StandardCharsets.UTF_8));
|
|
||||||
|
|
||||||
attackEffectProbability = buffer.readInt();
|
|
||||||
defenseDamage = buffer.readInt();
|
|
||||||
defenseDamageProbability = buffer.readInt();
|
|
||||||
evasion = buffer.readInt();
|
|
||||||
speed = buffer.readInt();
|
|
||||||
hasteSpeed = buffer.readInt();
|
|
||||||
slowSpeed = buffer.readInt();
|
|
||||||
|
|
||||||
int category_len = buffer.readInt();
|
|
||||||
ByteBuf category_bytes = buffer.readBytes(category_len);
|
|
||||||
category = category_bytes.toString(StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
decisionAttack = buffer.readInt();
|
|
||||||
decisionDefend = buffer.readInt();
|
|
||||||
decisionFlee = buffer.readInt();
|
|
||||||
|
|
||||||
int custom_len = buffer.readInt();
|
|
||||||
if (custom_len > 0) {
|
|
||||||
ByteBuf custom_bytes = buffer.readBytes(custom_len);
|
|
||||||
customName = custom_bytes.toString(StandardCharsets.UTF_8);
|
|
||||||
} else {
|
|
||||||
customName = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
int player_len = buffer.readInt();
|
|
||||||
if (player_len > 0) {
|
|
||||||
ByteBuf player_bytes = buffer.readBytes(player_len);
|
|
||||||
playerName = player_bytes.toString(StandardCharsets.UTF_8);
|
|
||||||
} else {
|
|
||||||
playerName = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void encode(ByteBuf buffer) {
|
|
||||||
if (classType == null) {
|
|
||||||
buffer.writeInt(0);
|
|
||||||
} else {
|
|
||||||
String name = classType.getName();
|
|
||||||
byte[] name_bytes = name.getBytes(StandardCharsets.UTF_8);
|
|
||||||
buffer.writeInt(name_bytes.length);
|
|
||||||
buffer.writeBytes(name_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.writeBoolean(ignoreBattle);
|
|
||||||
buffer.writeInt(attackPower);
|
|
||||||
buffer.writeInt(attackProbability);
|
|
||||||
buffer.writeInt(attackVariance);
|
|
||||||
|
|
||||||
String effect_name = attackEffect.toString();
|
|
||||||
byte[] effect_bytes = effect_name.getBytes(StandardCharsets.UTF_8);
|
|
||||||
buffer.writeInt(effect_bytes.length);
|
|
||||||
buffer.writeBytes(effect_bytes);
|
|
||||||
|
|
||||||
buffer.writeInt(attackEffectProbability);
|
|
||||||
buffer.writeInt(defenseDamage);
|
|
||||||
buffer.writeInt(defenseDamageProbability);
|
|
||||||
buffer.writeInt(evasion);
|
|
||||||
buffer.writeInt(speed);
|
|
||||||
buffer.writeInt(hasteSpeed);
|
|
||||||
buffer.writeInt(slowSpeed);
|
|
||||||
|
|
||||||
byte[] category_bytes = category.getBytes(StandardCharsets.UTF_8);
|
|
||||||
buffer.writeInt(category_bytes.length);
|
|
||||||
buffer.writeBytes(category_bytes);
|
|
||||||
|
|
||||||
buffer.writeInt(decisionAttack);
|
|
||||||
buffer.writeInt(decisionDefend);
|
|
||||||
buffer.writeInt(decisionFlee);
|
|
||||||
|
|
||||||
if (customName.isEmpty()) {
|
|
||||||
buffer.writeInt(0);
|
|
||||||
} else {
|
|
||||||
byte[] custom_bytes = customName.getBytes(StandardCharsets.UTF_8);
|
|
||||||
buffer.writeInt(custom_bytes.length);
|
|
||||||
buffer.writeBytes(custom_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (playerName.isEmpty()) {
|
|
||||||
buffer.writeInt(0);
|
|
||||||
} else {
|
|
||||||
byte[] player_bytes = playerName.getBytes(StandardCharsets.UTF_8);
|
|
||||||
buffer.writeInt(player_bytes.length);
|
|
||||||
buffer.writeBytes(player_bytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common;
|
|
||||||
|
|
||||||
import net.neoforged.bus.api.SubscribeEvent;
|
|
||||||
import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent;
|
|
||||||
|
|
||||||
public class HurtEventHandler {
|
|
||||||
@SubscribeEvent
|
|
||||||
public void handleHurtEvent(LivingIncomingDamageEvent event) {
|
|
||||||
CommonProxy proxy = TurnBasedMinecraftMod.proxy;
|
|
||||||
if (event.getEntity().level().isClientSide || proxy.getBattleManager() == null) {
|
|
||||||
return;
|
|
||||||
} else if (proxy.getConfig().getIgnoreHurtDamageSources().contains(event.getSource().getMsgId()) && proxy.getBattleManager().isInBattle(event.getEntity())) {
|
|
||||||
event.setCanceled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common;
|
|
||||||
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.neoforged.bus.api.SubscribeEvent;
|
|
||||||
import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent;
|
|
||||||
|
|
||||||
public class PlayerJoinEventHandler
|
|
||||||
{
|
|
||||||
@SubscribeEvent
|
|
||||||
public void entityJoinHandler(EntityJoinLevelEvent event)
|
|
||||||
{
|
|
||||||
if(event.getLevel().isClientSide)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(event.getEntity() instanceof Player && TurnBasedMinecraftMod.proxy.getConfig().getBattleDisabledForAll())
|
|
||||||
{
|
|
||||||
TurnBasedMinecraftMod.proxy.getConfig().addBattleIgnoringPlayer(event.getEntity().getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.client.ClientConfig;
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.client.ClientConfigGui;
|
|
||||||
import net.neoforged.api.distmarker.Dist;
|
|
||||||
import net.neoforged.fml.ModContainer;
|
|
||||||
import net.neoforged.fml.common.Mod;
|
|
||||||
import net.neoforged.neoforge.client.gui.IConfigScreenFactory;
|
|
||||||
|
|
||||||
@Mod(value = TurnBasedMinecraftMod.MODID, dist = Dist.CLIENT)
|
|
||||||
public class TBMM_Client {
|
|
||||||
public TBMM_Client(ModContainer container) {
|
|
||||||
container.registerExtensionPoint(IConfigScreenFactory.class, ClientConfigGui::new);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common;
|
|
||||||
|
|
||||||
import net.minecraft.core.component.DataComponents;
|
|
||||||
import net.minecraft.core.registries.Registries;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraft.world.item.ArrowItem;
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
|
|
||||||
public class Utility
|
|
||||||
{
|
|
||||||
public static float yawDirection(double posX, double posZ, double targetX, double targetZ)
|
|
||||||
{
|
|
||||||
double radians = Math.atan2(targetZ - posZ, targetX - posX);
|
|
||||||
radians = (radians - Math.PI / 2.0);
|
|
||||||
if(radians < 0.0)
|
|
||||||
{
|
|
||||||
radians += Math.PI * 2.0;
|
|
||||||
}
|
|
||||||
return (float)(radians * 180.0 / Math.PI);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static float pitchDirection(double posX, double posY, double posZ, double targetX, double targetY, double targetZ)
|
|
||||||
{
|
|
||||||
double diffX = targetX - posX;
|
|
||||||
double diffY = targetY - posY;
|
|
||||||
double diffZ = targetZ - posZ;
|
|
||||||
double distance = Math.sqrt(diffX * diffX + diffZ * diffZ);
|
|
||||||
if(Math.abs(diffY) < 0.1)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return (float)(-Math.atan(diffY / distance) * 180.0 / Math.PI);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean doesPlayerHaveArrows(Player player)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < player.getInventory().getContainerSize(); ++i)
|
|
||||||
{
|
|
||||||
if(player.getInventory().getItem(i).getItem() instanceof ArrowItem)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double distanceBetweenEntities(Entity a, Entity b)
|
|
||||||
{
|
|
||||||
return Math.sqrt(Math.pow(a.getX() - b.getX(), 2.0) + Math.pow(a.getY()- b.getY(), 2.0) + Math.pow(a.getZ()- b.getZ(), 2.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String serializeDimension(ResourceKey<Level> dimObject) {
|
|
||||||
return dimObject.registry().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ResourceKey<Level> deserializeDimension(String dimString) {
|
|
||||||
ResourceLocation dimRes = ResourceLocation.parse(dimString);
|
|
||||||
return ResourceKey.create(Registries.DIMENSION, dimRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isItemEdible(ItemStack itemStack, @Nullable LivingEntity entity) {
|
|
||||||
return itemStack.get(DataComponents.CONSUMABLE) != null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common.networking;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.Battle;
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
|
||||||
import net.minecraft.network.codec.StreamCodec;
|
|
||||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadHandler;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public record PacketBattleDecision(int battleID, int decision, int targetIDorItemID) implements CustomPacketPayload
|
|
||||||
{
|
|
||||||
public static final CustomPacketPayload.Type<PacketBattleDecision> TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(TurnBasedMinecraftMod.MODID, "network_packetbattledecision"));
|
|
||||||
|
|
||||||
public static final StreamCodec<ByteBuf, PacketBattleDecision> STREAM_CODEC = StreamCodec.composite(
|
|
||||||
ByteBufCodecs.INT,
|
|
||||||
PacketBattleDecision::battleID,
|
|
||||||
ByteBufCodecs.VAR_INT,
|
|
||||||
PacketBattleDecision::decision,
|
|
||||||
ByteBufCodecs.INT,
|
|
||||||
PacketBattleDecision::targetIDorItemID,
|
|
||||||
PacketBattleDecision::new
|
|
||||||
);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Type<? extends CustomPacketPayload> type() {
|
|
||||||
return TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class PayloadHandler implements IPayloadHandler<PacketBattleDecision> {
|
|
||||||
@Override
|
|
||||||
public void handle(final @NotNull PacketBattleDecision pkt, final IPayloadContext ctx) {
|
|
||||||
ctx.enqueueWork(() -> {
|
|
||||||
Battle b = TurnBasedMinecraftMod.proxy.getBattleManager().getBattleByID(pkt.battleID);
|
|
||||||
if(b != null) {
|
|
||||||
Player player = ctx.player();
|
|
||||||
b.setDecision(player.getId(), Battle.Decision.valueOf(pkt.decision), pkt.targetIDorItemID);
|
|
||||||
}
|
|
||||||
}).exceptionally(e -> {
|
|
||||||
ctx.disconnect(Component.literal("Exception handling PacketBattleDecision! " + e.getMessage()));
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common.networking;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.CommonProxy;
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
|
||||||
import net.minecraft.network.codec.StreamCodec;
|
|
||||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadHandler;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
public record PacketBattleInfo(int battleID, Collection<Integer> sideA, Collection<Integer> sideB, long decisionNanos, long maxDecisionNanos, boolean turnTimerEnabled) implements CustomPacketPayload
|
|
||||||
{
|
|
||||||
public static final CustomPacketPayload.Type<PacketBattleInfo> TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(TurnBasedMinecraftMod.MODID, "network_packetbattleinfo"));
|
|
||||||
|
|
||||||
public static final StreamCodec<ByteBuf, PacketBattleInfo> STREAM_CODEC = StreamCodec.composite(
|
|
||||||
ByteBufCodecs.INT,
|
|
||||||
PacketBattleInfo::battleID,
|
|
||||||
CommonProxy.COLLECTION_INT_CODEC,
|
|
||||||
PacketBattleInfo::sideA,
|
|
||||||
CommonProxy.COLLECTION_INT_CODEC,
|
|
||||||
PacketBattleInfo::sideB,
|
|
||||||
ByteBufCodecs.VAR_LONG,
|
|
||||||
PacketBattleInfo::decisionNanos,
|
|
||||||
ByteBufCodecs.VAR_LONG,
|
|
||||||
PacketBattleInfo::maxDecisionNanos,
|
|
||||||
ByteBufCodecs.BOOL,
|
|
||||||
PacketBattleInfo::turnTimerEnabled,
|
|
||||||
PacketBattleInfo::new
|
|
||||||
);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Type<? extends CustomPacketPayload> type() {
|
|
||||||
return TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class PayloadHandler implements IPayloadHandler<PacketBattleInfo> {
|
|
||||||
@Override
|
|
||||||
public void handle(final @NotNull PacketBattleInfo pkt, final IPayloadContext ctx) {
|
|
||||||
ctx.enqueueWork(() -> {
|
|
||||||
if(TurnBasedMinecraftMod.proxy.getLocalBattle() == null)
|
|
||||||
{
|
|
||||||
TurnBasedMinecraftMod.proxy.createLocalBattle(pkt.battleID);
|
|
||||||
}
|
|
||||||
TurnBasedMinecraftMod.proxy.getLocalBattle().clearCombatants();
|
|
||||||
for(Integer id : pkt.sideA)
|
|
||||||
{
|
|
||||||
Entity e = Minecraft.getInstance().level.getEntity(id);
|
|
||||||
if(e != null)
|
|
||||||
{
|
|
||||||
TurnBasedMinecraftMod.proxy.getLocalBattle().addCombatantToSideA(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(Integer id : pkt.sideB)
|
|
||||||
{
|
|
||||||
Entity e = Minecraft.getInstance().level.getEntity(id);
|
|
||||||
if(e != null)
|
|
||||||
{
|
|
||||||
TurnBasedMinecraftMod.proxy.getLocalBattle().addCombatantToSideB(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TurnBasedMinecraftMod.proxy.setBattleGuiAsGui();
|
|
||||||
TurnBasedMinecraftMod.proxy.setBattleGuiTime((int)(pkt.decisionNanos / 1000000000L));
|
|
||||||
TurnBasedMinecraftMod.proxy.setBattleGuiBattleChanged();
|
|
||||||
TurnBasedMinecraftMod.proxy.setBattleGuiTurnTimerEnabled(pkt.turnTimerEnabled);
|
|
||||||
TurnBasedMinecraftMod.proxy.setBattleGuiTurnTimerMax((int)(pkt.maxDecisionNanos / 1000000000L));
|
|
||||||
}).exceptionally(e -> {
|
|
||||||
ctx.disconnect(Component.literal("Exception handling PacketBattleInfo! " + e.getMessage()));
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,203 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common.networking;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.Utility;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
|
||||||
import net.minecraft.network.codec.StreamCodec;
|
|
||||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import net.neoforged.fml.loading.FMLEnvironment;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadHandler;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class PacketBattleMessage implements CustomPacketPayload
|
|
||||||
{
|
|
||||||
public static final CustomPacketPayload.Type<PacketBattleMessage> TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(TurnBasedMinecraftMod.MODID, "network_packetbattlemessage"));
|
|
||||||
|
|
||||||
public static final StreamCodec<ByteBuf, PacketBattleMessage> STREAM_CODEC = StreamCodec.composite(
|
|
||||||
ByteBufCodecs.VAR_INT.map(MessageType::valueOf, MessageType::getValue),
|
|
||||||
PacketBattleMessage::getMessageType,
|
|
||||||
ByteBufCodecs.INT,
|
|
||||||
PacketBattleMessage::getEntityIDFrom,
|
|
||||||
ByteBufCodecs.INT,
|
|
||||||
PacketBattleMessage::getEntityIDTo,
|
|
||||||
ByteBufCodecs.STRING_UTF8.map(Utility::deserializeDimension, Utility::serializeDimension),
|
|
||||||
PacketBattleMessage::getDimension,
|
|
||||||
ByteBufCodecs.INT,
|
|
||||||
PacketBattleMessage::getAmount,
|
|
||||||
ByteBufCodecs.STRING_UTF8,
|
|
||||||
PacketBattleMessage::getCustom,
|
|
||||||
PacketBattleMessage::new
|
|
||||||
);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Type<? extends CustomPacketPayload> type() {
|
|
||||||
return TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum MessageType
|
|
||||||
{
|
|
||||||
ENTERED(0),
|
|
||||||
FLEE(1),
|
|
||||||
DIED(2),
|
|
||||||
ENDED(3),
|
|
||||||
ATTACK(4),
|
|
||||||
DEFEND(5),
|
|
||||||
DEFENSE_DAMAGE(6),
|
|
||||||
MISS(7),
|
|
||||||
DEFENDING(8),
|
|
||||||
DID_NOTHING(9),
|
|
||||||
USED_ITEM(10),
|
|
||||||
TURN_BEGIN(11),
|
|
||||||
TURN_END(12),
|
|
||||||
SWITCHED_ITEM(13),
|
|
||||||
WAS_AFFECTED(14),
|
|
||||||
BECAME_CREATIVE(15),
|
|
||||||
FIRED_ARROW(16),
|
|
||||||
ARROW_HIT(17),
|
|
||||||
BOW_NO_AMMO(18),
|
|
||||||
CREEPER_WAIT(19),
|
|
||||||
CREEPER_WAIT_FINAL(20),
|
|
||||||
CREEPER_EXPLODE(21),
|
|
||||||
CROSSBOW_NO_AMMO(22);
|
|
||||||
|
|
||||||
private int value;
|
|
||||||
private static Map<Integer, MessageType> map = new HashMap<Integer, MessageType>();
|
|
||||||
|
|
||||||
MessageType(int value)
|
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getValue()
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
for(MessageType type : MessageType.values())
|
|
||||||
{
|
|
||||||
map.put(type.getValue(), type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MessageType valueOf(int value)
|
|
||||||
{
|
|
||||||
return map.get(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum UsedItemAction
|
|
||||||
{
|
|
||||||
USED_NOTHING(0),
|
|
||||||
USED_INVALID(1),
|
|
||||||
USED_FOOD(2),
|
|
||||||
USED_POTION(3);
|
|
||||||
|
|
||||||
private int value;
|
|
||||||
private static Map<Integer, UsedItemAction> map = new HashMap<Integer, UsedItemAction>();
|
|
||||||
|
|
||||||
UsedItemAction(int value)
|
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getValue()
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
for(UsedItemAction type : UsedItemAction.values())
|
|
||||||
{
|
|
||||||
map.put(type.getValue(), type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static UsedItemAction valueOf(int value)
|
|
||||||
{
|
|
||||||
return map.get(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageType messageType;
|
|
||||||
int entityIDFrom;
|
|
||||||
int entityIDTo;
|
|
||||||
int amount;
|
|
||||||
String custom;
|
|
||||||
ResourceKey<Level> dimension;
|
|
||||||
|
|
||||||
public MessageType getMessageType() {
|
|
||||||
return messageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getEntityIDFrom() {
|
|
||||||
return entityIDFrom;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getEntityIDTo() {
|
|
||||||
return entityIDTo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getAmount() {
|
|
||||||
return amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCustom() {
|
|
||||||
return custom;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResourceKey<Level> getDimension() {
|
|
||||||
return dimension;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDimensionSerialized() {
|
|
||||||
return Utility.serializeDimension(dimension);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PacketBattleMessage() { custom = new String(); }
|
|
||||||
|
|
||||||
public PacketBattleMessage(MessageType messageType, int entityIDFrom, int entityIDTo, ResourceKey<Level> dimension, int amount)
|
|
||||||
{
|
|
||||||
this.messageType = messageType;
|
|
||||||
this.entityIDFrom = entityIDFrom;
|
|
||||||
this.entityIDTo = entityIDTo;
|
|
||||||
this.dimension = dimension;
|
|
||||||
this.amount = amount;
|
|
||||||
custom = new String();
|
|
||||||
}
|
|
||||||
|
|
||||||
public PacketBattleMessage(MessageType messageType, int entityIDFrom, int entityIDTo, ResourceKey<Level> dimension, int amount, String custom)
|
|
||||||
{
|
|
||||||
this.messageType = messageType;
|
|
||||||
this.entityIDFrom = entityIDFrom;
|
|
||||||
this.entityIDTo = entityIDTo;
|
|
||||||
this.dimension = dimension;
|
|
||||||
this.amount = amount;
|
|
||||||
this.custom = custom;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class PayloadHandler implements IPayloadHandler<PacketBattleMessage> {
|
|
||||||
@Override
|
|
||||||
public void handle(final @NotNull PacketBattleMessage pkt, final IPayloadContext ctx) {
|
|
||||||
ctx.enqueueWork(() -> {
|
|
||||||
if (FMLEnvironment.dist.isClient()) {
|
|
||||||
TurnBasedMinecraftMod.proxy.handlePacket(pkt, ctx);
|
|
||||||
}
|
|
||||||
}).exceptionally(e -> {
|
|
||||||
ctx.disconnect(Component.literal("Exception handling PacketBattleMessage! " + e.getMessage()));
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common.networking;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
|
||||||
import net.minecraft.network.codec.StreamCodec;
|
|
||||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadHandler;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public record PacketBattlePing(int battleID, int remainingSeconds) implements CustomPacketPayload {
|
|
||||||
public static final CustomPacketPayload.Type<PacketBattlePing> TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(TurnBasedMinecraftMod.MODID, "network_packetbattleping"));
|
|
||||||
|
|
||||||
public static final StreamCodec<ByteBuf, PacketBattlePing> STREAM_CODEC = StreamCodec.composite(
|
|
||||||
ByteBufCodecs.INT,
|
|
||||||
PacketBattlePing::battleID,
|
|
||||||
ByteBufCodecs.VAR_INT,
|
|
||||||
PacketBattlePing::remainingSeconds,
|
|
||||||
PacketBattlePing::new
|
|
||||||
);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Type<? extends CustomPacketPayload> type() {
|
|
||||||
return TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class PayloadHandler implements IPayloadHandler<PacketBattlePing> {
|
|
||||||
@Override
|
|
||||||
public void handle(final @NotNull PacketBattlePing pkt, IPayloadContext ctx) {
|
|
||||||
ctx.enqueueWork(() -> {
|
|
||||||
if (TurnBasedMinecraftMod.proxy.getLocalBattle() != null) {
|
|
||||||
TurnBasedMinecraftMod.proxy.setBattleGuiAsGui();
|
|
||||||
TurnBasedMinecraftMod.proxy.setBattleGuiBattleChanged();
|
|
||||||
TurnBasedMinecraftMod.proxy.setBattleGuiTime(pkt.remainingSeconds);
|
|
||||||
TurnBasedMinecraftMod.proxy.pauseMCMusic();
|
|
||||||
}
|
|
||||||
}).exceptionally(e -> {
|
|
||||||
ctx.disconnect(Component.literal("Exception handling PacketBattlePing! " + e.getMessage()));
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common.networking;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.Battle;
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
|
||||||
import net.minecraft.network.codec.StreamCodec;
|
|
||||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadHandler;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public record PacketBattleRequestInfo(int battleID) implements CustomPacketPayload
|
|
||||||
{
|
|
||||||
public static final CustomPacketPayload.Type<PacketBattleRequestInfo> TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(TurnBasedMinecraftMod.MODID, "network_packetbattlerequestinfo"));
|
|
||||||
|
|
||||||
public static final StreamCodec<ByteBuf, PacketBattleRequestInfo> STREAM_CODEC = StreamCodec.composite(
|
|
||||||
ByteBufCodecs.INT,
|
|
||||||
PacketBattleRequestInfo::battleID,
|
|
||||||
PacketBattleRequestInfo::new
|
|
||||||
);
|
|
||||||
|
|
||||||
public PacketBattleRequestInfo(int battleID)
|
|
||||||
{
|
|
||||||
this.battleID = battleID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Type<? extends CustomPacketPayload> type() {
|
|
||||||
return TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class PayloadHandler implements IPayloadHandler<PacketBattleRequestInfo> {
|
|
||||||
@Override
|
|
||||||
public void handle(final @NotNull PacketBattleRequestInfo pkt, final IPayloadContext ctx) {
|
|
||||||
ctx.enqueueWork(() -> {
|
|
||||||
Battle b = TurnBasedMinecraftMod.proxy.getBattleManager().getBattleByID(pkt.battleID);
|
|
||||||
if(b == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ctx.reply(new PacketBattleInfo(
|
|
||||||
b.getId(),
|
|
||||||
b.getSideAIDs(),
|
|
||||||
b.getSideBIDs(),
|
|
||||||
b.getTimerNanos(),
|
|
||||||
TurnBasedMinecraftMod.proxy.getConfig().getDecisionDurationNanos(),
|
|
||||||
!TurnBasedMinecraftMod.proxy.getConfig().isBattleDecisionDurationForever()));
|
|
||||||
}).exceptionally(e -> {
|
|
||||||
ctx.disconnect(Component.literal("Exception handling PacketBattleRequestInfo! " + e.getMessage()));
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common.networking;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
|
||||||
import net.minecraft.network.codec.StreamCodec;
|
|
||||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.neoforged.fml.loading.FMLEnvironment;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadHandler;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public record PacketClientGUI(int reserved) implements CustomPacketPayload {
|
|
||||||
public static final CustomPacketPayload.Type<PacketClientGUI> TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(TurnBasedMinecraftMod.MODID, "network_packetclientgui"));
|
|
||||||
|
|
||||||
public static final StreamCodec<ByteBuf, PacketClientGUI> STREAM_CODEC = StreamCodec.composite(
|
|
||||||
ByteBufCodecs.VAR_INT,
|
|
||||||
PacketClientGUI::reserved,
|
|
||||||
PacketClientGUI::new
|
|
||||||
);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Type<? extends CustomPacketPayload> type() {
|
|
||||||
return TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class PayloadHandler implements IPayloadHandler<PacketClientGUI> {
|
|
||||||
@Override
|
|
||||||
public void handle(final @NotNull PacketClientGUI pkt, final IPayloadContext ctx) {
|
|
||||||
ctx.enqueueWork(() -> {
|
|
||||||
if (FMLEnvironment.dist.isClient()) {
|
|
||||||
TurnBasedMinecraftMod.proxy.showClientConfigGui();
|
|
||||||
}
|
|
||||||
}).exceptionally(e -> {
|
|
||||||
ctx.disconnect(Component.literal("Exception handling PacketClientGUI! " + e.getMessage()));
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,151 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common.networking;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.EntityInfo;
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
|
||||||
import net.minecraft.network.codec.StreamCodec;
|
|
||||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.neoforged.fml.loading.FMLEnvironment;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadHandler;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class PacketEditingMessage implements CustomPacketPayload
|
|
||||||
{
|
|
||||||
public static final CustomPacketPayload.Type<PacketEditingMessage> TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(TurnBasedMinecraftMod.MODID, "network_packeteditingmessage"));
|
|
||||||
|
|
||||||
public static final StreamCodec<ByteBuf, PacketEditingMessage> STREAM_CODEC = StreamCodec.composite(
|
|
||||||
ByteBufCodecs.INT.map(Type::valueOf, Type::getValue),
|
|
||||||
PacketEditingMessage::getType,
|
|
||||||
StreamCodec.ofMember(EntityInfo::encode, EntityInfo::new),
|
|
||||||
PacketEditingMessage::getEntityInfo,
|
|
||||||
PacketEditingMessage::new
|
|
||||||
);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CustomPacketPayload.Type<? extends CustomPacketPayload> type() {
|
|
||||||
return TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Type
|
|
||||||
{
|
|
||||||
ATTACK_ENTITY(0),
|
|
||||||
PICK_EDIT(1),
|
|
||||||
EDIT_IGNORE_BATTLE(2),
|
|
||||||
EDIT_ATTACK_POWER(3),
|
|
||||||
EDIT_ATTACK_PROBABILITY(4),
|
|
||||||
EDIT_ATTACK_VARIANCE(5),
|
|
||||||
EDIT_ATTACK_EFFECT(6),
|
|
||||||
EDIT_ATTACK_EFFECT_PROBABILITY(7),
|
|
||||||
EDIT_DEFENSE_DAMAGE(8),
|
|
||||||
EDIT_DEFENSE_DAMAGE_PROBABILITY(9),
|
|
||||||
EDIT_EVASION(10),
|
|
||||||
EDIT_SPEED(11),
|
|
||||||
EDIT_HASTE_SPEED(18),
|
|
||||||
EDIT_SLOW_SPEED(19),
|
|
||||||
EDIT_CATEGORY(12),
|
|
||||||
EDIT_DECISION_ATTACK(13),
|
|
||||||
EDIT_DECISION_DEFEND(14),
|
|
||||||
EDIT_DECISION_FLEE(15),
|
|
||||||
SERVER_EDIT(16),
|
|
||||||
PICK_PLAYER(17);
|
|
||||||
|
|
||||||
Type(int value)
|
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Map<Integer, Type> map;
|
|
||||||
private int value;
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
map = new HashMap<Integer, Type>();
|
|
||||||
for(Type t : values())
|
|
||||||
{
|
|
||||||
map.put(t.value, t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getValue()
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Type valueOf(int value)
|
|
||||||
{
|
|
||||||
return map.get(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Type type = Type.ATTACK_ENTITY;
|
|
||||||
EntityInfo entityInfo = new EntityInfo();
|
|
||||||
|
|
||||||
public Type getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EntityInfo getEntityInfo() {
|
|
||||||
return entityInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PacketEditingMessage() {}
|
|
||||||
|
|
||||||
public PacketEditingMessage(Type type)
|
|
||||||
{
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PacketEditingMessage(Type type, EntityInfo entityInfo)
|
|
||||||
{
|
|
||||||
this.type = type;
|
|
||||||
if(entityInfo != null)
|
|
||||||
{
|
|
||||||
this.entityInfo = entityInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public PacketEditingMessage(final FriendlyByteBuf buf) {
|
|
||||||
this.type = Type.valueOf(buf.readInt());
|
|
||||||
this.entityInfo = new EntityInfo();
|
|
||||||
try {
|
|
||||||
this.entityInfo.classType = this.entityInfo.getClass().getClassLoader().loadClass(buf.readUtf());
|
|
||||||
} catch (ClassNotFoundException e) { /* ignored */ }
|
|
||||||
this.entityInfo.ignoreBattle = buf.readBoolean();
|
|
||||||
this.entityInfo.attackPower = buf.readInt();
|
|
||||||
this.entityInfo.attackProbability = buf.readInt();
|
|
||||||
this.entityInfo.attackVariance = buf.readInt();
|
|
||||||
this.entityInfo.attackEffect = EntityInfo.Effect.fromString(buf.readUtf());
|
|
||||||
this.entityInfo.attackEffectProbability = buf.readInt();
|
|
||||||
this.entityInfo.defenseDamage = buf.readInt();
|
|
||||||
this.entityInfo.defenseDamageProbability = buf.readInt();
|
|
||||||
this.entityInfo.evasion = buf.readInt();
|
|
||||||
this.entityInfo.speed = buf.readInt();
|
|
||||||
this.entityInfo.category = buf.readUtf();
|
|
||||||
this.entityInfo.decisionAttack = buf.readInt();
|
|
||||||
this.entityInfo.decisionDefend = buf.readInt();
|
|
||||||
this.entityInfo.decisionFlee = buf.readInt();
|
|
||||||
this.entityInfo.customName = buf.readUtf();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class PayloadHandler implements IPayloadHandler<PacketEditingMessage> {
|
|
||||||
@Override
|
|
||||||
public void handle(final @NotNull PacketEditingMessage pkt, final IPayloadContext ctx) {
|
|
||||||
ctx.enqueueWork(() -> {
|
|
||||||
if (FMLEnvironment.dist.isClient()) {
|
|
||||||
TurnBasedMinecraftMod.proxy.handlePacket(pkt, ctx);
|
|
||||||
}
|
|
||||||
}).exceptionally(e -> {
|
|
||||||
ctx.disconnect(Component.literal("Exception handling PacketEditingMessage! " + e.getMessage()));
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +0,0 @@
|
||||||
package com.burnedkirby.TurnBasedMinecraft.common.networking;
|
|
||||||
|
|
||||||
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
|
||||||
import net.minecraft.network.codec.StreamCodec;
|
|
||||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.neoforged.fml.loading.FMLEnvironment;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
|
||||||
import net.neoforged.neoforge.network.handling.IPayloadHandler;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public record PacketGeneralMessage(String message) implements CustomPacketPayload
|
|
||||||
{
|
|
||||||
public static final CustomPacketPayload.Type<PacketGeneralMessage> TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(TurnBasedMinecraftMod.MODID, "network_packetgeneralmessage"));
|
|
||||||
|
|
||||||
public static final StreamCodec<ByteBuf, PacketGeneralMessage> STREAM_CODEC = StreamCodec.composite(
|
|
||||||
ByteBufCodecs.STRING_UTF8,
|
|
||||||
PacketGeneralMessage::message,
|
|
||||||
PacketGeneralMessage::new
|
|
||||||
);
|
|
||||||
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PacketGeneralMessage(String message)
|
|
||||||
{
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Type<? extends CustomPacketPayload> type() {
|
|
||||||
return TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class PayloadHandler implements IPayloadHandler<PacketGeneralMessage> {
|
|
||||||
@Override
|
|
||||||
public void handle(final @NotNull PacketGeneralMessage pkt, final IPayloadContext ctx) {
|
|
||||||
ctx.enqueueWork(() -> {
|
|
||||||
if (FMLEnvironment.dist.isClient()) {
|
|
||||||
TurnBasedMinecraftMod.proxy.handlePacket(pkt, ctx);
|
|
||||||
}
|
|
||||||
}).exceptionally(e -> {
|
|
||||||
ctx.disconnect(Component.literal("Exception handling PacketGeneralMessage! " + e.getMessage()));
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 60 KiB |
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"pack": {
|
|
||||||
"description": "TurnBasedMinecraft resources",
|
|
||||||
"pack_format": 3,
|
|
||||||
"_comment": "A pack_format of 3 should be used starting with Minecraft 1.11. All resources, including language files, should be lowercase (eg: en_us.lang). A pack_format of 2 will load your mod resources with LegacyV2Adapter, which requires language files to have uppercase letters (eg: en_US.lang)."
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
# This is an example neoforge.mods.toml file. It contains the data relating to the loading mods.
|
|
||||||
# There are several mandatory fields (#mandatory), and many more that are optional (#optional).
|
|
||||||
# The overall format is standard TOML format, v0.5.0.
|
|
||||||
# Note that there are a couple of TOML lists in this file.
|
|
||||||
# Find more information on toml format here: https://github.com/toml-lang/toml
|
|
||||||
# The name of the mod loader type to load - for regular FML @Mod mods it should be javafml
|
|
||||||
modLoader="javafml" #mandatory
|
|
||||||
|
|
||||||
# A version range to match for said mod loader - for regular FML @Mod it will be the FML version. This is currently 2.
|
|
||||||
loaderVersion="${loader_version_range}" #mandatory
|
|
||||||
|
|
||||||
# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties.
|
|
||||||
# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here.
|
|
||||||
license="${mod_license}"
|
|
||||||
|
|
||||||
# A URL to refer people to when problems occur with this mod
|
|
||||||
#issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional
|
|
||||||
|
|
||||||
# A list of mods - how many allowed here is determined by the individual mod loader
|
|
||||||
[[mods]] #mandatory
|
|
||||||
|
|
||||||
# The modid of the mod
|
|
||||||
modId="${mod_id}" #mandatory
|
|
||||||
|
|
||||||
# The version number of the mod
|
|
||||||
version="${mod_version}" #mandatory
|
|
||||||
|
|
||||||
# A display name for the mod
|
|
||||||
displayName="${mod_name}" #mandatory
|
|
||||||
|
|
||||||
# A URL to query for updates for this mod. See the JSON update specification https://docs.neoforged.net/docs/misc/updatechecker/
|
|
||||||
#updateJSONURL="https://change.me.example.invalid/updates.json" #optional
|
|
||||||
updateJSONURL="https://github.com/Stephen-Seo/TurnBasedMinecraftMod/raw/refs/heads/neoforge/update.json"
|
|
||||||
|
|
||||||
# A URL for the "homepage" for this mod, displayed in the mod UI
|
|
||||||
#displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional
|
|
||||||
|
|
||||||
# A file name (in the root of the mod JAR) containing a logo for display
|
|
||||||
#logoFile="examplemod.png" #optional
|
|
||||||
logoFile="assets/com_burnedkirby_turnbasedminecraft/tbmm_icon.png"
|
|
||||||
|
|
||||||
# A text field displayed in the mod UI
|
|
||||||
#credits="" #optional
|
|
||||||
|
|
||||||
# A text field displayed in the mod UI
|
|
||||||
authors="${mod_authors}" #optional
|
|
||||||
|
|
||||||
# The description text for the mod (multi line!) (#mandatory)
|
|
||||||
description='''${mod_description}'''
|
|
||||||
|
|
||||||
# The [[mixins]] block allows you to declare your mixin config to FML so that it gets loaded.
|
|
||||||
#[[mixins]]
|
|
||||||
#config="${mod_id}.mixins.json"
|
|
||||||
|
|
||||||
# The [[accessTransformers]] block allows you to declare where your AT file is.
|
|
||||||
# If this block is omitted, a fallback attempt will be made to load an AT from META-INF/accesstransformer.cfg
|
|
||||||
#[[accessTransformers]]
|
|
||||||
#file="META-INF/accesstransformer.cfg"
|
|
||||||
|
|
||||||
# The coremods config file path is not configurable and is always loaded from META-INF/coremods.json
|
|
||||||
|
|
||||||
# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional.
|
|
||||||
[[dependencies.${mod_id}]] #optional
|
|
||||||
# the modid of the dependency
|
|
||||||
modId="neoforge" #mandatory
|
|
||||||
# The type of the dependency. Can be one of "required", "optional", "incompatible" or "discouraged" (case insensitive).
|
|
||||||
# 'required' requires the mod to exist, 'optional' does not
|
|
||||||
# 'incompatible' will prevent the game from loading when the mod exists, and 'discouraged' will show a warning
|
|
||||||
type="required" #mandatory
|
|
||||||
# Optional field describing why the dependency is required or why it is incompatible
|
|
||||||
# reason="..."
|
|
||||||
# The version range of the dependency
|
|
||||||
versionRange="${neo_version_range}" #mandatory
|
|
||||||
# An ordering relationship for the dependency.
|
|
||||||
# BEFORE - This mod is loaded BEFORE the dependency
|
|
||||||
# AFTER - This mod is loaded AFTER the dependency
|
|
||||||
ordering="NONE"
|
|
||||||
# Side this dependency is applied on - BOTH, CLIENT, or SERVER
|
|
||||||
side="BOTH"
|
|
||||||
|
|
||||||
# Here's another dependency
|
|
||||||
[[dependencies.${mod_id}]]
|
|
||||||
modId="minecraft"
|
|
||||||
type="required"
|
|
||||||
# This version range declares a minimum of the current minecraft version up to but not including the next major version
|
|
||||||
versionRange="${minecraft_version_range}"
|
|
||||||
ordering="NONE"
|
|
||||||
side="BOTH"
|
|
||||||
|
|
||||||
# Features are specific properties of the game environment, that you may want to declare you require. This example declares
|
|
||||||
# that your mod requires GL version 3.2 or higher. Other features will be added. They are side aware so declaring this won't
|
|
||||||
# stop your mod loading on the server for example.
|
|
||||||
#[features.${mod_id}]
|
|
||||||
#openGLVersion="[3.2,)"
|
|
BIN
tbm-client-edit-cmd.png
Normal file
After Width: | Height: | Size: 6 KiB |
BIN
tbm-client-edit-config.jpg
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
tbm-client-edit-modlist.jpg
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
tbm-edit-custom-editing.jpg
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
tbm-edit-custom.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
tbm-edit-decision-attack.png
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
tbm-edit-levitation.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
tbm-edit-output.jpg
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
tbm-edit-post-battle.jpg
Normal file
After Width: | Height: | Size: 50 KiB |
BIN
tbm-edit-server-edit-ignore-battle-types.png
Normal file
After Width: | Height: | Size: 30 KiB |
BIN
tbm-edit-settings.jpg
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
tbm-edit-sheep.jpg
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
tbm-server-edit-damage-sources-set.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
tbm-server-edit-damage-sources.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
tbm-server-edit-full.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
tbm-server-edit-hover.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
tbm-server-edit-set-haste.png
Normal file
After Width: | Height: | Size: 5.8 KiB |
22
update.json
|
@ -1,22 +0,0 @@
|
||||||
{
|
|
||||||
"homepage": "https://github.com/Stephen-Seo/TurnBasedMinecraftMod",
|
|
||||||
"1.21.3": {
|
|
||||||
"1.26.5": "Config improvements, NeoForge 21.3.11-beta.\n https://github.com/Stephen-Seo/TurnBasedMinecraftMod/blob/neoforge/Changelog.md",
|
|
||||||
"1.26.4": "Add player-specific config, NeoForge 21.3.6-beta.\n https://github.com/Stephen-Seo/TurnBasedMinecraftMod/blob/neoforge/Changelog.md",
|
|
||||||
"1.26.3": "Ported to NeoForge 21.3.2-beta (MC 1.21.3), minor tweak to packet.\n https://github.com/Stephen-Seo/TurnBasedMinecraftMod/blob/neoforge/Changelog.md"
|
|
||||||
},
|
|
||||||
"1.21.1": {
|
|
||||||
"1.26.5-MC-1.21.1": "Config improvements, NeoForge 21.1.74.\n https://github.com/Stephen-Seo/TurnBasedMinecraftMod/blob/neoforge/Changelog.md",
|
|
||||||
"1.26.4-MC-1.21.1": "Add player-specific config, NeoForge 21.1.73.\n https://github.com/Stephen-Seo/TurnBasedMinecraftMod/blob/neoforge/Changelog.md",
|
|
||||||
"1.26.3-MC-1.21.1": "Minor tweak to packet.\n https://github.com/Stephen-Seo/TurnBasedMinecraftMod/blob/neoforge/Changelog.md",
|
|
||||||
"1.26.2": "Display Entities on attack menu in BattleGUI.\n https://github.com/Stephen-Seo/TurnBasedMinecraftMod/blob/neoforge/Changelog.md",
|
|
||||||
"1.26.1": "Ported to NeoForge 21.1.72, leave BattleGUI with Escape key, MC music paused in battle properly.\n https://github.com/Stephen-Seo/TurnBasedMinecraftMod/blob/neoforge/Changelog.md",
|
|
||||||
"1.26.0": "Ported to NeoForge 21.1.69, client config.\n https://github.com/Stephen-Seo/TurnBasedMinecraftMod/blob/neoforge/Changelog.md"
|
|
||||||
},
|
|
||||||
"promos": {
|
|
||||||
"1.21.3-latest": "1.26.5",
|
|
||||||
"1.21.3-recommended": "1.26.5",
|
|
||||||
"1.21.1-latest": "1.26.5-MC-1.21.1",
|
|
||||||
"1.21.1-recommended": "1.26.5-MC-1.21.1"
|
|
||||||
}
|
|
||||||
}
|
|