Compare commits

...

113 commits

Author SHA1 Message Date
Stephen Seo bba99d4e6a Update README.md 2024-01-30 11:14:01 +09:00
Stephen Seo 356502f722 Action: Check if release exists before releasing 2024-01-22 18:29:29 +09:00
Stephen Seo 75976c8d9a Enable "any_archLinux" act runner for building jar 2024-01-20 20:01:54 +09:00
Stephen Seo 62774b0b0c Fix Reproducibility.md
All checks were successful
Build TurnBasedMC and create Release / build-and-create-release (push) Successful in 6m57s
2024-01-17 14:51:42 +09:00
Stephen Seo 846840c3a7 Update README.md 2024-01-17 14:48:56 +09:00
Stephen Seo 43bb0c7059 Fix version in main mod class 2024-01-17 14:48:37 +09:00
Stephen Seo 288ed1cfd6 Update Reproducibility.md
Some checks failed
Build TurnBasedMC and create Release / build-and-create-release (push) Has been cancelled
2024-01-17 14:44:12 +09:00
Stephen Seo b8a32a490e Update Changelog.md 2024-01-17 14:43:21 +09:00
Stephen Seo ae3cbfe4f6 Bump version to 1.25.2, cleanup of gradle stuff 2024-01-17 14:42:55 +09:00
Stephen Seo 9a481f95d0 Update Changelog.md 2024-01-17 14:30:19 +09:00
Stephen Seo 24a29eaba6 Update Reproducibility.md 2024-01-17 14:29:31 +09:00
Stephen Seo 9fab572800 Fix usage of throwable potions in battle
Add (experimental) "right-click" support for items when "Use" is invoked
on an item in battle.
2024-01-17 14:29:19 +09:00
Stephen Seo 6f0c223c9d Update FAQ.md 2024-01-17 13:43:24 +09:00
Stephen Seo 17c39a5329 Update README.md 2024-01-17 13:38:59 +09:00
Stephen Seo 4879aaefd1 Update README.md 2024-01-17 13:35:09 +09:00
Stephen Seo 46f8e22c8b Update Changelog.md, Reproducibility.md 2024-01-16 22:20:09 +09:00
Stephen Seo 54afb08263 Update Reproducibility.md
All checks were successful
Build TurnBasedMC and create Release / build-and-create-release (push) Successful in 5m57s
2024-01-16 17:29:55 +09:00
Stephen Seo 2616e73407 Update Changelog.md 2024-01-16 17:24:22 +09:00
Stephen Seo edc3246bd1 Minor fixes to ItemSelectionButton 2024-01-16 17:10:24 +09:00
Stephen Seo b1b8451331 Update .gitignore 2024-01-16 16:58:48 +09:00
Stephen Seo f635badfe1 Bump version to 1.25.1 2024-01-16 16:58:39 +09:00
Stephen Seo fb2c4cd13c Update code for NeoForge 20.4.108-beta 2024-01-16 16:55:13 +09:00
Stephen Seo 830f4255bb Update Changelog.md 2024-01-16 14:15:29 +09:00
Stephen Seo 490518a58a Add "icon" for mod 2024-01-16 14:15:13 +09:00
Stephen Seo e3ba1abdae Remove unused mcmod.info file 2024-01-16 14:14:45 +09:00
Stephen Seo d564756c42 "Pin" j-ogg-vorbis version 2024-01-11 16:30:58 +09:00
Stephen Seo 64a7fb263f Tweak to forgejo action/workflow 2024-01-10 11:56:54 +09:00
Stephen Seo 52b1b5ee05 Minor tweak to FAQ.md 2024-01-09 11:16:06 +09:00
Stephen Seo 2e71ea97ad Minor fix to build-jar action/workflow 2024-01-08 18:34:00 +09:00
Stephen Seo f9178777ee Update README.md 2024-01-08 18:24:39 +09:00
Stephen Seo 9d4cd5c4e7 Update LICENSE year 2024-01-08 18:20:57 +09:00
Stephen Seo 85c4588470 Update FAQ.md 2024-01-08 17:31:03 +09:00
Stephen Seo 7770698947 Update README.md 2024-01-08 17:27:45 +09:00
Stephen Seo a3d4ae74ef Add FAQ.md 2024-01-08 17:25:43 +09:00
Stephen Seo f56891e1d0 Update Reproducibility.md
All checks were successful
Build TurnBasedMC and create Release / build-and-store-artifact (push) Successful in 8m22s
2024-01-08 15:41:33 +09:00
Stephen Seo d58ef1585a Update README.md 2024-01-08 15:37:48 +09:00
Stephen Seo 2cbad47b33 Update Changelog.md 2024-01-08 15:34:40 +09:00
Stephen Seo d57f18d6c2 Add support for ogg-vorbis audio files 2024-01-08 15:19:42 +09:00
Stephen Seo c0bbf92efc Bump version, add j-ogg-vorbis dependency
Updated README.md, Reproducibility.md, etc.
2024-01-08 15:19:31 +09:00
Stephen Seo 5708e46118 Tweak to build jar release action
All checks were successful
Build TurnBasedMC and store Artifact / build-and-store-artifact (push) Successful in 6m4s
2024-01-06 14:57:13 +09:00
Stephen Seo edf2d3926d Minor fix to build-jar action 2024-01-06 14:31:29 +09:00
Stephen Seo 3caf1d31bf Make release on tag with build artifact 2024-01-06 14:23:37 +09:00
Stephen Seo 01bf977fd6 Change build action to build tags only 2024-01-05 20:28:13 +09:00
Stephen Seo 75b710c3d4 Re-attempt build jar action
All checks were successful
Build TurnBasedMC and store Artifact / build-and-store-artifact (push) Successful in 5m36s
2024-01-05 20:18:53 +09:00
Stephen Seo 0c5e823839 Fix builds changing MANIFEST based on project dir 2024-01-05 20:17:39 +09:00
Stephen Seo c8e405f685 Remove build action for neoforge for now 2024-01-05 18:43:27 +09:00
Stephen Seo 29d45ea0f9 Attempt to reduce memory usage on neoforge build
Some checks failed
Build TurnBasedMC and store Artifact / build-and-store-artifact (push) Failing after 3m2s
2024-01-05 17:34:17 +09:00
Stephen Seo 63fb52e75f Fix artifact name of neoforge build action
Some checks are pending
Build TurnBasedMC and store Artifact / build-and-store-artifact (push) Waiting to run
2024-01-05 16:34:31 +09:00
Stephen Seo 4881f056f5 Output sha256sum of jars in action 2024-01-05 16:32:18 +09:00
Stephen Seo 3cc138dd47 Change repo clone dir name in action 2024-01-05 16:32:05 +09:00
Stephen Seo 8d15bbb593 Add forgejo build action for NeoForge branch
Some checks failed
Build TurnBasedMC and store Artifact / build-and-store-artifact (push) Failing after 20m33s
2024-01-05 15:46:40 +09:00
Stephen Seo 36b25b7d07 Fix newline for download links list 2024-01-01 12:37:45 +09:00
Stephen Seo 4801558716 Add modrinth.com link to README.md 2024-01-01 12:35:58 +09:00
Stephen Seo 69b72cadd8 Update README.md
Remove reference to `shadow` in README.md since jarJar is being used
instead for NeoForge builds.
2023-12-30 16:27:51 +09:00
Stephen Seo f245947686 Update Reproducibility.md 2023-12-30 14:01:30 +09:00
Stephen Seo 08b8c7d412 Update README.md
Reorder `Reproducibility` to be under `Building`.
2023-12-30 13:50:34 +09:00
Stephen Seo 8e3b028f6c Update Reproducibility.md 2023-12-30 12:35:32 +09:00
Stephen Seo 7c4d4b6eb8 Update README.md, add Reproducibility.md 2023-12-30 12:24:26 +09:00
Stephen Seo 02684bfbad Update README.md 2023-12-30 11:58:11 +09:00
Stephen Seo b00f500e36 Fix version in mcmod.info 2023-12-29 17:28:09 +09:00
Stephen Seo a1de902d69 Update Changelog.md 2023-12-29 17:26:14 +09:00
Stephen Seo c9bf87271d Update to NeoForge 20.2.88 2023-12-29 17:20:14 +09:00
Stephen Seo adb3a652f6 Update README.md 2023-12-28 12:23:00 +09:00
Stephen Seo 531cb65e1f Update LICENSE year 2023-12-28 12:16:34 +09:00
Stephen Seo 351fb1db55 v1.23.1 More robust possible damage source loading 2023-10-12 17:23:21 +09:00
Stephen Seo fab8e2d4a0 v1.23.0, forge 1.20.1-47.1.0 2023-09-19 18:49:49 +09:00
Stephen Seo 8e8771dfc6 Set ForgeGradle version to 6.0.6
ForgeGradle version will need to be manually updated, which should be
better than suddenly compiling with a different version of ForgeGradle
when compiling in the future, which may break the "reproducibility" in
reproducible builds.
2023-06-08 21:42:32 +09:00
Stephen Seo 2ae8f77b4d Apply build.gradle changes for reprod. builds
Updated gradle wrapper to 8.1.1.
Updated ForgeGradle to "6.0.+".
Updated "shadow" to "8.1.1".
2023-06-08 21:31:55 +09:00
Stephen Seo ac97776ba7
Update Changelog.md
Fix typo
2023-03-31 14:33:23 +09:00
Stephen Seo 275a613f0f Version 1.22.0: to Forge 1.19.3-44.1.1 2023-03-31 14:22:58 +09:00
Stephen Seo c8add16c86 Version 1.21.4, bug fix
Fix bug where client may not be able to attack entities for which an entry did
not exist on the client-side config.
2022-09-02 19:46:26 +09:00
Stephen Seo c6b0cd9d26 More refactoring of check-if-in-battle code 2022-09-02 19:41:03 +09:00
Stephen Seo 80f37fc378 Update Changelog.md 2022-09-02 19:40:32 +09:00
Stephen Seo d837bebad6 Update Changelog.md 2022-09-02 15:24:43 +09:00
Stephen Seo 14f52a505e Update Changelog.md 2022-09-02 11:48:10 +09:00
Stephen Seo 240d6497ed Update Changelog.md 2022-09-01 22:05:28 +09:00
Stephen Seo 52a914b42d Update Changelog.md 2022-09-01 21:32:53 +09:00
Stephen Seo 2820fbd5fc Update README.md 2022-08-24 16:34:18 +09:00
Stephen Seo e447116e1d Impl. player_only_battles, v1.21.3
A server-side config option was added to enable "player_only_battles" where mobs
cannot enter battle. (I haven't actually tested this fully since I am only 1
person, so there may be bugs.) This can be edited via the config, or via the
`/tbm-server-edit` command.

Version bumped to 1.21.3 .
2022-08-24 12:18:32 +09:00
Stephen Seo 819aea162a Refactor entity-in-battle checking, v1.21.2 2022-08-23 15:01:14 +09:00
Stephen Seo 12e6583b1f Refactor entity-in-battle checking code, v1.21.1 2022-08-23 14:36:32 +09:00
Stephen Seo dbd4d3cdba
Update Changelog.md 2022-08-23 14:04:40 +09:00
Stephen Seo 972997a49b Updated mod to use forge 1.19.2-43.1.1 2022-08-23 13:55:09 +09:00
Stephen Seo abc0c55dc3 Update Changelog.md 2022-08-23 13:40:08 +09:00
Stephen Seo a3431b135e Impl ignore specific damage sources in battle
Fixes #1. (Damage is inhibited, but some things like amount of air while
underwater still decreases for the duration of being underwater regardless of
being in battle.)

Server-side config specifies which damage sources are ignored in battle. This
can also be set in-game with `/tbm-server-edit`.

Also updated config for entities which should reduce the amount of stuff printed
into the logs (sorry about that).
2022-08-23 13:30:10 +09:00
Stephen Seo ff326bcbe9 Update Changelog.md, year in LICENSE 2022-08-03 14:57:56 +09:00
Stephen Seo 74b9681253 Update for forge-1.19-41.1.0, mod ver. 1.19 2022-08-03 14:47:43 +09:00
Stephen Seo c4b10f1791
Update README.md 2022-07-21 14:28:31 +09:00
Stephen Seo 752d0c881e Bump network protocol version, version to 1.18.7 2022-07-21 14:19:21 +09:00
Stephen Seo d44b000570 Update Changelog.md 2022-07-21 14:08:53 +09:00
Stephen Seo a9d2b11f65 Fix turn-timer not matching server-side's value 2022-07-21 14:01:34 +09:00
Stephen Seo e8f3c0cd52 Impl "disable-turn-timer", mod version 1.18.6 2022-07-21 12:57:10 +09:00
Stephen Seo de5e66e98d Mod version 1.18.5 2022-06-14 14:16:51 +09:00
Stephen Seo 3624b56727 Fix Battle text output when drinking a potion 2022-06-14 14:14:22 +09:00
Stephen Seo cb4fda06e3 1.18.4 Fix battle hits, non-instant hits
Fix hits in battles not hitting due to invulnerability frames.

Changed hits to be spaced appart by approx. 15ms.
2022-06-10 16:57:48 +09:00
Stephen Seo 3b11975fe8
Update Changelog.md 2022-06-10 13:58:04 +09:00
Stephen Seo 9989d94cb1
Update README.md 2022-06-10 13:39:09 +09:00
Stephen Seo b2f7fd0456
Update README.md 2022-06-10 12:19:13 +09:00
Stephen Seo 53f1831518 Update Changelog.md 2022-06-10 12:13:35 +09:00
Stephen Seo 7ea5bb64b4 Update README.md 2022-06-10 12:06:26 +09:00
Stephen Seo c094f9b690 Impl in-game server config editing 2022-06-10 12:05:19 +09:00
Stephen Seo bfd584ad69 WIP 1.18.3: Impl in-game server config editing 2022-06-09 16:42:21 +09:00
Stephen Seo d9981da5fd Update Changelog.md 2022-06-08 19:24:32 +09:00
Stephen Seo 28291e5134 WIP 1.18.3: Impl editing of server config in-game
Fixed Battle not checking Player haste/speed status for using
"player_haste_speed" and "player_slow_speed".
2022-06-08 19:22:45 +09:00
Stephen Seo bc598c41b7 WIP 1.18.3: Allow editing of server config in-game 2022-06-08 15:24:29 +09:00
Stephen Seo 607ca015b1
Update README.md 2022-06-08 12:08:02 +09:00
Stephen Seo b060fb575f Update Changelog.md 2022-06-08 12:02:23 +09:00
Stephen Seo d9dbe39156 TBM 1.18.2: show team color in attack menu button
If a Player is in a team that has a specific team color, that Player's name will
be displayed with that color in the list of targets when selecting a target to
attack in the Battle GUI.
2022-06-08 11:59:34 +09:00
Stephen Seo c46828c58a Fix battle text output, v1.18.1
Battle text output now respects team colors of players in teams.
2022-06-03 14:51:17 +09:00
Stephen Seo 0c4c1ee090
Update Changelog.md 2022-05-18 14:16:23 +09:00
Stephen Seo bc080b2f6f Update for forge-1.18.2-40.1.0 (mod ver 1.18.0) 2022-05-17 16:10:18 +09:00
Stephen Seo 4306072329
Update README.md 2021-06-01 16:13:39 +09:00
Stephen Seo 31e9b0677b
Update README.md 2021-05-24 13:17:19 +09:00
48 changed files with 6253 additions and 3469 deletions

View file

@ -0,0 +1,50 @@
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: any_archLinux
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]\+m/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

1
.gitignore vendored
View file

@ -22,3 +22,4 @@ eclipse
run
logs/
runs/

View file

@ -1,5 +1,231 @@
# Upcoming changes
# 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.

77
FAQ.md Normal file
View file

@ -0,0 +1,77 @@
## 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.**
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.**
## 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?
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.

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2018-2020 Stephen Seo
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

View file

@ -2,12 +2,20 @@
This mod puts turn-based-combat of RPGs into Minecraft!
# Downloads
# Links/Downloads
Precompiled jars are available here:
https://seodisparate.com/static/tbm_releases/
https://burnedkirby.com/tbmm_downloads/
https://minecraft.curseforge.com/projects/turnbasedminecraft/files
https://www.curseforge.com/minecraft/mc-mods/turnbasedminecraft/files
https://modrinth.com/mod/turnbasedmc
https://git.seodisparate.com/stephenseo/TurnBasedMinecraftMod/releases
# 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
@ -38,14 +46,19 @@ When playing multiplayer, some configuration of the config on the server may be
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`~~, and `.mp3` 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).
- 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
@ -53,20 +66,32 @@ 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/reobfShadowJar/output.jar"
finished jar will be saved at
`build/libs/TurnBasedMinecraft-NeoForge-1.25.2-all.jar`
# Reproducibility
This mod should support reproducible builds. See `Reproducibility.md` to see
more details.
# Other notes
This mod uses [shadow](https://github.com/johnrengelman/shadow) which is
licenced under the [Apache License 2.0](https://github.com/johnrengelman/shadow/blob/master/LICENSE).
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/master/FAQ.md)
# Related Videos
[See related videos here](https://burnedkirby.com/tbmm_vids/)
[See related videos here](https://burnedkirby.com/posts/tbmm/)

109
Reproducibility.md Normal file
View file

@ -0,0 +1,109 @@
# 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.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

View file

@ -1,169 +1,139 @@
buildscript {
repositories {
maven { url = "https://files.minecraftforge.net/maven" }
jcenter()
mavenCentral()
}
dependencies {
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '4.1.+', changing: true
classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.4'
}
}
apply plugin: 'net.minecraftforge.gradle'
apply plugin: 'eclipse'
//apply plugin: 'maven-publish'
apply plugin: 'com.github.johnrengelman.shadow'
version = "1.17.2"
group = "com.burnedkirby.TurnBasedMinecraft"
archivesBaseName = "TurnBasedMinecraft"
java.toolchain.languageVersion = JavaLanguageVersion.of(8)
println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
minecraft {
// The mappings can be changed at any time, and must be in the following format.
// snapshot_YYYYMMDD Snapshot are built nightly.
// stable_# Stables are built at the discretion of the MCP team.
// Use non-default mappings at your own risk. they may not always work.
// Simply re-run your setup task after changing the mappings to update your workspace.
mappings channel: 'official', version: '1.16.5'
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
// accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
// Default run configurations.
// These can be tweaked, removed, or duplicated as needed.
runs {
client {
workingDirectory project.file('run')
// Recommended logging data for a userdev environment
property 'forge.logging.markers', 'REGISTRIES'
// Recommended logging level for the console
property 'forge.logging.console.level', 'debug'
mods {
TurnBasedMinecraftMod {
source sourceSets.main
}
}
}
server {
workingDirectory project.file('run')
// Recommended logging data for a userdev environment
property 'forge.logging.markers', 'REGISTRIES'
// Recommended logging level for the console
property 'forge.logging.console.level', 'debug'
mods {
TurnBasedMinecraftMod {
source sourceSets.main
}
}
}
data {
workingDirectory project.file('run')
// Recommended logging data for a userdev environment
property 'forge.logging.markers', 'REGISTRIES'
// Recommended logging level for the console
property 'forge.logging.console.level', 'debug'
args '--mod', 'TurnBasedMinecraftMod', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources')
mods {
TurnBasedMinecraftMod {
source sourceSets.main
}
}
}
}
}
// Include resources generated by data generators.
sourceSets.main.resources { srcDir 'src/generated/resources' }
dependencies {
// Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed
// that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied.
// The userdev artifact is a special name and will get all sorts of transformations applied to it.
minecraft 'net.minecraftforge:forge:1.16.5-36.1.0'
// You may put jars on which you depend on in ./libs or you may define them like so..
// compile "some.group:artifact:version:classifier"
// compile "some.group:artifact:version"
// Real examples
// compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
// compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
// The 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
// provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
// These dependencies get remapped to your current MCP mappings
// deobf 'com.mod-buildcraft:buildcraft:6.0.8:dev'
// For more info...
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
// http://www.gradle.org/docs/current/userguide/dependency_management.html
compile files('libs/javamp3-1.0.3.jar')
shadow files('libs/javamp3-1.0.3.jar')
}
shadowJar {
project.configurations.shadow.setTransitive(true);
configurations = [project.configurations.shadow]
relocate 'fr.delthas', 'com.burnedkirby.tbm_repack.fr.delthas'
classifier '' // replace the default jar
}
reobf {
shadowJar {} // reobfuscate the shadowed jar
}
// Example for how to get properties into the manifest for reading by the runtime..
jar {
manifest {
attributes([
"Specification-Title": "TurnBasedMinecraftMod",
"Specification-Vendor": "TurnBasedMinecraftMod_BK",
"Specification-Version": "1", // We are version 1 of ourselves
"Implementation-Title": project.name,
"Implementation-Version": "${version}",
"Implementation-Vendor" :"TurnBasedMinecraftMod_BK",
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
// "ContainedDeps": "javamp3-1.0.3.jar"
])
}
}
// Example configuration to allow publishing using the maven-publish task
// we define a custom artifact that is sourced from the reobfJar output task
// and then declare that to be published
// Note you'll need to add a repository here
//def reobfFile = file("$buildDir/reobfJar/output.jar")
//def reobfArtifact = artifacts.add('default', reobfFile) {
// type 'jar'
// builtBy 'reobfJar'
//}
//publishing {
// publications {
// mavenJava(MavenPublication) {
// artifact reobfArtifact
// }
// }
// repositories {
// maven {
// url "file:///${project.projectDir}/mcmodsrepo"
// }
// }
//}
plugins {
id 'eclipse'
id 'idea'
id 'maven-publish'
id 'net.neoforged.gradle.userdev' version '7.0.80'
}
version = mod_version
group = mod_group_id
archivesBaseName = "TurnBasedMinecraft-NeoForge"
java.toolchain.languageVersion = JavaLanguageVersion.of(17)
println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
jarJar.enable()
// Default run configurations.
// These can be tweaked, removed, or duplicated as needed.
runs {
// applies to all the run configs below
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
systemProperty 'forge.logging.console.level', 'debug'
modSource project.sourceSets.main
}
client {
// Comma-separated list of namespaces to load gametests from. Empty = all namespaces.
systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
}
server {
systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
programArgument '--nogui'
}
// 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 {
systemProperty 'forge.enabledGameTestNamespaces', project.mod_id
}
data {
// example of overriding the workingDirectory set in configureEach above, uncomment if you want to use it
// workingDirectory 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()
}
}
// Include resources generated by data generators.
sourceSets.main.resources { srcDir 'src/generated/resources' }
repositories {
flatDir {
dir 'libs'
}
}
dependencies {
// Specify the version of Minecraft to use.
// Depending on the plugin applied there are several options. We will assume you applied the userdev plugin as shown above.
// The group for userdev is net.neoforged, the module name is neoforge, and the version is the same as the neoforge version.
// You can however also use the vanilla plugin (net.neoforged.gradle.vanilla) to use a version of Minecraft without the neoforge loader.
// And its provides the option to then use net.minecraft as the group, and one of; client, server or joined as the module name, plus the game version as version.
// For all intends and purposes: You can treat this dependency as if it is a normal library you would use.
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(group: 'fr.delthas', name: 'javamp3', version: '[1.0.0,2.0.0)') {
jarJar.pin(it, '1.0.3')
}
jarJar(group: 'com.github.stephengold', name: 'j-ogg-vorbis', version: '[1.0.4, 2.0.0)') {
jarJar.pin(it, '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.
// When "copyIdeResources" is enabled, this will also run before the game launches in IDE environments.
// See https://docs.gradle.org/current/dsl/org.gradle.language.jvm.tasks.ProcessResources.html
tasks.withType(ProcessResources).configureEach {
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
filesMatching(['META-INF/mods.toml']) {
expand replaceProperties + [project: project]
}
}
// Example for how to get properties into the manifest for reading by the runtime..
jar {
archiveClassifier = 'slim'
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
}

42
gradle.properties Normal file
View file

@ -0,0 +1,42 @@
org.gradle.jvmargs=-Xmx4096m
org.gradle.daemon=false
org.gradle.debug=false
#read more on this at https://github.com/neoforged/NeoGradle/blob/NG_7.0/README.md#apply-parchment-mappings
# you can also find the latest versions at: https://parchmentmc.org/docs/getting-started
neogradle.subsystems.parchment.minecraftVersion=1.20.3
neogradle.subsystems.parchment.mappingsVersion=2023.12.31
# 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.20.4
# 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.20.4,1.21)
# The Neo version must agree with the Minecraft version to get a valid artifact
neo_version=20.4.109-beta
# The Neo version range can use any version of Neo as bounds
neo_version_range=[20.4,)
# The loader version range can only use the major version of FML as bounds
loader_version_range=[2,)
## 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.25.2
# 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.

Binary file not shown.

View file

@ -1,5 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

285
gradlew vendored
View file

@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# 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.
@ -17,67 +17,101 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# 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/subprojects/plugins/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
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# 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##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# 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"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
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
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
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
@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
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"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || 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
@ -106,80 +140,105 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
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=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=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# 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.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# 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
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
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" "$@"

181
gradlew.bat vendored
View file

@ -1,89 +1,92 @@
@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
@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=.
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%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
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%"=="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!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
@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
@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.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
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

14
settings.gradle Normal file
View file

@ -0,0 +1,14 @@
pluginManagement {
repositories {
gradlePluginPortal()
maven {
url = 'https://maven.neoforged.net/releases'
}
jcenter()
mavenCentral()
}
}
plugins {
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0'
}

View file

@ -1,33 +1,33 @@
package com.burnedkirby.TurnBasedMinecraft.client;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
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 com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.text.StringTextComponent;
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.network.chat.Component;
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 Matrix4f identity;
private enum MenuState {
MAIN_MENU(0), ATTACK_TARGET(1), ITEM_ACTION(2), WAITING(3), SWITCH_ITEM(4), USE_ITEM(5);
@ -84,14 +84,13 @@ public class BattleGui extends Screen {
}
public BattleGui() {
super(new StringTextComponent("Battle Gui"));
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;
identity = new Matrix4f();
identity.setIdentity();
}
private void setState(MenuState state) {
@ -110,7 +109,7 @@ public class BattleGui extends Screen {
if (TurnBasedMinecraftMod.proxy.getLocalBattle() != null) {
TurnBasedMinecraftMod.proxy.getLocalBattle().setState(Battle.State.DECISION);
}
timeRemaining.set(TurnBasedMinecraftMod.proxy.getConfig().getDecisionDurationSeconds());
timeRemaining.set(timerMax);
elapsedTime = 0;
lastInstant = System.nanoTime();
setState(MenuState.MAIN_MENU);
@ -126,23 +125,22 @@ public class BattleGui extends Screen {
}
stateChanged = false;
buttons.clear();
children.clear();
clearWidgets();
switch (state) {
case MAIN_MENU:
info = "What will you do?";
addButton(new Button(width * 3 / 7 - 25, 40, 50, 20, new StringTextComponent("Attack"), (button) -> {
addRenderableWidget(Button.builder(Component.literal("Attack"), (button) -> {
buttonActionEvent(button, ButtonAction.ATTACK);
}));
addButton(new Button(width * 4 / 7 - 25, 40, 50, 20, new StringTextComponent("Defend"), (button) -> {
}).bounds(width * 3 / 7 - 25, 40, 50, 20).build());
addRenderableWidget(Button.builder(Component.literal("Defend"), (button) -> {
buttonActionEvent(button, ButtonAction.DEFEND);
}));
addButton(new Button(width * 3 / 7 - 25, 60, 50, 20, new StringTextComponent("Item"), (button) -> {
}).bounds(width * 4 / 7 - 25, 40, 50, 20).build());
addRenderableWidget(Button.builder(Component.literal("Item"), (button) -> {
buttonActionEvent(button, ButtonAction.ITEM);
}));
addButton(new Button(width * 4 / 7 - 25, 60, 50, 20, new StringTextComponent("Flee"), (button) -> {
}).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?";
@ -151,12 +149,12 @@ public class BattleGui extends Screen {
for (Map.Entry<Integer, Combatant> e : TurnBasedMinecraftMod.proxy.getLocalBattle()
.getSideAEntrySet()) {
if (e.getValue().entity != null) {
addButton(new EntitySelectionButton(width / 4 - 60, y, 120, 20, e.getValue().entity.getName().getString(), e.getKey(), true, (button) -> {
buttonActionEvent(button, ButtonAction.ATTACK_TARGET);
addRenderableWidget(new EntitySelectionButton(width / 4 - 60, y, 120, 20, e.getValue().entity.getDisplayName(), e.getKey(), true, (button) -> {
entityButtonActionEvent(button, ButtonAction.ATTACK_TARGET);
}));
} else {
addButton(new EntitySelectionButton(width / 4 - 60, y, 120, 20, "Unknown", e.getKey(), true, (button) -> {
buttonActionEvent(button, ButtonAction.ATTACK_TARGET);
addRenderableWidget(new EntitySelectionButton(width / 4 - 60, y, 120, 20, "Unknown", e.getKey(), true, (button) -> {
entityButtonActionEvent(button, ButtonAction.ATTACK_TARGET);
}));
}
y += 20;
@ -169,12 +167,12 @@ public class BattleGui extends Screen {
for (Map.Entry<Integer, Combatant> e : TurnBasedMinecraftMod.proxy.getLocalBattle()
.getSideBEntrySet()) {
if (e.getValue().entity != null) {
addButton(new EntitySelectionButton(width * 3 / 4 - 60, y, 120, 20, e.getValue().entity.getName().getString(), e.getKey(), false, (button) -> {
buttonActionEvent(button, ButtonAction.ATTACK_TARGET);
addRenderableWidget(new EntitySelectionButton(width * 3 / 4 - 60, y, 120, 20, e.getValue().entity.getDisplayName(), e.getKey(), false, (button) -> {
entityButtonActionEvent(button, ButtonAction.ATTACK_TARGET);
}));
} else {
addButton(new EntitySelectionButton(width * 3 / 4 - 60, y, 120, 20, "Unknown", e.getKey(), false, (button) -> {
buttonActionEvent(button, ButtonAction.ATTACK_TARGET);
addRenderableWidget(new EntitySelectionButton(width * 3 / 4 - 60, y, 120, 20, "Unknown", e.getKey(), false, (button) -> {
entityButtonActionEvent(button, ButtonAction.ATTACK_TARGET);
}));
}
y += 20;
@ -182,21 +180,21 @@ public class BattleGui extends Screen {
} catch (ConcurrentModificationException e) {
// ignored
}
addButton(new Button(width / 2 - 30, height - 120, 60, 20, new StringTextComponent("Cancel"), (button) -> {
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?";
addButton(new Button(width * 1 / 4 - 40, height - 120, 80, 20, new StringTextComponent("Switch Held"), (button) -> {
addRenderableWidget(Button.builder(Component.literal("Switch Held"), (button) -> {
buttonActionEvent(button, ButtonAction.SWITCH_HELD_ITEM);
}));
addButton(new Button(width * 2 / 4 - 40, height - 120, 80, 20, new StringTextComponent("Use"), (button) -> {
}).bounds(width / 4 - 40, height - 120, 80, 20).build());
addRenderableWidget(Button.builder(Component.literal("Use"), (button) -> {
buttonActionEvent(button, ButtonAction.DECIDE_USE_ITEM);
}));
addButton(new Button(width * 3 / 4 - 40, height - 120, 80, 20, new StringTextComponent("Cancel"), (button) -> {
}).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...";
@ -204,33 +202,33 @@ public class BattleGui extends Screen {
case SWITCH_ITEM:
info = "To which item will you switch to?";
for (int i = 0; i < 9; ++i) {
addButton(new ItemSelectionButton(width / 2 - 88 + i * 20, height - 19, 16, 16, "", i, (button) -> {
buttonActionEvent(button, ButtonAction.DO_ITEM_SWITCH);
addRenderableWidget(new ItemSelectionButton(width / 2 - 88 + i * 20, height - 19, 16, 16, i, (button) -> {
itemButtonActionEvent(button, ButtonAction.DO_ITEM_SWITCH);
}));
}
addButton(new Button(width / 2 - 40, height - 120, 80, 20, new StringTextComponent("Cancel"), (button) -> {
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) {
addButton(new ItemSelectionButton(width / 2 - 88 + i * 20, height - 19, 16, 16, "", i, (button) -> {
buttonActionEvent(button, ButtonAction.DO_USE_ITEM);
addRenderableWidget(new ItemSelectionButton(width / 2 - 88 + i * 20, height - 19, 16, 16, i, (button) -> {
itemButtonActionEvent(button, ButtonAction.DO_USE_ITEM);
}));
}
addButton(new Button(width / 2 - 40, height - 120, 80, 20, new StringTextComponent("Cancel"), (button) -> {
addRenderableWidget(Button.builder(Component.literal("Cancel"), (button) -> {
buttonActionEvent(button, ButtonAction.CANCEL);
}));
}).bounds(width / 2 - 40, height - 120, 80, 20).build());
break;
}
}
@Override
public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) {
if (TurnBasedMinecraftMod.proxy.getLocalBattle() == null) {
// drawHoveringText("Waiting...", width / 2 - 50, height / 2);
drawString(matrixStack, "Waiting...", width / 2 - 50, height / 2, 0xFFFFFFFF);
drawString(guiGraphics, "Waiting...", width / 2 - 50, height / 2, 0xFFFFFFFF);
return;
}
if (TurnBasedMinecraftMod.proxy.getLocalBattle().getState() == Battle.State.DECISION
@ -246,53 +244,52 @@ public class BattleGui extends Screen {
updateState();
super.render(matrixStack, mouseX, mouseY, partialTicks);
super.render(guiGraphics, mouseX, mouseY, partialTicks);
String timeRemainingString = "Time remaining: ";
int timeRemainingInt = timeRemaining.get();
if (timeRemainingInt > 8) {
if (timeRemainingInt > 8 || !turnTimerEnabled) {
timeRemainingString += "\u00A7a";
} else if (timeRemainingInt > 4) {
timeRemainingString += "\u00A7e";
} else {
timeRemainingString += "\u00A7c";
}
timeRemainingString += Integer.toString(timeRemainingInt);
if (!turnTimerEnabled) {
timeRemainingString += "Infinity";
} else {
timeRemainingString += Integer.toString(timeRemainingInt);
}
int stringWidth = font.width(timeRemainingString);
fill(matrixStack, width / 2 - stringWidth / 2, 5, width / 2 + stringWidth / 2, 15, 0x70000000);
drawString(matrixStack, timeRemainingString, width / 2 - stringWidth / 2, 5, 0xFFFFFFFF);
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);
fill(matrixStack, width / 2 - stringWidth / 2, 20, width / 2 + stringWidth / 2, 30, 0x70000000);
drawString(matrixStack, info, width / 2 - stringWidth / 2, 20, 0xFFFFFFFF);
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(Button button, ButtonAction action) {
protected void buttonActionEvent(AbstractButton button, ButtonAction action) {
switch (action) {
case ATTACK:
setState(MenuState.ATTACK_TARGET);
break;
case DEFEND:
TurnBasedMinecraftMod.getHandler().sendToServer(new PacketBattleDecision(
TurnBasedMinecraftMod.proxy.getLocalBattle().getId(), Battle.Decision.DEFEND, 0));
PacketDistributor.SERVER.noArg().send(new PacketBattleDecision(
TurnBasedMinecraftMod.proxy.getLocalBattle().getId(), Battle.Decision.DEFEND, 0));
setState(MenuState.WAITING);
break;
case ITEM:
setState(MenuState.ITEM_ACTION);
break;
case FLEE:
TurnBasedMinecraftMod.getHandler().sendToServer(new PacketBattleDecision(
TurnBasedMinecraftMod.proxy.getLocalBattle().getId(), Battle.Decision.FLEE, 0));
PacketDistributor.SERVER.noArg().send(new PacketBattleDecision(
TurnBasedMinecraftMod.proxy.getLocalBattle().getId(), Battle.Decision.FLEE, 0));
setState(MenuState.WAITING);
break;
case ATTACK_TARGET:
if (button instanceof EntitySelectionButton) {
TurnBasedMinecraftMod.getHandler()
.sendToServer(new PacketBattleDecision(TurnBasedMinecraftMod.proxy.getLocalBattle().getId(),
Battle.Decision.ATTACK, ((EntitySelectionButton) button).getID()));
setState(MenuState.WAITING);
} else {
setState(MenuState.MAIN_MENU);
}
// Invalid, but set menu to main menu anyways.
setState(MenuState.MAIN_MENU);
break;
case SWITCH_HELD_ITEM:
setState(MenuState.SWITCH_ITEM);
@ -304,31 +301,50 @@ public class BattleGui extends Screen {
setState(MenuState.MAIN_MENU);
break;
case DO_ITEM_SWITCH:
if (button instanceof ItemSelectionButton) {
TurnBasedMinecraftMod.getHandler()
.sendToServer(new PacketBattleDecision(TurnBasedMinecraftMod.proxy.getLocalBattle().getId(),
Battle.Decision.SWITCH_ITEM, ((ItemSelectionButton) button).getID()));
if (((ItemSelectionButton) button).getID() >= 0 && ((ItemSelectionButton) button).getID() < 9) {
Minecraft.getInstance().player.inventory.selected = ((ItemSelectionButton) button).getID();
}
setState(MenuState.WAITING);
} else {
setState(MenuState.MAIN_MENU);
}
// Invalid, but set menu to main menu anyways.
setState(MenuState.MAIN_MENU);
break;
case DO_USE_ITEM:
if (button instanceof ItemSelectionButton) {
TurnBasedMinecraftMod.getHandler()
.sendToServer(new PacketBattleDecision(TurnBasedMinecraftMod.proxy.getLocalBattle().getId(),
Battle.Decision.USE_ITEM, ((ItemSelectionButton) button).getID()));
setState(MenuState.WAITING);
} else {
setState(MenuState.MAIN_MENU);
}
// 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.SERVER.noArg().send(
new PacketBattleDecision(TurnBasedMinecraftMod.proxy.getLocalBattle().getId(),
Battle.Decision.ATTACK, ((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.SERVER.noArg().send(
new PacketBattleDecision(TurnBasedMinecraftMod.proxy.getLocalBattle().getId(),
Battle.Decision.SWITCH_ITEM, 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.SERVER.noArg().send(
new PacketBattleDecision(TurnBasedMinecraftMod.proxy.getLocalBattle().getId(),
Battle.Decision.USE_ITEM, button.getID()));
setState(MenuState.WAITING);
break;
default:
setState(MenuState.MAIN_MENU);
break;
}
}
@Override
public boolean isPauseScreen() {
return false;
@ -354,7 +370,20 @@ public class BattleGui extends Screen {
timeRemaining.set(remaining);
}
private void drawString(MatrixStack matrixStack, String string, int x, int y, int color) {
font.draw(matrixStack, string, x, y, color);
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.
}
}

View file

@ -1,21 +1,19 @@
package com.burnedkirby.TurnBasedMinecraft.client;
import java.io.*;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
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 fr.delthas.javamp3.Sound;
import org.apache.logging.log4j.Logger;
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
import net.minecraft.client.Minecraft;
import java.io.*;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
public class BattleMusic
{
@ -31,7 +29,9 @@ public class BattleMusic
private boolean playingIsSilly;
private boolean isPlaying;
private Thread mp3StreamThread;
private Thread oggVorbisStreamThread;
private MP3Streamer mp3StreamRunnable;
private OGGVorbisStreamer oggVorbisStreamRunnable;
public BattleMusic(Logger logger)
{
@ -84,7 +84,7 @@ public class BattleMusic
}
String ext = name.substring(extIndex + 1).toLowerCase();
// return ext.equals("mid") || ext.equals("wav") || ext.equals("mp3");
return ext.equals("wav") || ext.equals("mp3"); // midi disabled
return ext.equals("wav") || ext.equals("mp3") || ext.equals("ogg"); // midi disabled
}
});
for(File f : battleFiles)
@ -104,7 +104,7 @@ public class BattleMusic
}
String ext = name.substring(extIndex + 1).toLowerCase();
// return ext.equals("mid") || ext.equals("wav") || ext.equals("mp3");
return ext.equals("wav") || ext.equals("mp3"); // midi disabled
return ext.equals("wav") || ext.equals("mp3") || ext.equals("ogg"); // midi disabled
}
});
for(File f : sillyFiles)
@ -306,6 +306,39 @@ public class BattleMusic
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;
}
}
}
}
@ -323,6 +356,10 @@ public class BattleMusic
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)
{
Minecraft.getInstance().getSoundManager().resume();
@ -457,4 +494,93 @@ public class BattleMusic
}
}
}
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(volume * 20.0f - 20.0f); // in decibels
}
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();
}
}
}
}

View file

@ -1,20 +1,49 @@
package com.burnedkirby.TurnBasedMinecraft.client;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.util.text.StringTextComponent;
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 extends Button {
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, Button.IPressable onPress) {
super(x, y, widthIn, heightIn, new StringTextComponent(buttonText), onPress);
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() {
@ -26,62 +55,87 @@ public class EntitySelectionButton extends Button {
}
@Override
public void renderButton(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
super.renderButton(matrixStack, mouseX, mouseY, partialTicks);
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 = getX();
int xpos = this.x;
int xoffset;
if (isSideA) {
xpos += getWidth() + 4;
xpos += this.width + 4;
xoffset = 4;
} else {
xpos -= 6;
xoffset = -4;
}
if (health > 200) {
fill(matrixStack, xpos, getY() + getHeight() * 4 / 5, xpos + 2, getY() + getHeight(), 0xFFFF0000);
fill(matrixStack, xpos, getY() + getHeight() * 3 / 5, xpos + 2, getY() + getHeight() * 4 / 5, 0xFFFFFF00);
fill(matrixStack, xpos, getY() + getHeight() * 2 / 5, xpos + 2, getY() + getHeight() * 3 / 5, 0xFF00FF00);
fill(matrixStack, xpos, getY() + getHeight() / 5, xpos + 2, getY() + getHeight() * 2 / 5, 0xFF00FFFF);
fill(matrixStack, xpos, getY(), xpos + 2, getY() + getHeight() / 5, 0xFF0000FF);
int healthHeight = ((health - 200) * getHeight() / 100);
fill(matrixStack, xpos + xoffset, getY() + getHeight() - healthHeight, xpos + xoffset + 2, getY() + getHeight(), 0xFFFFFFFF);
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) {
fill(matrixStack, xpos, getY() + getHeight() * 4 / 5, xpos + 2, getY() + getHeight(), 0xFFFF0000);
fill(matrixStack, xpos, getY() + getHeight() * 3 / 5, xpos + 2, getY() + getHeight() * 4 / 5, 0xFFFFFF00);
fill(matrixStack, xpos, getY() + getHeight() * 2 / 5, xpos + 2, getY() + getHeight() * 3 / 5, 0xFF00FF00);
fill(matrixStack, xpos, getY() + getHeight() / 5, xpos + 2, getY() + getHeight() * 2 / 5, 0xFF00FFFF);
int healthHeight = ((health - 100) * getHeight() / 100);
fill(matrixStack, xpos + xoffset, getY() + getHeight() - healthHeight, xpos + xoffset + 2, getY() + getHeight(), 0xFF0000FF);
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) {
fill(matrixStack, xpos, getY() + getHeight() * 4 / 5, xpos + 2, getY() + getHeight(), 0xFFFF0000);
fill(matrixStack, xpos, getY() + getHeight() * 3 / 5, xpos + 2, getY() + getHeight() * 4 / 5, 0xFFFFFF00);
fill(matrixStack, xpos, getY() + getHeight() * 2 / 5, xpos + 2, getY() + getHeight() * 3 / 5, 0xFF00FF00);
int healthHeight = ((health - 50) * getHeight() / 50);
fill(matrixStack, xpos + xoffset, getY() + getHeight() - healthHeight, xpos + xoffset + 2, getY() + getHeight(), 0xFF00FFFF);
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) {
fill(matrixStack, xpos, getY() + getHeight() * 4 / 5, xpos + 2, getY() + getHeight(), 0xFFFF0000);
fill(matrixStack, xpos, getY() + getHeight() * 3 / 5, xpos + 2, getY() + getHeight() * 4 / 5, 0xFFFFFF00);
int healthHeight = ((health - 20) * getHeight() / 30);
fill(matrixStack, xpos + xoffset, getY() + getHeight() - healthHeight, xpos + xoffset + 2, getY() + getHeight(), 0xFF00FF00);
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) {
fill(matrixStack, xpos, getY() + getHeight() * 4 / 5, xpos + 2, getY() + getHeight(), 0xFFFF0000);
int healthHeight = ((health - 10) * getHeight() / 10);
fill(matrixStack, xpos + xoffset, getY() + getHeight() - healthHeight, xpos + xoffset + 2, getY() + getHeight(), 0xFFFFFF00);
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 * getHeight() / 10);
fill(matrixStack, xpos + xoffset, getY() + getHeight() - healthHeight, xpos + xoffset + 2, getY() + getHeight(), 0xFFFF0000);
int healthHeight = (health * this.height / 10);
guiGraphics.fill(xpos + xoffset, this.y + this.height - healthHeight, xpos + xoffset + 2, this.y + this.height, 0xFFFF0000);
}
}
}
private int getX() {
return x;
public void onPress() {
onPress.onPress(this);
}
private int getY() {
return y;
@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;
}
}

View file

@ -1,14 +1,27 @@
package com.burnedkirby.TurnBasedMinecraft.client;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.client.gui.widget.button.Button;
import net.minecraft.util.text.StringTextComponent;
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 extends Button {
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, String buttonText, int itemStackID, Button.IPressable onPress) {
super(x, y, widthIn, heightIn, new StringTextComponent(buttonText), onPress);
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;
}
@ -17,22 +30,45 @@ public class ItemSelectionButton extends Button {
}
@Override
public void renderButton(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
if (visible) {
boolean hovered = mouseX >= getX() && mouseY >= getY() && mouseX < getX() + getWidth() && mouseY < getY() + getHeight();
if (hovered) {
fill(matrixStack, getX(), getY(), getX() + getWidth(), getY() + getHeight(), 0x80FFFFFF);
} else {
fill(matrixStack, getX(), getY(), getX() + getWidth(), getY() + getHeight(), 0x20707070);
}
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);
}
}
private int getX() {
return x;
public void onPress() {
onPress.onPress(this);
}
private int getY() {
return y;
@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;
}
}

View file

@ -0,0 +1,7 @@
package com.burnedkirby.TurnBasedMinecraft.client;
import net.minecraft.client.gui.components.AbstractButton;
public interface TBMButtonPress {
void onPress(AbstractButton button);
}

View file

@ -0,0 +1,5 @@
package com.burnedkirby.TurnBasedMinecraft.client;
public interface TBMEntityButtonPress {
void onPress(EntitySelectionButton button);
}

View file

@ -0,0 +1,5 @@
package com.burnedkirby.TurnBasedMinecraft.client;
public interface TBMItemButtonPress {
void onPress(ItemSelectionButton button);
}

View file

@ -6,12 +6,13 @@ import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketBattleMessage;
import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketEditingMessage;
import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketGeneralMessage;
import net.minecraft.entity.monster.CreeperEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.network.PacketDistributor;
import net.minecraft.world.damagesource.DamageTypes;
import net.minecraft.world.entity.monster.Creeper;
import net.minecraft.server.level.ServerPlayer;
import net.neoforged.neoforge.event.entity.living.LivingAttackEvent;
import net.neoforged.neoforge.event.entity.living.LivingChangeTargetEvent;
import net.neoforged.neoforge.network.PacketDistributor;
import net.neoforged.bus.api.SubscribeEvent;
public class AttackEventHandler
{
@ -38,7 +39,7 @@ public class AttackEventHandler
{
iter.remove();
}
else if(event.getSource().getEntity().equals(attacker.entity) && event.getSource().isProjectile())
else if(event.getSource().getEntity().equals(attacker.entity) && event.getSource().is(DamageTypes.ARROW))
{
iter.remove();
if(!isValid)
@ -60,7 +61,7 @@ public class AttackEventHandler
@SubscribeEvent
public void entityAttacked(LivingAttackEvent event)
{
if(event.getEntity().level.isClientSide)
if(event.getEntity().level().isClientSide)
{
return;
}
@ -81,7 +82,7 @@ public class AttackEventHandler
if(!event.getEntity().hasCustomName())
{
TurnBasedMinecraftMod.logger.error("Cannot edit custom name from entity without custom name");
TurnBasedMinecraftMod.getHandler().send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity)editingInfo.editor), new PacketGeneralMessage("Cannot edit custom name from entity without custom name"));
PacketDistributor.PLAYER.with((ServerPlayer)editingInfo.editor).send(new PacketGeneralMessage("Cannot edit custom name from entity without custom name"));
return;
}
editingInfo.entityInfo = config.getCustomEntityInfo(event.getEntity().getCustomName().getString());
@ -90,9 +91,9 @@ public class AttackEventHandler
editingInfo.entityInfo = new EntityInfo();
editingInfo.entityInfo.customName = event.getEntity().getCustomName().getString();
}
TurnBasedMinecraftMod.getHandler().send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity)editingInfo.editor), new PacketGeneralMessage("Editing custom name \"" + event.getEntity().getCustomName().getString() + "\""));
PacketDistributor.PLAYER.with((ServerPlayer)editingInfo.editor).send(new PacketGeneralMessage("Editing custom name \"" + event.getEntity().getCustomName().getString() + "\""));
TurnBasedMinecraftMod.logger.info("Begin editing custom \"" + event.getEntity().getCustomName().getString() + "\"");
TurnBasedMinecraftMod.getHandler().send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity)editingInfo.editor), new PacketEditingMessage(PacketEditingMessage.Type.PICK_EDIT, editingInfo.entityInfo));
PacketDistributor.PLAYER.with((ServerPlayer)editingInfo.editor).send(new PacketEditingMessage(PacketEditingMessage.Type.PICK_EDIT, editingInfo.entityInfo));
}
else
{
@ -106,9 +107,9 @@ public class AttackEventHandler
{
editingInfo.entityInfo = editingInfo.entityInfo.clone();
}
TurnBasedMinecraftMod.getHandler().send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity)editingInfo.editor), new PacketGeneralMessage("Editing entity \"" + editingInfo.entityInfo.classType.getName() + "\""));
PacketDistributor.PLAYER.with((ServerPlayer)editingInfo.editor).send(new PacketGeneralMessage("Editing entity \"" + editingInfo.entityInfo.classType.getName() + "\""));
TurnBasedMinecraftMod.logger.info("Begin editing \"" + editingInfo.entityInfo.classType.getName() + "\"");
TurnBasedMinecraftMod.getHandler().send(PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity)editingInfo.editor), new PacketEditingMessage(PacketEditingMessage.Type.PICK_EDIT, editingInfo.entityInfo));
PacketDistributor.PLAYER.with((ServerPlayer)editingInfo.editor).send(new PacketEditingMessage(PacketEditingMessage.Type.PICK_EDIT, editingInfo.entityInfo));
}
return;
}
@ -116,7 +117,7 @@ public class AttackEventHandler
}
if(event.getEntity() != null && event.getSource().getEntity() != null && (battleManager.isRecentlyLeftBattle(event.getEntity().getId()) || battleManager.isRecentlyLeftBattle(event.getSource().getEntity().getId())))
{
if(event.getSource().getEntity().getEntity() instanceof CreeperEntity && TurnBasedMinecraftMod.proxy.getConfig().getCreeperAlwaysAllowDamage()) {
if(event.getSource().getEntity() instanceof Creeper && TurnBasedMinecraftMod.proxy.getConfig().getCreeperAlwaysAllowDamage()) {
event.setCanceled(false);
} else {
// TurnBasedMinecraftMod.logger.debug("Canceled attack");
@ -130,7 +131,7 @@ public class AttackEventHandler
&& 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())
&& 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());
@ -146,23 +147,23 @@ public class AttackEventHandler
}
@SubscribeEvent
public void entityTargeted(LivingSetAttackTargetEvent event)
public void entityTargeted(LivingChangeTargetEvent event)
{
Config config = TurnBasedMinecraftMod.proxy.getConfig();
BattleManager battleManager = TurnBasedMinecraftMod.proxy.getBattleManager();
if(event.getEntity().level.isClientSide
if(event.getEntity().level().isClientSide
|| config.isOldBattleBehaviorEnabled()
|| (event.getEntity() != null && battleManager.isRecentlyLeftBattle(event.getEntity().getId()))
|| (event.getTarget() != null && battleManager.isRecentlyLeftBattle(event.getTarget().getId()))
|| (event.getEntity() != null && event.getTarget() != null && Utility.distanceBetweenEntities(event.getEntity(), event.getTarget()) > (double)config.getAggroStartBattleDistance()))
|| (event.getNewTarget() != null && battleManager.isRecentlyLeftBattle(event.getNewTarget().getId()))
|| (event.getEntity() != null && event.getNewTarget() != null && Utility.distanceBetweenEntities(event.getEntity(), event.getNewTarget()) > (double)config.getAggroStartBattleDistance()))
{
return;
}
else if(event.getEntity() != null
&& event.getTarget() != null
&& event.getNewTarget() != null
&& !config.getBattleIgnoringPlayers().contains(event.getEntity().getId())
&& !config.getBattleIgnoringPlayers().contains(event.getTarget().getId())
&& event.getEntity().level.dimension().equals(event.getTarget().level.dimension()))
&& !config.getBattleIgnoringPlayers().contains(event.getNewTarget().getId())
&& event.getEntity().level().dimension().equals(event.getNewTarget().level().dimension()))
{
TurnBasedMinecraftMod.proxy.getBattleManager().checkTargeted(event);
}

View file

@ -1,6 +1,6 @@
package com.burnedkirby.TurnBasedMinecraft.common;
import net.minecraft.entity.Entity;
import net.minecraft.world.entity.Entity;
public class AttackerViaBow
{

View file

@ -1,26 +1,19 @@
package com.burnedkirby.TurnBasedMinecraft.common;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import net.minecraft.entity.monster.CreeperEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.ItemGroup;
import net.minecraft.util.RegistryKey;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.network.PacketDistributor;
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.LivingAttackEvent;
import net.neoforged.neoforge.event.entity.living.LivingChangeTargetEvent;
import net.neoforged.neoforge.network.PacketDistributor;
import org.apache.logging.log4j.Logger;
import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketGeneralMessage;
import net.minecraft.entity.Entity;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
import java.util.*;
public class BattleManager
{
@ -30,8 +23,8 @@ public class BattleManager
private Map<Integer, Combatant> recentlyLeftBattle;
private BattleUpdater battleUpdater;
private Map<EntityIDDimPair, Integer> entityToBattleMap;
private static Collection<ItemGroup> otherFoodItemGroups = new ArrayList<>();
private EntityIDDimPair tempIDPair;
public BattleManager(Logger logger)
{
this.logger = logger;
@ -39,7 +32,8 @@ public class BattleManager
recentlyLeftBattle = new HashMap<Integer, Combatant>();
battleUpdater = new BattleUpdater(this);
entityToBattleMap = new HashMap<EntityIDDimPair, Integer>();
MinecraftForge.EVENT_BUS.register(battleUpdater);
NeoForge.EVENT_BUS.register(battleUpdater);
tempIDPair = new EntityIDDimPair();
}
/**
@ -74,11 +68,14 @@ public class BattleManager
attackerCustomName = null;
}
// verify that both entities are EntityPlayer and not in creative or has a corresponding EntityInfo
if(!((event.getEntity() instanceof PlayerEntity && !((PlayerEntity)event.getEntity()).isCreative())
// 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 PlayerEntity && !((PlayerEntity)event.getSource().getEntity()).isCreative())
|| (config.getEntityInfoReference(attackerClassName) != null || config.getCustomEntityInfoReference(attackerCustomName) != 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;
@ -138,14 +135,14 @@ public class BattleManager
return true;
} else if(attackerBattle == null && defenderBattle == null) {
// neither entity is in battle
if(event.getEntity() instanceof PlayerEntity || event.getSource().getEntity() instanceof PlayerEntity)
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());
createBattle(sideA, sideB, event.getEntity().level().dimension());
logger.debug("Attack Not Canceled: new battle created");
}
else
@ -182,11 +179,17 @@ public class BattleManager
return true;
}
public void checkTargeted(LivingSetAttackTargetEvent event)
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.getNewTarget() instanceof Player))) {
return;
}
String targetedCustomName;
try {
targetedCustomName = event.getTarget().getCustomName().getString();
targetedCustomName = event.getNewTarget().getCustomName().getString();
} catch (NullPointerException e) {
targetedCustomName = null;
}
@ -204,7 +207,7 @@ public class BattleManager
}
EntityInfo targetedInfo;
if(event.getTarget() instanceof PlayerEntity)
if(event.getNewTarget() instanceof Player)
{
targetedInfo = null;
}
@ -213,10 +216,10 @@ public class BattleManager
targetedInfo = TurnBasedMinecraftMod.proxy.getConfig().getCustomEntityInfoReference(targetedCustomName);
if(targetedInfo == null)
{
targetedInfo = TurnBasedMinecraftMod.proxy.getConfig().getMatchingEntityInfo(event.getTarget());
targetedInfo = TurnBasedMinecraftMod.proxy.getConfig().getMatchingEntityInfo(event.getNewTarget());
}
}
if((event.getTarget() instanceof PlayerEntity && ((PlayerEntity)event.getTarget()).isCreative())
if((event.getNewTarget() instanceof Player && ((Player)event.getNewTarget()).isCreative())
|| attackerInfo == null
|| attackerInfo.ignoreBattle
|| TurnBasedMinecraftMod.proxy.getConfig().isIgnoreBattleType(attackerInfo.category)
@ -232,8 +235,8 @@ public class BattleManager
if(attackerBattle != null && !attackerBattle.hasCombatant(event.getEntity().getId())) {
attackerBattle = null;
}
Battle defenderBattle = battleMap.get(entityToBattleMap.get(new EntityIDDimPair(event.getTarget())));
if(defenderBattle != null && !defenderBattle.hasCombatant(event.getTarget().getId())) {
Battle defenderBattle = battleMap.get(entityToBattleMap.get(new EntityIDDimPair(event.getNewTarget())));
if(defenderBattle != null && !defenderBattle.hasCombatant(event.getNewTarget().getId())) {
defenderBattle = null;
}
@ -241,14 +244,14 @@ public class BattleManager
return;
} else if(attackerBattle == null && defenderBattle == null) {
// neither in battle
if(event.getEntity() instanceof PlayerEntity || event.getTarget() instanceof PlayerEntity)
if(event.getEntity() instanceof Player || event.getNewTarget() 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.getTarget());
createBattle(sideA, sideB, event.getEntity().level.dimension());
sideB.add(event.getNewTarget());
createBattle(sideA, sideB, event.getEntity().level().dimension());
logger.debug("neither in battle, at least one is player, creating new battle");
}
} else {
@ -258,16 +261,16 @@ public class BattleManager
// battle max reached, cannot add to battle
return;
} else if (attackerBattle.hasCombatantInSideA(event.getEntity().getId())) {
attackerBattle.addCombatantToSideB(event.getTarget());
attackerBattle.addCombatantToSideB(event.getNewTarget());
} else {
attackerBattle.addCombatantToSideA(event.getTarget());
attackerBattle.addCombatantToSideA(event.getNewTarget());
}
entityToBattleMap.put(new EntityIDDimPair(event.getTarget()), attackerBattle.getId());
entityToBattleMap.put(new EntityIDDimPair(event.getNewTarget()), attackerBattle.getId());
} else {
if (defenderBattle.getSize() >= TurnBasedMinecraftMod.proxy.getConfig().getMaxInBattle()) {
// battle max reached, cannot add to battle
return;
} else if (defenderBattle.hasCombatantInSideA(event.getTarget().getId())) {
} else if (defenderBattle.hasCombatantInSideA(event.getNewTarget().getId())) {
defenderBattle.addCombatantToSideB(event.getEntity());
} else {
defenderBattle.addCombatantToSideA(event.getEntity());
@ -277,7 +280,7 @@ public class BattleManager
}
}
private Battle createBattle(Collection<Entity> sideA, Collection<Entity> sideB, RegistryKey<World> dimension)
private Battle createBattle(Collection<Entity> sideA, Collection<Entity> sideB, ResourceKey<Level> dimension)
{
Battle newBattle = null;
while(battleMap.containsKey(IDCounter))
@ -304,7 +307,7 @@ public class BattleManager
public void cleanup()
{
battleUpdater.setRunning(false);
MinecraftForge.EVENT_BUS.unregister(battleUpdater);
NeoForge.EVENT_BUS.unregister(battleUpdater);
battleMap.clear();
battleUpdater = null;
}
@ -313,8 +316,8 @@ public class BattleManager
{
c.time = System.nanoTime();
Config config = TurnBasedMinecraftMod.proxy.getConfig();
if(c.entity instanceof ServerPlayerEntity) {
TurnBasedMinecraftMod.getHandler().send(PacketDistributor.PLAYER.with(()->(ServerPlayerEntity) c.entity), new PacketGeneralMessage("You just left battle! " + config.getLeaveBattleCooldownSeconds() + " seconds until you can attack/be-attacked again!"));
if(c.entity instanceof ServerPlayer) {
PacketDistributor.PLAYER.with((ServerPlayer)c.entity).send(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));
@ -326,15 +329,15 @@ public class BattleManager
for(Iterator<Map.Entry<Integer, Combatant>> iter = recentlyLeftBattle.entrySet().iterator(); iter.hasNext();)
{
Map.Entry<Integer, Combatant> entry = iter.next();
if(entry.getValue().entity instanceof CreeperEntity && TurnBasedMinecraftMod.proxy.getConfig().getCreeperStopExplodeOnLeaveBattle()) {
((CreeperEntity)entry.getValue().entity).setSwellDir(-10);
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 ServerPlayerEntity)
if(entry.getValue().entity instanceof ServerPlayer)
{
TurnBasedMinecraftMod.getHandler().send(PacketDistributor.PLAYER.with(()->(ServerPlayerEntity)entry.getValue().entity), new PacketGeneralMessage("Timer ended, you can now attack/be-attacked again."));
PacketDistributor.PLAYER.with((ServerPlayer)entry.getValue().entity).send(new PacketGeneralMessage("Timer ended, you can now attack/be-attacked again."));
}
}
}
@ -359,11 +362,11 @@ public class BattleManager
return result;
}
public static void addOtherModItemGroup(ItemGroup itemGroup) {
otherFoodItemGroups.add(itemGroup);
}
public static Collection<ItemGroup> getOtherFoodItemGroups() {
return otherFoodItemGroups;
public boolean isInBattle(Entity entity) {
synchronized(tempIDPair) {
tempIDPair.id = entity.getId();
tempIDPair.dim = entity.level().dimension();
return entityToBattleMap.keySet().contains(tempIDPair);
}
}
}

View file

@ -1,8 +1,8 @@
package com.burnedkirby.TurnBasedMinecraft.common;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.neoforge.event.TickEvent;
import java.util.concurrent.atomic.AtomicBoolean;
@ -11,7 +11,7 @@ public class BattleUpdater
private BattleManager manager;
private AtomicBoolean isRunning;
private int tick;
private final int tickLimit = 10;
private final int tickLimit = 3;
public BattleUpdater(BattleManager manager)
{

View file

@ -2,11 +2,11 @@ package com.burnedkirby.TurnBasedMinecraft.common;
import java.util.Comparator;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.potion.EffectInstance;
import net.minecraft.potion.Effects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
public class Combatant
{
@ -53,18 +53,18 @@ public class Combatant
@Override
public int compare(Combatant c0, Combatant c1)
{
if(c0.entity instanceof PlayerEntity && c0.recalcSpeedOnCompare)
if(c0.entity instanceof Player && c0.recalcSpeedOnCompare)
{
LivingEntity c0Entity = (LivingEntity)c0.entity;
boolean isHaste = false;
boolean isSlow = false;
for(EffectInstance e : c0Entity.getActiveEffects())
for(MobEffectInstance e : c0Entity.getActiveEffects())
{
if(e.getEffect().equals(Effects.MOVEMENT_SPEED) || e.getEffect().equals(Effects.DIG_SPEED))
if(e.getEffect().equals(MobEffects.MOVEMENT_SPEED) || e.getEffect().equals(MobEffects.DIG_SPEED))
{
isHaste = true;
}
else if(e.getEffect().equals(Effects.MOVEMENT_SLOWDOWN) || e.getEffect().equals(Effects.DIG_SLOWDOWN))
else if(e.getEffect().equals(MobEffects.MOVEMENT_SLOWDOWN) || e.getEffect().equals(MobEffects.DIG_SLOWDOWN))
{
isSlow = true;
}
@ -87,18 +87,18 @@ public class Combatant
}
}
if(c1.entity instanceof PlayerEntity && c1.recalcSpeedOnCompare)
if(c1.entity instanceof Player && c1.recalcSpeedOnCompare)
{
LivingEntity c1Entity = (LivingEntity)c1.entity;
boolean isHaste = false;
boolean isSlow = false;
for(EffectInstance e : c1Entity.getActiveEffects())
for(MobEffectInstance e : c1Entity.getActiveEffects())
{
if(e.getEffect().equals(Effects.MOVEMENT_SPEED))
if(e.getEffect().equals(MobEffects.MOVEMENT_SPEED))
{
isHaste = true;
}
else if(e.getEffect().equals(Effects.MOVEMENT_SLOWDOWN))
else if(e.getEffect().equals(MobEffects.MOVEMENT_SLOWDOWN))
{
isSlow = true;
}

View file

@ -1,20 +1,18 @@
package com.burnedkirby.TurnBasedMinecraft.common;
import java.lang.reflect.Field;
import java.util.*;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemGroup;
import net.minecraft.util.RegistryKey;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.world.DimensionType;
import net.minecraft.world.World;
import net.minecraftforge.fml.ModContainer;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.server.ServerLifecycleHooks;
import net.minecraft.network.chat.Component;
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.PlayPayloadContext;
import net.neoforged.neoforge.server.ServerLifecycleHooks;
import org.apache.logging.log4j.Logger;
import net.minecraft.entity.Entity;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
public class CommonProxy
{
@ -62,6 +60,10 @@ public class CommonProxy
public void setBattleGuiBattleChanged() {}
public void setBattleGuiAsGui() {}
public void setBattleGuiTurnTimerEnabled(boolean enabled) {}
public void setBattleGuiTurnTimerMax(int timeMax) {}
public void battleGuiTurnBegin() {}
@ -75,96 +77,11 @@ public class CommonProxy
{
config = new Config(logger);
postInitClient();
pamsFoodIntegrationLoading();
logger.debug("postInit proxy for com_burnedkirby_turnbasedminecraft");
}
protected void postInitClient() {}
private final void pamsFoodIntegrationLoading() {
// TODO: generalize other mod's food loading via config with a list of mod ids
// pamhc2foodcore
{
ModList modList = ModList.get();
Optional<? extends ModContainer> pamsFoodCoreContainer = modList.getModContainerById("pamhc2foodcore");
if (pamsFoodCoreContainer.isPresent()) {
Object pamsFoodCore = pamsFoodCoreContainer.get().getMod();
try {
Field itemGroupField = pamsFoodCore.getClass().getField("ITEM_GROUP");
ItemGroup foodItemGroup = (ItemGroup) itemGroupField.get(null);
if(foodItemGroup != null) {
BattleManager.addOtherModItemGroup(foodItemGroup);
} else {
throw new NullPointerException();
}
} catch (Exception e) {
TurnBasedMinecraftMod.logger.info("Failed to get pamhc2foodcore ITEM_GROUP");
}
}
}
// pamhc2crops
{
ModList modList = ModList.get();
Optional<? extends ModContainer> pamsFoodCoreContainer = modList.getModContainerById("pamhc2crops");
if (pamsFoodCoreContainer.isPresent()) {
Object pamsFoodCore = pamsFoodCoreContainer.get().getMod();
try {
Field itemGroupField = pamsFoodCore.getClass().getField("ITEM_GROUP");
ItemGroup foodItemGroup = (ItemGroup) itemGroupField.get(null);
if(foodItemGroup != null) {
BattleManager.addOtherModItemGroup(foodItemGroup);
} else {
throw new NullPointerException();
}
} catch (Exception e) {
TurnBasedMinecraftMod.logger.info("Failed to get pamhc2crops ITEM_GROUP");
}
}
}
// pamhc2trees
{
ModList modList = ModList.get();
Optional<? extends ModContainer> pamsFoodCoreContainer = modList.getModContainerById("pamhc2trees");
if (pamsFoodCoreContainer.isPresent()) {
Object pamsFoodCore = pamsFoodCoreContainer.get().getMod();
try {
Field itemGroupField = pamsFoodCore.getClass().getField("ITEM_GROUP");
ItemGroup foodItemGroup = (ItemGroup) itemGroupField.get(null);
if(foodItemGroup != null) {
BattleManager.addOtherModItemGroup(foodItemGroup);
} else {
throw new NullPointerException();
}
} catch (Exception e) {
TurnBasedMinecraftMod.logger.info("Failed to get pamhc2trees ITEM_GROUP");
}
}
}
// pamhc2foodextended
{
ModList modList = ModList.get();
Optional<? extends ModContainer> pamsFoodCoreContainer = modList.getModContainerById("pamhc2foodextended");
if (pamsFoodCoreContainer.isPresent()) {
Object pamsFoodCore = pamsFoodCoreContainer.get().getMod();
try {
Field itemGroupField = pamsFoodCore.getClass().getField("ITEM_GROUP");
ItemGroup foodItemGroup = (ItemGroup) itemGroupField.get(null);
if(foodItemGroup != null) {
BattleManager.addOtherModItemGroup(foodItemGroup);
} else {
throw new NullPointerException();
}
} catch (Exception e) {
TurnBasedMinecraftMod.logger.info("Failed to get pamhc2foodextended ITEM_GROUP");
}
}
}
}
public final void setLogger(Logger logger)
{
this.logger = logger;
@ -182,7 +99,7 @@ public class CommonProxy
public void displayString(String message) {}
public void displayTextComponent(ITextComponent textComponent) {}
public void displayComponent(Component textComponent) {}
public final boolean isServerRunning()
{
@ -241,7 +158,7 @@ public class CommonProxy
return editingPlayers.get(id);
}
protected final EditingInfo setEditingPlayer(PlayerEntity player)
protected final EditingInfo setEditingPlayer(Player player)
{
return editingPlayers.put(player.getId(), new EditingInfo(player));
}
@ -251,7 +168,9 @@ public class CommonProxy
return editingPlayers.remove(id);
}
public Entity getEntity(int id, RegistryKey<World> dim) {
public Entity getEntity(int id, ResourceKey<Level> dim) {
return ServerLifecycleHooks.getCurrentServer().getLevel(dim).getEntity(id);
}
public <MSG> void handlePacket(final MSG msg, final PlayPayloadContext ctx) {}
}

View file

@ -7,6 +7,8 @@ import java.util.*;
import com.electronwill.nightconfig.core.file.CommentedFileConfig;
import com.electronwill.nightconfig.toml.TomlFormat;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.registries.VanillaRegistries;
import org.apache.logging.log4j.Logger;
import com.electronwill.nightconfig.core.file.FileConfig;
@ -20,6 +22,7 @@ public class Config
public static final long BATTLE_DECISION_DURATION_NANO_MAX = BATTLE_DECISION_DURATION_SEC_MAX * 1000000000L;
public static final long BATTLE_DECISION_DURATION_NANO_DEFAULT = BATTLE_DECISION_DURATION_SEC_DEFAULT * 1000000000L;
private long battleDecisionDurationNanos = BATTLE_DECISION_DURATION_NANO_DEFAULT;
private boolean battleDecisionDurationForever = false;
private Map<String, EntityInfo> entityInfoMap;
private Map<String, EntityInfo> customEntityInfoMap;
private Set<String> ignoreBattleTypes;
@ -49,6 +52,11 @@ public class Config
private boolean creeperStopExplodeOnLeaveBattle = true;
private boolean creeperAlwaysAllowDamage = true;
private Set<String> possibleIgnoreHurtDamageSources;
private Set<String> ignoreHurtDamageSources;
private boolean playerOnlyBattles = false;
public Config(Logger logger)
{
entityInfoMap = new HashMap<String, EntityInfo>();
@ -58,6 +66,10 @@ public class Config
musicBattleTypes = new HashSet<String>();
musicSillyTypes = new HashSet<String>();
battleIgnoringPlayers = new HashSet<Integer>();
possibleIgnoreHurtDamageSources = new HashSet<String>();
ignoreHurtDamageSources = new HashSet<String>();
loadDamageSources();
{
File confPath = new File(TurnBasedMinecraftMod.CONFIG_DIRECTORY);
@ -142,11 +154,7 @@ public class Config
private boolean parseConfig(File configFile) throws IOException
{
CommentedFileConfig conf = CommentedFileConfig
.builder(configFile)
.defaultResource(TurnBasedMinecraftMod.DEFAULT_CONFIG_FILE_PATH)
.build();
conf.load();
CommentedFileConfig conf = getConfigObj(configFile);
// client config
try {
@ -498,6 +506,43 @@ public class Config
logTOMLInvalidValue("server_config.battle_turn_time_seconds", "15");
}
try {
Boolean battle_turn_wait_forever = conf.get("server_config.battle_turn_wait_forever");
if (battle_turn_wait_forever != null) {
this.battleDecisionDurationForever = battle_turn_wait_forever;
} else {
this.battleDecisionDurationForever = false;
logNotFound("server_config.battle_turn_wait_forever", "false");
}
} catch (ClassCastException e) {
this.battleDecisionDurationForever = false;
logTOMLInvalidValue("server_config.battle_turn_wait_forever", "false");
}
try {
Collection<String> damage_sources = conf.get("server_config.ignore_damage_sources");
for (String source : damage_sources) {
if (possibleIgnoreHurtDamageSources.contains(source)) {
ignoreHurtDamageSources.add(source);
}
}
} catch (ClassCastException e) {
logTOMLInvalidValue("server_config.ignore_damage_sources");
}
try {
Boolean is_only_player_battles_enabled = conf.get("server_config.player_only_battles");
if (is_only_player_battles_enabled != null) {
playerOnlyBattles = is_only_player_battles_enabled;
} else {
playerOnlyBattles = false;
logNotFound("server_config.player_only_battles", "false");
}
} catch (ClassCastException e) {
playerOnlyBattles = false;
logTOMLInvalidValue("server_config.player_only_battles", "false");
}
Collection<com.electronwill.nightconfig.core.Config> entities = null;
try {
entities = conf.get("server_config.entity");
@ -940,41 +985,117 @@ public class Config
return playerSpeed;
}
public void setPlayerSpeed(int speed) {
if (speed < 0) {
speed = 0;
} else if (speed > 100) {
speed = 100;
}
playerSpeed = speed;
}
public int getPlayerHasteSpeed()
{
return playerHasteSpeed;
}
public void setPlayerHasteSpeed(int speed) {
if (speed < 0) {
speed = 0;
} else if (speed > 100) {
speed = 100;
}
playerHasteSpeed = speed;
}
public int getPlayerSlowSpeed()
{
return playerSlowSpeed;
}
public void setPlayerSlowSpeed(int speed) {
if (speed < 0) {
speed = 0;
} else if (speed > 100) {
speed = 100;
}
playerSlowSpeed = speed;
}
public int getPlayerAttackProbability()
{
return playerAttackProbability;
}
public void setPlayerAttackProbability(int probability) {
if (probability < 1) {
probability = 1;
} else if (probability > 100) {
probability = 100;
}
playerAttackProbability = probability;
}
public int getPlayerEvasion()
{
return playerEvasion;
}
public void setPlayerEvasion(int evasion) {
if (evasion < 0) {
evasion = 0;
} else if (evasion > 100) {
evasion = 100;
}
playerEvasion = evasion;
}
public int getDefenseDuration()
{
return defenseDuration;
}
public void setDefenseDuration(int turns) {
if (turns < 0) {
turns = 0;
} else if (turns > 5) {
turns = 5;
}
defenseDuration = turns;
}
public int getFleeGoodProbability()
{
return fleeGoodProbability;
}
public void setFleeGoodProbability(int probability) {
if (probability < 1) {
probability = 1;
} else if (probability > 100) {
probability = 100;
}
fleeGoodProbability = probability;
}
public int getFleeBadProbability()
{
return fleeBadProbability;
}
public void setFleeBadProbability(int probability) {
if (probability < 1) {
probability = 1;
} else if (probability > 100) {
probability = 100;
}
fleeBadProbability = probability;
}
/**
* Returns a clone of an EntityInfo (to prevent editing it).
* @param classFullName
@ -1079,21 +1200,134 @@ public class Config
return canOverwrite;
}
private CommentedFileConfig getConfigObj(File configFile) {
CommentedFileConfig conf = CommentedFileConfig
.builder(configFile)
.defaultResource(TurnBasedMinecraftMod.DEFAULT_CONFIG_FILE_PATH)
.build();
conf.load();
return conf;
}
public boolean updateConfig(String path, Object value) {
File configFile = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
CommentedFileConfig conf = getConfigObj(configFile);
conf.set(path, value);
conf.save();
conf.close();
return true;
}
public boolean updateConfigAppendToStringArray(String path, String string_value) {
File configFile = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
CommentedFileConfig conf = getConfigObj(configFile);
Collection<String> strings;
try {
strings = conf.get(path);
} catch (Exception e) {
TurnBasedMinecraftMod.logger.warn("Exception during fetching Collection<String> from config (append)");
TurnBasedMinecraftMod.logger.warn(e);
return false;
}
if (strings.contains(string_value)) {
return false;
}
strings.add(string_value);
try {
conf.set(path, strings);
} catch (Exception e) {
TurnBasedMinecraftMod.logger.warn("Exception during setting Collection<String> in config (append)");
TurnBasedMinecraftMod.logger.warn(e);
return false;
}
conf.save();
conf.close();
return true;
}
public boolean updateConfigRemoveFromStringArray(String path, String string_value) {
File configFile = new File(TurnBasedMinecraftMod.CONFIG_FILE_PATH);
CommentedFileConfig conf = getConfigObj(configFile);
Collection<String> strings;
try {
strings = conf.get(path);
} catch (Exception e) {
TurnBasedMinecraftMod.logger.warn("Exception during fetching Collection<String> from config (removal)");
TurnBasedMinecraftMod.logger.warn(e);
return false;
}
if (!strings.contains(string_value)) {
return false;
}
strings.remove(string_value);
try {
conf.set(path, strings);
} catch (Exception e) {
TurnBasedMinecraftMod.logger.warn("Exception during setting Collection<String> in config (removal)");
TurnBasedMinecraftMod.logger.warn(e);
return false;
}
conf.save();
conf.close();
return true;
}
public boolean isIgnoreBattleType(String type)
{
return ignoreBattleTypes.contains(type);
}
public Collection<String> getIgnoreBattleTypes() {
return ignoreBattleTypes;
}
public boolean removeIgnoreBattleType(String category) {
return ignoreBattleTypes.remove(category);
}
public boolean addIgnoreBattleType(String category) {
return ignoreBattleTypes.add(category);
}
public int getMinimumHitPercentage()
{
return minimumHitPercentage;
}
public void setMinimumHitPercentage(int percentage) {
if (percentage < 1) {
percentage = 1;
} else if (percentage > 100) {
percentage = 100;
}
minimumHitPercentage = percentage;
}
public int getMaxInBattle()
{
return maxInBattle;
}
public void setMaxInBattle(int maxInBattle) {
if (maxInBattle < 2) {
maxInBattle = 2;
} else if (maxInBattle > 30) {
maxInBattle = 30;
}
this.maxInBattle = maxInBattle;
}
public boolean isBattleMusicType(String type)
{
return musicBattleTypes.contains(type.toLowerCase());
@ -1109,6 +1343,10 @@ public class Config
return freezeCombatantsInBattle;
}
public void setFreezeCombatantsInBattle(boolean enabled) {
freezeCombatantsInBattle = enabled;
}
public int getSillyMusicThreshold()
{
return sillyMusicThreshold;
@ -1129,6 +1367,15 @@ public class Config
return (int)(battleDecisionDurationNanos / 1000000000L);
}
public void setDecisionDurationSeconds(long seconds) {
if (seconds < 5) {
seconds = 5;
} else if (seconds > 60) {
seconds = 60;
}
battleDecisionDurationNanos = seconds * 1000000000L;
}
protected void addBattleIgnoringPlayer(int id)
{
battleIgnoringPlayers.add(id);
@ -1154,6 +1401,10 @@ public class Config
return onlyOPsSelfDisableTB;
}
public void setIfOnlyOPsCanDisableTurnBasedForSelf(boolean enabled_for_only_ops) {
onlyOPsSelfDisableTB = enabled_for_only_ops;
}
protected void setBattleDisabledForAll(boolean isDisabled)
{
battleDisabledForAll = isDisabled;
@ -1169,11 +1420,24 @@ public class Config
return oldBattleBehaviorEnabled;
}
public void setOldBattleBehavior(boolean enabled) {
oldBattleBehaviorEnabled = enabled;
}
public int getLeaveBattleCooldownSeconds()
{
return leaveBattleCooldownSeconds;
}
public void setLeaveBattleCooldownSeconds(int seconds) {
if (seconds < 1) {
seconds = 1;
} else if (seconds > 10) {
seconds = 10;
}
leaveBattleCooldownSeconds = seconds;
}
public long getLeaveBattleCooldownNanos()
{
return (long)leaveBattleCooldownSeconds * 1000000000L;
@ -1184,9 +1448,83 @@ public class Config
return aggroStartBattleDistance;
}
public void setAggroStartBattleDistance(int distance) {
if (distance < 5) {
distance = 5;
} else if (distance > 50) {
distance = 50;
}
aggroStartBattleDistance = distance;
}
public int getCreeperExplodeTurn() { return creeperExplodeTurn; }
public void setCreeperExplodeTurn(int turns) {
if (turns < 1) {
turns = 1;
} else if (turns > 10) {
turns = 10;
}
creeperExplodeTurn = turns;
}
public boolean getCreeperStopExplodeOnLeaveBattle() { return creeperStopExplodeOnLeaveBattle; }
public void setCreeperStopExplodeOnLeaveBattle(boolean stop_explode_on_leave_battle) {
creeperStopExplodeOnLeaveBattle = stop_explode_on_leave_battle;
}
public boolean getCreeperAlwaysAllowDamage() { return creeperAlwaysAllowDamage; }
public void setCreeperAlwaysAllowDamage(boolean allow_damage) {
creeperAlwaysAllowDamage = allow_damage;
}
public boolean isBattleDecisionDurationForever() {
return battleDecisionDurationForever;
}
public void setBattleDecisionDurationForever(boolean battleDecisionDurationForever) {
this.battleDecisionDurationForever = battleDecisionDurationForever;
}
public final Collection<String> getPossibleIgnoreHurtDamageSources() {
return possibleIgnoreHurtDamageSources;
}
public final Collection<String> getIgnoreHurtDamageSources() {
return ignoreHurtDamageSources;
}
public boolean addIgnoreHurtDamageSource(String source) {
if (possibleIgnoreHurtDamageSources.contains(source) && !ignoreHurtDamageSources.contains(source)) {
ignoreHurtDamageSources.add(source);
return true;
} else {
return false;
}
}
public boolean removeIgnoreHurtDamageSource(String source) {
return ignoreHurtDamageSources.remove(source);
}
public boolean isPlayerOnlyBattlesEnabled() {
return playerOnlyBattles;
}
public void setIsPlayerOnlyBattles(boolean enabled) {
playerOnlyBattles = enabled;
}
private void loadDamageSources() {
possibleIgnoreHurtDamageSources.clear();
try {
VanillaRegistries.createLookup().lookupOrThrow(Registries.DAMAGE_TYPE).listElements().forEach(dt -> possibleIgnoreHurtDamageSources.add(dt.value().msgId()));
} catch (Exception e) {
logger.warn("Config failed to load possible DamageSources! Undesired things may happen, like Zombies dying from Fire during battle!");
logger.warn(e);
}
}
}

View file

@ -1,22 +1,20 @@
package com.burnedkirby.TurnBasedMinecraft.common;
import com.burnedkirby.TurnBasedMinecraft.common.networking.PacketGeneralMessage;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraftforge.event.entity.EntityTravelToDimensionEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.network.PacketDistributor;
import net.minecraft.server.level.ServerPlayer;
import net.neoforged.neoforge.event.entity.EntityTravelToDimensionEvent;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.neoforge.network.PacketDistributor;
public class DimensionChangedHandler {
@SubscribeEvent
public void dimensionChanged(EntityTravelToDimensionEvent event) {
if(event.getEntity().level.isClientSide) {
if(event.getEntity().level().isClientSide) {
return;
}
if(TurnBasedMinecraftMod.proxy.getBattleManager().forceLeaveBattle(new EntityIDDimPair(event.getEntity()))
&& event.getEntity() instanceof ServerPlayerEntity) {
TurnBasedMinecraftMod.getHandler().send(
PacketDistributor.PLAYER.with(() -> (ServerPlayerEntity)event.getEntity()),
new PacketGeneralMessage("Left battle due to moving to a different dimension"));
&& event.getEntity() instanceof ServerPlayer) {
PacketDistributor.PLAYER.with((ServerPlayer)event.getEntity()).send(new PacketGeneralMessage("Left battle due to moving to a different dimension"));
}
}
}

View file

@ -1,10 +1,10 @@
package com.burnedkirby.TurnBasedMinecraft.common;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.world.entity.player.Player;
public class EditingInfo
{
public PlayerEntity editor;
public Player editor;
public EntityInfo entityInfo;
public boolean isPendingEntitySelection;
public boolean isEditingCustomName;
@ -17,7 +17,7 @@ public class EditingInfo
isEditingCustomName = false;
}
public EditingInfo(PlayerEntity player)
public EditingInfo(Player player)
{
editor = player;
entityInfo = null;

View file

@ -1,13 +1,12 @@
package com.burnedkirby.TurnBasedMinecraft.common;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.util.RegistryKey;
import net.minecraft.world.World;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
public class EntityIDDimPair {
public int id;
public RegistryKey<World> dim;
public ResourceKey<Level> dim;
EntityIDDimPair() {
id = 0;
@ -15,14 +14,14 @@ public class EntityIDDimPair {
dim = null;
}
EntityIDDimPair(int id, RegistryKey<World> dim) {
EntityIDDimPair(int id, ResourceKey<Level> dim) {
this.id = id;
this.dim = dim;
}
EntityIDDimPair(Entity entity) {
id = entity.getId();
dim = entity.level.dimension();
dim = entity.level().dimension();
}
public Entity getEntity() {

View file

@ -1,8 +1,8 @@
package com.burnedkirby.TurnBasedMinecraft.common;
import net.minecraft.entity.LivingEntity;
import net.minecraft.potion.EffectInstance;
import net.minecraft.potion.Effects;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.LivingEntity;
public class EntityInfo
{
@ -194,71 +194,71 @@ public class EntityInfo
}
}
public EffectInstance getPotionEffect()
public MobEffectInstance getPotionEffect()
{
return getPotionEffect(20 * 7, 0);
}
public EffectInstance getPotionEffect(int duration, int amplifier) {
public MobEffectInstance getPotionEffect(int duration, int amplifier) {
switch(this) {
case SPEED:
return new EffectInstance(Effects.MOVEMENT_SPEED, duration, amplifier);
return new MobEffectInstance(MobEffects.MOVEMENT_SPEED, duration, amplifier);
case SLOW:
return new EffectInstance(Effects.MOVEMENT_SLOWDOWN, duration, amplifier);
return new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, duration, amplifier);
case HASTE:
return new EffectInstance(Effects.DIG_SPEED, duration, amplifier);
return new MobEffectInstance(MobEffects.DIG_SPEED, duration, amplifier);
case MINING_FATIGUE:
return new EffectInstance(Effects.DIG_SLOWDOWN, duration, amplifier);
return new MobEffectInstance(MobEffects.DIG_SLOWDOWN, duration, amplifier);
case STRENGTH:
return new EffectInstance(Effects.DAMAGE_BOOST, duration, amplifier);
return new MobEffectInstance(MobEffects.DAMAGE_BOOST, duration, amplifier);
case JUMP_BOOST:
return new EffectInstance(Effects.JUMP, duration, amplifier);
return new MobEffectInstance(MobEffects.JUMP, duration, amplifier);
case NAUSEA:
return new EffectInstance(Effects.CONFUSION, duration, amplifier);
return new MobEffectInstance(MobEffects.CONFUSION, duration, amplifier);
case REGENERATION:
return new EffectInstance(Effects.REGENERATION, duration, amplifier);
return new MobEffectInstance(MobEffects.REGENERATION, duration, amplifier);
case RESISTANCE:
return new EffectInstance(Effects.DAMAGE_RESISTANCE, duration, amplifier);
return new MobEffectInstance(MobEffects.DAMAGE_RESISTANCE, duration, amplifier);
case FIRE_RESISTANCE:
return new EffectInstance(Effects.FIRE_RESISTANCE, duration, amplifier);
return new MobEffectInstance(MobEffects.FIRE_RESISTANCE, duration, amplifier);
case WATER_BREATHING:
return new EffectInstance(Effects.WATER_BREATHING, duration, amplifier);
return new MobEffectInstance(MobEffects.WATER_BREATHING, duration, amplifier);
case INVISIBILITY:
return new EffectInstance(Effects.INVISIBILITY, duration, amplifier);
return new MobEffectInstance(MobEffects.INVISIBILITY, duration, amplifier);
case BLINDNESS:
return new EffectInstance(Effects.BLINDNESS, duration, amplifier);
return new MobEffectInstance(MobEffects.BLINDNESS, duration, amplifier);
case NIGHT_VISION:
return new EffectInstance(Effects.NIGHT_VISION, duration, amplifier);
return new MobEffectInstance(MobEffects.NIGHT_VISION, duration, amplifier);
case HUNGER:
return new EffectInstance(Effects.HUNGER, duration, amplifier);
return new MobEffectInstance(MobEffects.HUNGER, duration, amplifier);
case WEAKNESS:
return new EffectInstance(Effects.WEAKNESS, duration, amplifier);
return new MobEffectInstance(MobEffects.WEAKNESS, duration, amplifier);
case POISON:
return new EffectInstance(Effects.POISON, duration, amplifier);
return new MobEffectInstance(MobEffects.POISON, duration, amplifier);
case WITHER:
return new EffectInstance(Effects.WITHER, duration, amplifier);
return new MobEffectInstance(MobEffects.WITHER, duration, amplifier);
case HEALTH_BOOST:
return new EffectInstance(Effects.HEALTH_BOOST, duration, amplifier);
return new MobEffectInstance(MobEffects.HEALTH_BOOST, duration, amplifier);
case ABSORPTION:
return new EffectInstance(Effects.ABSORPTION, duration, amplifier);
return new MobEffectInstance(MobEffects.ABSORPTION, duration, amplifier);
case SATURATION:
return new EffectInstance(Effects.SATURATION, duration, amplifier);
return new MobEffectInstance(MobEffects.SATURATION, duration, amplifier);
case GLOWING:
return new EffectInstance(Effects.GLOWING, duration, amplifier);
return new MobEffectInstance(MobEffects.GLOWING, duration, amplifier);
case LEVITATION:
return new EffectInstance(Effects.LEVITATION, duration, amplifier);
return new MobEffectInstance(MobEffects.LEVITATION, duration, amplifier);
case LUCK:
return new EffectInstance(Effects.LUCK, duration, amplifier);
return new MobEffectInstance(MobEffects.LUCK, duration, amplifier);
case UNLUCK:
return new EffectInstance(Effects.UNLUCK, duration, amplifier);
return new MobEffectInstance(MobEffects.UNLUCK, duration, amplifier);
case SLOW_FALLING:
return new EffectInstance(Effects.SLOW_FALLING, duration, amplifier);
return new MobEffectInstance(MobEffects.SLOW_FALLING, duration, amplifier);
case CONDUIT_POWER:
return new EffectInstance(Effects.CONDUIT_POWER, duration, amplifier);
return new MobEffectInstance(MobEffects.CONDUIT_POWER, duration, amplifier);
case DOLPHINS_GRACE:
return new EffectInstance(Effects.DOLPHINS_GRACE, duration, amplifier);
return new MobEffectInstance(MobEffects.DOLPHINS_GRACE, duration, amplifier);
case BAD_OMEN:
return new EffectInstance(Effects.BAD_OMEN, duration, amplifier);
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;

View file

@ -0,0 +1,16 @@
package com.burnedkirby.TurnBasedMinecraft.common;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.neoforge.event.entity.living.LivingHurtEvent;
public class HurtEventHandler {
@SubscribeEvent
public void handleHurtEvent(LivingHurtEvent 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);
}
}
}

View file

@ -1,19 +1,19 @@
package com.burnedkirby.TurnBasedMinecraft.common;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
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(EntityJoinWorldEvent event)
public void entityJoinHandler(EntityJoinLevelEvent event)
{
if(event.getWorld().isClientSide)
if(event.getLevel().isClientSide)
{
return;
}
if(event.getEntity() instanceof PlayerEntity && TurnBasedMinecraftMod.proxy.getConfig().getBattleDisabledForAll())
if(event.getEntity() instanceof Player && TurnBasedMinecraftMod.proxy.getConfig().getBattleDisabledForAll())
{
TurnBasedMinecraftMod.proxy.getConfig().addBattleIgnoringPlayer(event.getEntity().getId());
}

View file

@ -1,12 +1,12 @@
package com.burnedkirby.TurnBasedMinecraft.common;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ArrowItem;
import net.minecraft.util.RegistryKey;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.World;
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.player.Player;
import net.minecraft.world.item.ArrowItem;
import net.minecraft.world.level.Level;
public class Utility
{
@ -37,11 +37,11 @@ public class Utility
}
}
public static boolean doesPlayerHaveArrows(PlayerEntity player)
public static boolean doesPlayerHaveArrows(Player player)
{
for(int i = 0; i < player.inventory.getContainerSize(); ++i)
for(int i = 0; i < player.getInventory().getContainerSize(); ++i)
{
if(player.inventory.getItem(i).getItem() instanceof ArrowItem)
if(player.getInventory().getItem(i).getItem() instanceof ArrowItem)
{
return true;
}
@ -54,12 +54,12 @@ public class Utility
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(RegistryKey<World> dimObject) {
return dimObject.getRegistryName().toString();
public static String serializeDimension(ResourceKey<Level> dimObject) {
return dimObject.registry().toString();
}
public static RegistryKey<World> deserializeDimension(String dimString) {
public static ResourceKey<Level> deserializeDimension(String dimString) {
ResourceLocation dimRes = new ResourceLocation(dimString);
return RegistryKey.create(Registry.DIMENSION_REGISTRY, dimRes);
return ResourceKey.create(Registries.DIMENSION, dimRes);
}
}

View file

@ -1,17 +1,20 @@
package com.burnedkirby.TurnBasedMinecraft.common.networking;
import java.util.function.Supplier;
import com.burnedkirby.TurnBasedMinecraft.common.Battle;
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
import com.burnedkirby.TurnBasedMinecraft.common.Battle.Decision;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.NetworkEvent;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.player.Player;
import net.neoforged.neoforge.network.handling.PlayPayloadContext;
public class PacketBattleDecision
public class PacketBattleDecision implements CustomPacketPayload
{
public static final ResourceLocation ID = new ResourceLocation(TurnBasedMinecraftMod.MODID, "network_packetbattledecision");
private int battleID;
private Battle.Decision decision;
private int targetIDOrItemID;
@ -24,28 +27,44 @@ public class PacketBattleDecision
this.decision = decision;
this.targetIDOrItemID = targetIDOrItemID;
}
public static void encode(PacketBattleDecision pkt, PacketBuffer buf) {
buf.writeInt(pkt.battleID);
buf.writeInt(pkt.decision.getValue());
buf.writeInt(pkt.targetIDOrItemID);
public PacketBattleDecision(final FriendlyByteBuf buf) {
this.battleID = buf.readInt();
this.decision = Decision.valueOf(buf.readInt());
this.targetIDOrItemID = buf.readInt();
}
public static PacketBattleDecision decode(PacketBuffer buf) {
return new PacketBattleDecision(buf.readInt(), Decision.valueOf(buf.readInt()), buf.readInt());
@Override
public void write(FriendlyByteBuf buf) {
buf.writeInt(battleID);
buf.writeInt(decision.getValue());
buf.writeInt(targetIDOrItemID);
}
public static class Handler {
public static void handle(final PacketBattleDecision pkt, Supplier<NetworkEvent.Context> ctx) {
ctx.get().enqueueWork(() -> {
Battle b = TurnBasedMinecraftMod.proxy.getBattleManager().getBattleByID(pkt.battleID);
if(b != null)
{
ServerPlayerEntity player = ctx.get().getSender();
b.setDecision(player.getId(), pkt.decision, pkt.targetIDOrItemID);
}
});
ctx.get().setPacketHandled(true);
}
@Override
public ResourceLocation id() {
return ID;
}
public static class PayloadHandler {
private static final PayloadHandler INSTANCE = new PayloadHandler();
public static PayloadHandler getInstance() {
return INSTANCE;
}
public void handleData(final PacketBattleDecision pkt, final PlayPayloadContext ctx) {
ctx.workHandler().submitAsync(() -> {
Battle b = TurnBasedMinecraftMod.proxy.getBattleManager().getBattleByID(pkt.battleID);
if(b != null)
{
Player player = ctx.player().get();
b.setDecision(player.getId(), pkt.decision, pkt.targetIDOrItemID);
}
}).exceptionally(e -> {
ctx.packetHandler().disconnect(Component.literal("Exception handling PacketBattleDecision! " + e.getMessage()));
return null;
});
}
}
}

View file

@ -2,65 +2,90 @@ package com.burnedkirby.TurnBasedMinecraft.common.networking;
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Supplier;
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.NetworkEvent;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.network.FriendlyByteBuf;
import net.neoforged.neoforge.network.handling.PlayPayloadContext;
public class PacketBattleInfo
public class PacketBattleInfo implements CustomPacketPayload
{
public static final ResourceLocation ID = new ResourceLocation(TurnBasedMinecraftMod.MODID, "network_packetbattleinfo");
private Collection<Integer> sideA;
private Collection<Integer> sideB;
private long decisionNanos;
private long maxDecisionNanos;
private boolean turnTimerEnabled;
public PacketBattleInfo()
{
sideA = new ArrayList<Integer>();
sideB = new ArrayList<Integer>();
decisionNanos = TurnBasedMinecraftMod.proxy.getConfig().getDecisionDurationNanos();
maxDecisionNanos = decisionNanos;
turnTimerEnabled = false;
}
public PacketBattleInfo(Collection<Integer> sideA, Collection<Integer> sideB, long decisionNanos)
public PacketBattleInfo(Collection<Integer> sideA, Collection<Integer> sideB, long decisionNanos, long maxDecisionNanos, boolean turnTimerEnabled)
{
this.sideA = sideA;
this.sideB = sideB;
this.decisionNanos = decisionNanos;
this.maxDecisionNanos = maxDecisionNanos;
this.turnTimerEnabled = turnTimerEnabled;
}
public static void encode(PacketBattleInfo pkt, PacketBuffer buf) {
buf.writeInt(pkt.sideA.size());
buf.writeInt(pkt.sideB.size());
for(Integer id : pkt.sideA) {
buf.writeInt(id);
}
for(Integer id : pkt.sideB) {
buf.writeInt(id);
}
buf.writeLong(pkt.decisionNanos);
public PacketBattleInfo(final FriendlyByteBuf buf) {
int sideACount = buf.readInt();
int sideBCount = buf.readInt();
this.sideA = new ArrayList<>(sideACount);
this.sideB = new ArrayList<>(sideBCount);
for (int i = 0; i < sideACount; ++i) {
this.sideA.add(buf.readInt());
}
for (int i = 0; i < sideBCount; ++i) {
this.sideB.add(buf.readInt());
}
this.decisionNanos = buf.readLong();
this.maxDecisionNanos = buf.readLong();
this.turnTimerEnabled = buf.readBoolean();
}
public static PacketBattleInfo decode(PacketBuffer buf) {
int sideACount = buf.readInt();
int sideBCount = buf.readInt();
Collection<Integer> sideA = new ArrayList<Integer>(sideACount);
Collection<Integer> sideB = new ArrayList<Integer>(sideBCount);
for(int i = 0; i < sideACount; ++i) {
sideA.add(buf.readInt());
}
for(int i = 0; i < sideBCount; ++i) {
sideB.add(buf.readInt());
}
long decisionNanos = buf.readLong();
return new PacketBattleInfo(sideA, sideB, decisionNanos);
@Override
public void write(FriendlyByteBuf buf) {
buf.writeInt(sideA.size());
buf.writeInt(sideB.size());
for(Integer id : sideA) {
buf.writeInt(id);
}
for(Integer id : sideB) {
buf.writeInt(id);
}
buf.writeLong(decisionNanos);
buf.writeLong(maxDecisionNanos);
buf.writeBoolean(turnTimerEnabled);
}
public static class Handler {
public static void handle(final PacketBattleInfo pkt, Supplier<NetworkEvent.Context> ctx) {
ctx.get().enqueueWork(() -> {
@Override
public ResourceLocation id() {
return ID;
}
public static class PayloadHandler {
private static final PayloadHandler INSTANCE = new PayloadHandler();
public static PayloadHandler getInstance() {
return INSTANCE;
}
public void handleData(final PacketBattleInfo pkt, final PlayPayloadContext ctx) {
ctx.workHandler().submitAsync(() -> {
if(TurnBasedMinecraftMod.proxy.getLocalBattle() == null)
{
return;
@ -84,8 +109,12 @@ public class PacketBattleInfo
}
TurnBasedMinecraftMod.proxy.setBattleGuiTime((int)(pkt.decisionNanos / 1000000000L));
TurnBasedMinecraftMod.proxy.setBattleGuiBattleChanged();
});
ctx.get().setPacketHandled(true);
}
TurnBasedMinecraftMod.proxy.setBattleGuiTurnTimerEnabled(pkt.turnTimerEnabled);
TurnBasedMinecraftMod.proxy.setBattleGuiTurnTimerMax((int)(pkt.maxDecisionNanos / 1000000000L));
}).exceptionally(e -> {
ctx.packetHandler().disconnect(Component.literal("Exception handling PacketBattleInfo! " + e.getMessage()));
return null;
});
}
}
}

View file

@ -2,21 +2,38 @@ package com.burnedkirby.TurnBasedMinecraft.common.networking;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
import com.burnedkirby.TurnBasedMinecraft.common.Utility;
import net.minecraft.entity.Entity;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.RegistryKey;
import net.minecraft.util.text.Color;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.world.World;
import net.minecraftforge.fml.network.NetworkEvent;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
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.PlayPayloadContext;
public class PacketBattleMessage
public class PacketBattleMessage implements CustomPacketPayload
{
public static final ResourceLocation ID = new ResourceLocation(TurnBasedMinecraftMod.MODID, "network_packetbattlemessage");
@Override
public void write(FriendlyByteBuf buf) {
buf.writeInt(messageType.getValue());
buf.writeInt(entityIDFrom);
buf.writeInt(entityIDTo);
buf.writeUtf(Utility.serializeDimension(dimension));
buf.writeInt(amount);
buf.writeUtf(custom);
}
@Override
public ResourceLocation id() {
return ID;
}
public enum MessageType
{
ENTERED(0),
@ -40,7 +57,8 @@ public class PacketBattleMessage
BOW_NO_AMMO(18),
CREEPER_WAIT(19),
CREEPER_WAIT_FINAL(20),
CREEPER_EXPLODE(21);
CREEPER_EXPLODE(21),
CROSSBOW_NO_AMMO(22);
private int value;
private static Map<Integer, MessageType> map = new HashMap<Integer, MessageType>();
@ -102,17 +120,40 @@ public class PacketBattleMessage
return map.get(value);
}
}
MessageType messageType;
int entityIDFrom;
int entityIDTo;
int amount;
String custom;
RegistryKey<World> dimension;
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 PacketBattleMessage() { custom = new String(); }
public PacketBattleMessage(MessageType messageType, int entityIDFrom, int entityIDTo, RegistryKey<World> dimension, int amount)
public PacketBattleMessage(MessageType messageType, int entityIDFrom, int entityIDTo, ResourceKey<Level> dimension, int amount)
{
this.messageType = messageType;
this.entityIDFrom = entityIDFrom;
@ -122,7 +163,7 @@ public class PacketBattleMessage
custom = new String();
}
public PacketBattleMessage(MessageType messageType, int entityIDFrom, int entityIDTo, RegistryKey<World> dimension, int amount, String custom)
public PacketBattleMessage(MessageType messageType, int entityIDFrom, int entityIDTo, ResourceKey<Level> dimension, int amount, String custom)
{
this.messageType = messageType;
this.entityIDFrom = entityIDFrom;
@ -131,204 +172,32 @@ public class PacketBattleMessage
this.amount = amount;
this.custom = custom;
}
public static void encode(PacketBattleMessage pkt, PacketBuffer buf) {
buf.writeInt(pkt.messageType.getValue());
buf.writeInt(pkt.entityIDFrom);
buf.writeInt(pkt.entityIDTo);
buf.writeUtf(Utility.serializeDimension(pkt.dimension));
buf.writeInt(pkt.amount);
buf.writeUtf(pkt.custom);
public PacketBattleMessage(final FriendlyByteBuf buf) {
this.messageType = MessageType.valueOf(buf.readInt());
this.entityIDFrom = buf.readInt();
this.entityIDTo = buf.readInt();
this.dimension = Utility.deserializeDimension(buf.readUtf());
this.amount = buf.readInt();
this.custom = buf.readUtf();
}
public static PacketBattleMessage decode(PacketBuffer buf) {
return new PacketBattleMessage(
MessageType.valueOf(
buf.readInt()),
buf.readInt(),
buf.readInt(),
Utility.deserializeDimension(buf.readUtf()),
buf.readInt(),
buf.readUtf());
}
public static class Handler {
public static void handle(final PacketBattleMessage pkt, Supplier<NetworkEvent.Context> ctx) {
ctx.get().enqueueWork(() -> {
Entity fromEntity = TurnBasedMinecraftMod.proxy.getEntity(pkt.entityIDFrom, pkt.dimension);
String from = "Unknown";
if(fromEntity != null)
{
from = fromEntity.getDisplayName().getString();
public static class PayloadHandler {
private static final PayloadHandler INSTANCE = new PayloadHandler();
public static PayloadHandler getInstance() {
return INSTANCE;
}
public void handleData(final PacketBattleMessage pkt, final PlayPayloadContext ctx) {
ctx.workHandler().submitAsync(() -> {
if (FMLEnvironment.dist.isClient()) {
TurnBasedMinecraftMod.proxy.handlePacket(pkt, ctx);
}
else if(TurnBasedMinecraftMod.proxy.getLocalBattle() != null)
{
fromEntity = TurnBasedMinecraftMod.proxy.getLocalBattle().getCombatantEntity(pkt.entityIDFrom);
if(fromEntity != null)
{
from = fromEntity.getDisplayName().getString();
}
}
Entity toEntity = TurnBasedMinecraftMod.proxy.getEntity(pkt.entityIDTo, pkt.dimension);
String to = "Unknown";
if(toEntity != null)
{
to = toEntity.getDisplayName().getString();
}
else if(TurnBasedMinecraftMod.proxy.getLocalBattle() != null)
{
toEntity = TurnBasedMinecraftMod.proxy.getLocalBattle().getCombatantEntity(pkt.entityIDTo);
if(toEntity != null)
{
to = toEntity.getDisplayName().getString();
}
}
switch(pkt.messageType)
{
case ENTERED:
TurnBasedMinecraftMod.proxy.displayString(from + " entered battle!");
if(TurnBasedMinecraftMod.proxy.getLocalBattle() == null || TurnBasedMinecraftMod.proxy.getLocalBattle().getId() != pkt.amount)
{
TurnBasedMinecraftMod.proxy.createLocalBattle(pkt.amount);
}
TurnBasedMinecraftMod.proxy.battleStarted();
TurnBasedMinecraftMod.proxy.typeEnteredBattle(pkt.custom);
break;
case FLEE:
if(pkt.amount != 0)
{
TurnBasedMinecraftMod.proxy.displayString(from + " fled battle!");
TurnBasedMinecraftMod.proxy.typeLeftBattle(pkt.custom);
}
else
{
TurnBasedMinecraftMod.proxy.displayString(from + " tried to flee battle but failed!");
}
break;
case DIED:
TurnBasedMinecraftMod.proxy.displayString(from + " died in battle!");
TurnBasedMinecraftMod.proxy.typeLeftBattle(pkt.custom);
break;
case ENDED:
TurnBasedMinecraftMod.proxy.displayString("Battle has ended!");
TurnBasedMinecraftMod.proxy.battleEnded();
break;
case ATTACK:
TurnBasedMinecraftMod.proxy.displayString(from + " attacked " + to + " and dealt " + pkt.amount + " damage!");
break;
case DEFEND:
TurnBasedMinecraftMod.proxy.displayString(from + " blocked " + to + "'s attack!");
break;
case DEFENSE_DAMAGE:
TurnBasedMinecraftMod.proxy.displayString(from + " retaliated from " + to + "'s attack and dealt " + pkt.amount + " damage!");
break;
case MISS:
TurnBasedMinecraftMod.proxy.displayString(from + " attacked " + to + " but missed!");
break;
case DEFENDING:
TurnBasedMinecraftMod.proxy.displayString(from + " is defending!");
break;
case DID_NOTHING:
TurnBasedMinecraftMod.proxy.displayString(from + " did nothing!");
break;
case USED_ITEM:
switch(UsedItemAction.valueOf(pkt.amount))
{
case USED_NOTHING:
TurnBasedMinecraftMod.proxy.displayString(from + " tried to use nothing!");
break;
case USED_INVALID:
if(pkt.custom.length() > 0)
{
TurnBasedMinecraftMod.proxy.displayString(from + " tried to consume " + pkt.custom + " and failed!");
}
else
{
TurnBasedMinecraftMod.proxy.displayString(from + " tried to consume an invalid item and failed!");
}
break;
case USED_FOOD:
TurnBasedMinecraftMod.proxy.displayString(from + " ate a " + pkt.custom + "!");
break;
case USED_POTION:
TurnBasedMinecraftMod.proxy.displayString(from + " drank a " + pkt.custom + "!");
break;
}
break;
case TURN_BEGIN:
TurnBasedMinecraftMod.proxy.displayString("The turn begins!");
TurnBasedMinecraftMod.proxy.battleGuiTurnBegin();
break;
case TURN_END:
if(TurnBasedMinecraftMod.proxy.getLocalBattle() != null)
{
if(pkt.amount == 0)
{
TurnBasedMinecraftMod.proxy.displayString("The turn ended!");
}
else
{
TurnBasedMinecraftMod.proxy.displayString("The turn ended (abnormally due to internal error)!");
}
}
TurnBasedMinecraftMod.proxy.battleGuiTurnEnd();
break;
case SWITCHED_ITEM:
if(pkt.amount != 0)
{
TurnBasedMinecraftMod.proxy.displayString(from + " switched to a different item!");
}
else
{
TurnBasedMinecraftMod.proxy.displayString(from + " switched to a different item but failed because it was invalid!");
}
break;
case WAS_AFFECTED:
TurnBasedMinecraftMod.proxy.displayString(to + " was " + pkt.custom + " by " + from + "!");
break;
case BECAME_CREATIVE:
TurnBasedMinecraftMod.proxy.displayString(from + " entered creative mode and left battle!");
break;
case FIRED_ARROW:
TurnBasedMinecraftMod.proxy.displayString(from + " let loose an arrow towards " + to + "!");
break;
case ARROW_HIT:
TurnBasedMinecraftMod.proxy.displayString(to + " was hit by " + from + "'s arrow!");
break;
case BOW_NO_AMMO:
TurnBasedMinecraftMod.proxy.displayString(from + " tried to use their bow but ran out of ammo!");
break;
case CREEPER_WAIT: {
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent message = new StringTextComponent(from + " is charging up!");
message.setStyle(message.getStyle().withColor(Color.fromRgb(0xFFFFFF00)));
prefix.getSiblings().add(message);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
}
break;
case CREEPER_WAIT_FINAL: {
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent message = new StringTextComponent(from + " is about to explode!");
message.setStyle(message.getStyle().withColor(Color.fromRgb(0xFFFF5050)));
prefix.getSiblings().add(message);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
}
break;
case CREEPER_EXPLODE: {
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent message = new StringTextComponent(from + " exploded!");
message.setStyle(message.getStyle().withColor(Color.fromRgb(0xFFFF0000)));
prefix.getSiblings().add(message);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
}
break;
}
});
ctx.get().setPacketHandled(true);
}
}).exceptionally(e -> {
ctx.packetHandler().disconnect(Component.literal("Exception handling PacketBattleMessage! " + e.getMessage()));
return null;
});
}
}
}

View file

@ -1,16 +1,18 @@
package com.burnedkirby.TurnBasedMinecraft.common.networking;
import java.util.function.Supplier;
import com.burnedkirby.TurnBasedMinecraft.common.Battle;
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
import io.netty.buffer.Unpooled;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.NetworkEvent;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import net.neoforged.neoforge.network.handling.PlayPayloadContext;
public class PacketBattleRequestInfo
public class PacketBattleRequestInfo implements CustomPacketPayload
{
public static final ResourceLocation ID = new ResourceLocation(TurnBasedMinecraftMod.MODID, "network_packetbattlerequestinfo");
private int battleID;
public PacketBattleRequestInfo() {}
@ -19,25 +21,44 @@ public class PacketBattleRequestInfo
{
this.battleID = battleID;
}
public static void encode(PacketBattleRequestInfo pkt, PacketBuffer buf) {
buf.writeInt(pkt.battleID);
public PacketBattleRequestInfo(final FriendlyByteBuf buf) {
battleID = buf.readInt();
}
public static PacketBattleRequestInfo decode(PacketBuffer buf) {
return new PacketBattleRequestInfo(buf.readInt());
@Override
public void write(FriendlyByteBuf buf) {
buf.writeInt(battleID);
}
public static class Handler {
public static void handle(final PacketBattleRequestInfo pkt, Supplier<NetworkEvent.Context> ctx) {
ctx.get().enqueueWork(() -> {
@Override
public ResourceLocation id() {
return ID;
}
public static class PayloadHandler {
private static final PayloadHandler INSTANCE = new PayloadHandler();
public static PayloadHandler getInstance() {
return INSTANCE;
}
public void handleData(final PacketBattleRequestInfo pkt, final PlayPayloadContext ctx) {
ctx.workHandler().submitAsync(() -> {
Battle b = TurnBasedMinecraftMod.proxy.getBattleManager().getBattleByID(pkt.battleID);
if(b == null) {
return;
return;
}
TurnBasedMinecraftMod.getHandler().reply(new PacketBattleInfo(b.getSideAIDs(), b.getSideBIDs(), b.getTimerSeconds()), ctx.get());
});
ctx.get().setPacketHandled(true);
}
ctx.replyHandler().send(new PacketBattleInfo(
b.getSideAIDs(),
b.getSideBIDs(),
b.getTimerNanos(),
TurnBasedMinecraftMod.proxy.getConfig().getDecisionDurationNanos(),
!TurnBasedMinecraftMod.proxy.getConfig().isBattleDecisionDurationForever()));
}).exceptionally(e -> {
ctx.packetHandler().disconnect(Component.literal("Exception handling PacketBattleRequestInfo! " + e.getMessage()));
return null;
});
}
}
}

View file

@ -2,20 +2,50 @@ package com.burnedkirby.TurnBasedMinecraft.common.networking;
import com.burnedkirby.TurnBasedMinecraft.common.EntityInfo;
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.text.Color;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.event.ClickEvent;
import net.minecraft.util.text.event.HoverEvent;
import net.minecraftforge.fml.network.NetworkEvent;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
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.PlayPayloadContext;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
public class PacketEditingMessage
public class PacketEditingMessage implements CustomPacketPayload
{
public static final ResourceLocation ID = new ResourceLocation(TurnBasedMinecraftMod.MODID, "network_packeteditingmessage");
@Override
public void write(FriendlyByteBuf buf) {
buf.writeInt(type.getValue());
if(entityInfo.classType != null) {
buf.writeUtf(entityInfo.classType.getName());
} else {
buf.writeUtf("unknown");
}
buf.writeBoolean(entityInfo.ignoreBattle);
buf.writeInt(entityInfo.attackPower);
buf.writeInt(entityInfo.attackProbability);
buf.writeInt(entityInfo.attackVariance);
buf.writeUtf(entityInfo.attackEffect.toString());
buf.writeInt(entityInfo.attackEffectProbability);
buf.writeInt(entityInfo.defenseDamage);
buf.writeInt(entityInfo.defenseDamageProbability);
buf.writeInt(entityInfo.evasion);
buf.writeInt(entityInfo.speed);
buf.writeUtf(entityInfo.category);
buf.writeInt(entityInfo.decisionAttack);
buf.writeInt(entityInfo.decisionDefend);
buf.writeInt(entityInfo.decisionFlee);
buf.writeUtf(entityInfo.customName);
}
@Override
public ResourceLocation id() {
return ID;
}
public enum Type
{
ATTACK_ENTITY(0),
@ -33,7 +63,8 @@ public class PacketEditingMessage
EDIT_CATEGORY(12),
EDIT_DECISION_ATTACK(13),
EDIT_DECISION_DEFEND(14),
EDIT_DECISION_FLEE(15);
EDIT_DECISION_FLEE(15),
SERVER_EDIT(16);
Type(int value)
{
@ -66,6 +97,14 @@ public class PacketEditingMessage
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)
@ -81,652 +120,46 @@ public class PacketEditingMessage
this.entityInfo = entityInfo;
}
}
public static void encode(PacketEditingMessage pkt, PacketBuffer buf) {
buf.writeInt(pkt.type.getValue());
if(pkt.entityInfo.classType != null) {
buf.writeUtf(pkt.entityInfo.classType.getName());
} else {
buf.writeUtf("unknown");
}
buf.writeBoolean(pkt.entityInfo.ignoreBattle);
buf.writeInt(pkt.entityInfo.attackPower);
buf.writeInt(pkt.entityInfo.attackProbability);
buf.writeInt(pkt.entityInfo.attackVariance);
buf.writeUtf(pkt.entityInfo.attackEffect.toString());
buf.writeInt(pkt.entityInfo.attackEffectProbability);
buf.writeInt(pkt.entityInfo.defenseDamage);
buf.writeInt(pkt.entityInfo.defenseDamageProbability);
buf.writeInt(pkt.entityInfo.evasion);
buf.writeInt(pkt.entityInfo.speed);
buf.writeUtf(pkt.entityInfo.category);
buf.writeInt(pkt.entityInfo.decisionAttack);
buf.writeInt(pkt.entityInfo.decisionDefend);
buf.writeInt(pkt.entityInfo.decisionFlee);
buf.writeUtf(pkt.entityInfo.customName);
}
public static PacketEditingMessage decode(PacketBuffer buf) {
Type type = Type.valueOf(buf.readInt());
EntityInfo einfo = new EntityInfo();
try {
einfo.classType = einfo.getClass().getClassLoader().loadClass(buf.readUtf());
} catch (ClassNotFoundException e) { /* ignored */ }
einfo.ignoreBattle = buf.readBoolean();
einfo.attackPower = buf.readInt();
einfo.attackProbability = buf.readInt();
einfo.attackVariance = buf.readInt();
einfo.attackEffect = EntityInfo.Effect.fromString(buf.readUtf());
einfo.attackEffectProbability = buf.readInt();
einfo.defenseDamage = buf.readInt();
einfo.defenseDamageProbability = buf.readInt();
einfo.evasion = buf.readInt();
einfo.speed = buf.readInt();
einfo.category = buf.readUtf();
einfo.decisionAttack = buf.readInt();
einfo.decisionDefend = buf.readInt();
einfo.decisionFlee = buf.readInt();
einfo.customName = buf.readUtf();
return new PacketEditingMessage(type, einfo);
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 Handler {
public static void handle(final PacketEditingMessage pkt, Supplier<NetworkEvent.Context> ctx) {
ctx.get().enqueueWork(() -> {
switch(pkt.type)
{
case ATTACK_ENTITY:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("Attack the entity you want to edit for TurnBasedMinecraftMod. ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
public static class PayloadHandler {
private static final PayloadHandler INSTANCE = new PayloadHandler();
StringTextComponent cancel = new StringTextComponent("Cancel");
cancel.setStyle(cancel.getStyle().withColor(Color.fromRgb(0xFFFF0000)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit cancel")));
text.getSiblings().add(cancel);
public static PayloadHandler getInstance() {
return INSTANCE;
}
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
public void handleData(final PacketEditingMessage pkt, final PlayPayloadContext ctx) {
ctx.workHandler().submitAsync(() -> {
if (FMLEnvironment.dist.isClient()) {
TurnBasedMinecraftMod.proxy.handlePacket(pkt, ctx);
}
case PICK_EDIT:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("Edit what value? ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
StringTextComponent option = new StringTextComponent("IgB");
// HoverEvent.Action.SHOW_TEXT is probably SHOW_TEXT
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit ignoreBattle"))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent("IgnoreBattle"))));
StringTextComponent value = new StringTextComponent("(" + pkt.entityInfo.ignoreBattle + ") ");
value.setStyle(value.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
option.getSiblings().add(value);
text.getSiblings().add(option);
option = new StringTextComponent("AP");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit attackPower"))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent("AttackPower"))));
value = new StringTextComponent("(" + pkt.entityInfo.attackPower + ") ");
value.setStyle(value.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
option.getSiblings().add(value);
text.getSiblings().add(option);
option = new StringTextComponent("APr");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit attackProbability"))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent("AttackProbability"))));
value = new StringTextComponent("(" + pkt.entityInfo.attackProbability + "%) ");
value.setStyle(value.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
option.getSiblings().add(value);
text.getSiblings().add(option);
option = new StringTextComponent("AV");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit attackVariance"))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent("AttackVariance"))));
value = new StringTextComponent("(" + pkt.entityInfo.attackVariance + ") ");
value.setStyle(value.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
option.getSiblings().add(value);
text.getSiblings().add(option);
option = new StringTextComponent("AE");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit attackEffect"))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent("AttackEffect"))));
value = new StringTextComponent("(" + pkt.entityInfo.attackEffect.toString() + ") ");
value.setStyle(value.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
option.getSiblings().add(value);
text.getSiblings().add(option);
option = new StringTextComponent("AEPr");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit attackEffectProbability"))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent("AttackEffectProbability"))));
value = new StringTextComponent("(" + pkt.entityInfo.attackEffectProbability + "%) ");
value.setStyle(value.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
option.getSiblings().add(value);
text.getSiblings().add(option);
option = new StringTextComponent("DD");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit defenseDamage"))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent("DefenseDamage"))));
value = new StringTextComponent("(" + pkt.entityInfo.defenseDamage + ") ");
value.setStyle(value.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
option.getSiblings().add(value);
text.getSiblings().add(option);
option = new StringTextComponent("DDPr");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit defenseDamageProbability"))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent("DefenseDamageProbability"))));
value = new StringTextComponent("(" + pkt.entityInfo.defenseDamageProbability + "%) ");
value.setStyle(value.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
option.getSiblings().add(value);
text.getSiblings().add(option);
option = new StringTextComponent("E");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit evasion"))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent("Evasion"))));
value = new StringTextComponent("(" + pkt.entityInfo.evasion + "%) ");
value.setStyle(value.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
option.getSiblings().add(value);
text.getSiblings().add(option);
option = new StringTextComponent("S");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit speed"))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent("Speed"))));
value = new StringTextComponent("(" + pkt.entityInfo.speed + ") ");
value.setStyle(value.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
option.getSiblings().add(value);
text.getSiblings().add(option);
option = new StringTextComponent("C");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit category"))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent("Category"))));
value = new StringTextComponent("(" + pkt.entityInfo.category + ") ");
value.setStyle(value.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
option.getSiblings().add(value);
text.getSiblings().add(option);
option = new StringTextComponent("DecA");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit decisionAttack"))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent("DecisionAttack"))));
value = new StringTextComponent("(" + pkt.entityInfo.decisionAttack + "%) ");
value.setStyle(value.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
option.getSiblings().add(value);
text.getSiblings().add(option);
option = new StringTextComponent("DecD");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit decisionDefend"))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent("DecisionDefend"))));
value = new StringTextComponent("(" + pkt.entityInfo.decisionDefend + "%) ");
value.setStyle(value.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
option.getSiblings().add(value);
text.getSiblings().add(option);
option = new StringTextComponent("DecF");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit decisionFlee"))
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new StringTextComponent("DecisionFlee"))));
value = new StringTextComponent("(" + pkt.entityInfo.decisionFlee + "%) ");
value.setStyle(value.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
option.getSiblings().add(value);
text.getSiblings().add(option);
option = new StringTextComponent("Finished Editing");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit finish")));
text.getSiblings().add(option);
text.getSiblings().add(new StringTextComponent(" "));
option = new StringTextComponent("Cancel");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFF0000)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit cancel")));
text.getSiblings().add(option);
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
case EDIT_IGNORE_BATTLE:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("ignoreBattle: ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
StringTextComponent option = new StringTextComponent("true");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit ignoreBattle true")));
text.getSiblings().add(option);
text.getSiblings().add(new StringTextComponent(" "));
option = new StringTextComponent("false");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFF0000)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit ignoreBattle false")));
text.getSiblings().add(option);
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
case EDIT_ATTACK_POWER:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("attackPower: ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
for(int i = 0; i <= 15; ++i)
{
StringTextComponent option = new StringTextComponent(Integer.toString(i));
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit attackPower " + Integer.toString(i))));
text.getSiblings().add(option);
if(i < 15)
{
text.getSiblings().add(new StringTextComponent(", "));
}
}
text.getSiblings().add(new StringTextComponent(" (or use command \"/tbm-edit edit attackPower <integer>\")"));
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
case EDIT_ATTACK_PROBABILITY:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("attackProbability: ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
for(int i = 10; i <= 100; i += 10)
{
StringTextComponent option = new StringTextComponent(Integer.toString(i) + "%");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit attackProbability " + Integer.toString(i))));
text.getSiblings().add(option);
if(i < 100)
{
text.getSiblings().add(new StringTextComponent(", "));
}
}
text.getSiblings().add(new StringTextComponent(" (or use command \"/tbm-edit edit attackProbability <percentage-integer>\")"));
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
case EDIT_ATTACK_VARIANCE:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("attackVariance: ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
for(int i = 0; i <= 10; ++i)
{
StringTextComponent option = new StringTextComponent(Integer.toString(i));
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit attackVariance " + Integer.toString(i))));
text.getSiblings().add(option);
if(i < 10)
{
text.getSiblings().add(new StringTextComponent(", "));
}
}
text.getSiblings().add(new StringTextComponent(" (or use command \"/tbm-edit edit attackVariance <integer>\")"));
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
case EDIT_ATTACK_EFFECT:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("attackEffect: ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
for(EntityInfo.Effect e : EntityInfo.Effect.values())
{
StringTextComponent option = new StringTextComponent(e.toString());
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit attackEffect " + e.toString())));
text.getSiblings().add(option);
if(e != EntityInfo.Effect.UNKNOWN)
{
// TODO find a better way to handle printing comma for items before last
text.getSiblings().add(new StringTextComponent(", "));
}
}
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
case EDIT_ATTACK_EFFECT_PROBABILITY:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("attackEffectProbability: ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
for(int i = 0; i <= 100; i += 10)
{
StringTextComponent option = new StringTextComponent(Integer.toString(i) + "%");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit attackEffectProbability " + Integer.toString(i))));
text.getSiblings().add(option);
if(i < 100)
{
text.getSiblings().add(new StringTextComponent(", "));
}
}
text.getSiblings().add(new StringTextComponent(" (or use command \"/tbm-edit edit attackEffectProbability <percentage-integer>\")"));
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
case EDIT_DEFENSE_DAMAGE:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("defenseDamage: ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
for(int i = 0; i <= 15; ++i)
{
StringTextComponent option = new StringTextComponent(Integer.toString(i));
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit defenseDamage " + Integer.toString(i))));
text.getSiblings().add(option);
if(i < 15)
{
text.getSiblings().add(new StringTextComponent(", "));
}
}
text.getSiblings().add(new StringTextComponent(" (or use command \"/tbm-edit edit defenseDamage <integer>\")"));
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
case EDIT_DEFENSE_DAMAGE_PROBABILITY:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("defenseDamageProbability: ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
for(int i = 0; i <= 100; i += 10)
{
StringTextComponent option = new StringTextComponent(Integer.toString(i) + "%");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit defenseDamageProbability " + Integer.toString(i))));
text.getSiblings().add(option);
if(i < 100)
{
text.getSiblings().add(new StringTextComponent(", "));
}
}
text.getSiblings().add(new StringTextComponent(" (or use command \"/tbm-edit edit defenseDamageProbability <percentage-integer>\")"));
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
case EDIT_EVASION:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("evasion: ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
for(int i = 0; i <= 100; i += 10)
{
StringTextComponent option = new StringTextComponent(Integer.toString(i) + "%");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit evasion " + Integer.toString(i))));
text.getSiblings().add(option);
if(i < 100)
{
text.getSiblings().add(new StringTextComponent(", "));
}
}
text.getSiblings().add(new StringTextComponent(" (or use command \"/tbm-edit edit evasion <percentage-integer>\")"));
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
case EDIT_SPEED:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("speed: ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
for(int i = 0; i <= 100; i += 10)
{
StringTextComponent option = new StringTextComponent(Integer.toString(i));
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit speed " + Integer.toString(i))));
text.getSiblings().add(option);
if(i < 100)
{
text.getSiblings().add(new StringTextComponent(", "));
}
}
text.getSiblings().add(new StringTextComponent(" (or use command \"/tbm-edit edit speed <integer>\")"));
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
case EDIT_CATEGORY:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("category: ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
StringTextComponent option = new StringTextComponent("monster");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit category monster")));
if(TurnBasedMinecraftMod.proxy.getConfig().isIgnoreBattleType("monster"))
{
StringTextComponent optionInfo = new StringTextComponent("(battle-");
optionInfo.setStyle(optionInfo.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
StringTextComponent optionInfoBool = new StringTextComponent("disabled");
optionInfoBool.setStyle(optionInfoBool.getStyle().withColor(Color.fromRgb(0xFFFF0000)));
optionInfo.getSiblings().add(optionInfoBool);
optionInfo.getSiblings().add(new StringTextComponent(")"));
option.getSiblings().add(optionInfo);
}
else
{
StringTextComponent optionInfo = new StringTextComponent("(battle-");
optionInfo.setStyle(optionInfo.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
StringTextComponent optionInfoBool = new StringTextComponent("enabled");
optionInfoBool.setStyle(optionInfoBool.getStyle().withColor(Color.fromRgb(0xFF00FF00)));
optionInfo.getSiblings().add(optionInfoBool);
optionInfo.getSiblings().add(new StringTextComponent(")"));
option.getSiblings().add(optionInfo);
}
text.getSiblings().add(option);
text.getSiblings().add(new StringTextComponent(", "));
option = new StringTextComponent("animal");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit category animal")));
if(TurnBasedMinecraftMod.proxy.getConfig().isIgnoreBattleType("animal"))
{
StringTextComponent optionInfo = new StringTextComponent("(battle-");
optionInfo.setStyle(optionInfo.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
StringTextComponent optionInfoBool = new StringTextComponent("disabled");
optionInfoBool.setStyle(optionInfoBool.getStyle().withColor(Color.fromRgb(0xFFFF0000)));
optionInfo.getSiblings().add(optionInfoBool);
optionInfo.getSiblings().add(new StringTextComponent(")"));
option.getSiblings().add(optionInfo);
}
else
{
StringTextComponent optionInfo = new StringTextComponent("(battle-");
optionInfo.setStyle(optionInfo.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
StringTextComponent optionInfoBool = new StringTextComponent("enabled");
optionInfoBool.setStyle(optionInfoBool.getStyle().withColor(Color.fromRgb(0xFF00FF00)));
optionInfo.getSiblings().add(optionInfoBool);
optionInfo.getSiblings().add(new StringTextComponent(")"));
option.getSiblings().add(optionInfo);
}
text.getSiblings().add(option);
text.getSiblings().add(new StringTextComponent(", "));
option = new StringTextComponent("passive");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit category passive")));
if(TurnBasedMinecraftMod.proxy.getConfig().isIgnoreBattleType("passive"))
{
StringTextComponent optionInfo = new StringTextComponent("(battle-");
optionInfo.setStyle(optionInfo.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
StringTextComponent optionInfoBool = new StringTextComponent("disabled");
optionInfoBool.setStyle(optionInfoBool.getStyle().withColor(Color.fromRgb(0xFFFF0000)));
optionInfo.getSiblings().add(optionInfoBool);
optionInfo.getSiblings().add(new StringTextComponent(")"));
option.getSiblings().add(optionInfo);
}
else
{
StringTextComponent optionInfo = new StringTextComponent("(battle-");
optionInfo.setStyle(optionInfo.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
StringTextComponent optionInfoBool = new StringTextComponent("enabled");
optionInfoBool.setStyle(optionInfoBool.getStyle().withColor(Color.fromRgb(0xFF00FF00)));
optionInfo.getSiblings().add(optionInfoBool);
optionInfo.getSiblings().add(new StringTextComponent(")"));
option.getSiblings().add(optionInfo);
}
text.getSiblings().add(option);
text.getSiblings().add(new StringTextComponent(", "));
option = new StringTextComponent("boss");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit category boss")));
if(TurnBasedMinecraftMod.proxy.getConfig().isIgnoreBattleType("boss"))
{
StringTextComponent optionInfo = new StringTextComponent("(battle-");
optionInfo.setStyle(optionInfo.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
StringTextComponent optionInfoBool = new StringTextComponent("disabled");
optionInfoBool.setStyle(optionInfoBool.getStyle().withColor(Color.fromRgb(0xFFFF0000)));
optionInfo.getSiblings().add(optionInfoBool);
optionInfo.getSiblings().add(new StringTextComponent(")"));
option.getSiblings().add(optionInfo);
}
else
{
StringTextComponent optionInfo = new StringTextComponent("(battle-");
optionInfo.setStyle(optionInfo.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
StringTextComponent optionInfoBool = new StringTextComponent("enabled");
optionInfoBool.setStyle(optionInfoBool.getStyle().withColor(Color.fromRgb(0xFF00FF00)));
optionInfo.getSiblings().add(optionInfoBool);
optionInfo.getSiblings().add(new StringTextComponent(")"));
option.getSiblings().add(optionInfo);
}
text.getSiblings().add(option);
text.getSiblings().add(new StringTextComponent(", "));
option = new StringTextComponent("player");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit category player")));
if(TurnBasedMinecraftMod.proxy.getConfig().isIgnoreBattleType("player"))
{
StringTextComponent optionInfo = new StringTextComponent("(battle-");
optionInfo.setStyle(optionInfo.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
StringTextComponent optionInfoBool = new StringTextComponent("disabled");
optionInfoBool.setStyle(optionInfoBool.getStyle().withColor(Color.fromRgb(0xFFFF0000)));
optionInfo.getSiblings().add(optionInfoBool);
optionInfo.getSiblings().add(new StringTextComponent(")"));
option.getSiblings().add(optionInfo);
}
else
{
StringTextComponent optionInfo = new StringTextComponent("(battle-");
optionInfo.setStyle(optionInfo.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)));
StringTextComponent optionInfoBool = new StringTextComponent("enabled");
optionInfoBool.setStyle(optionInfoBool.getStyle().withColor(Color.fromRgb(0xFF00FF00)));
optionInfo.getSiblings().add(optionInfoBool);
optionInfo.getSiblings().add(new StringTextComponent(")"));
option.getSiblings().add(optionInfo);
}
text.getSiblings().add(option);
text.getSiblings().add(new StringTextComponent(" (or use command \"/tbm-edit edit category <string>\")"));
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
case EDIT_DECISION_ATTACK:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("decisionAttack: ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
for(int i = 0; i <= 100; i += 10)
{
StringTextComponent option = new StringTextComponent(Integer.toString(i) + "%");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit decisionAttack " + Integer.toString(i))));
text.getSiblings().add(option);
if(i < 100)
{
text.getSiblings().add(new StringTextComponent(", "));
}
}
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
case EDIT_DECISION_DEFEND:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("decisionDefend: ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
for(int i = 0; i <= 100; i += 10)
{
StringTextComponent option = new StringTextComponent(Integer.toString(i) + "%");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit decisionDefend " + Integer.toString(i))));
text.getSiblings().add(option);
if(i < 100)
{
text.getSiblings().add(new StringTextComponent(", "));
}
}
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
case EDIT_DECISION_FLEE:
{
StringTextComponent prefix = new StringTextComponent("TBM: ");
prefix.setStyle(prefix.getStyle().withColor(Color.fromRgb(0xFF00FF00)).withBold(true));
StringTextComponent text = new StringTextComponent("decisionFlee: ");
text.setStyle(text.getStyle().withColor(Color.fromRgb(0xFFFFFFFF)).withBold(false));
for(int i = 0; i <= 100; i += 10)
{
StringTextComponent option = new StringTextComponent(Integer.toString(i) + "%");
option.setStyle(option.getStyle().withColor(Color.fromRgb(0xFFFFFF00)).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tbm-edit edit decisionFlee " + Integer.toString(i))));
text.getSiblings().add(option);
if(i < 100)
{
text.getSiblings().add(new StringTextComponent(", "));
}
}
prefix.getSiblings().add(text);
TurnBasedMinecraftMod.proxy.displayTextComponent(prefix);
break;
}
default:
break;
}
});
ctx.get().setPacketHandled(true);
}
}).exceptionally(e -> {
ctx.packetHandler().disconnect(Component.literal("Exception handling PacketEditingMessage! " + e.getMessage()));
return null;
});
}
}
}
}

View file

@ -1,15 +1,23 @@
package com.burnedkirby.TurnBasedMinecraft.common.networking;
import java.util.function.Supplier;
import com.burnedkirby.TurnBasedMinecraft.common.TurnBasedMinecraftMod;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.NetworkEvent;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
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.PlayPayloadContext;
public class PacketGeneralMessage
public class PacketGeneralMessage implements CustomPacketPayload
{
public static final ResourceLocation ID = new ResourceLocation(TurnBasedMinecraftMod.MODID, "network_packetgeneralmessage");
String message;
public String getMessage() {
return message;
}
public PacketGeneralMessage()
{
@ -20,21 +28,37 @@ public class PacketGeneralMessage
{
this.message = message;
}
public static void encode(PacketGeneralMessage pkt, PacketBuffer buf) {
buf.writeUtf(pkt.message);
public PacketGeneralMessage(final FriendlyByteBuf buf) {
this.message = buf.readUtf();
}
public static PacketGeneralMessage decode(PacketBuffer buf) {
return new PacketGeneralMessage(buf.readUtf());
@Override
public void write(FriendlyByteBuf buf) {
buf.writeUtf(message);
}
public static class Handler {
public static void handle(final PacketGeneralMessage pkt, Supplier<NetworkEvent.Context> ctx) {
ctx.get().enqueueWork(() -> {
TurnBasedMinecraftMod.proxy.displayString(pkt.message);
});
ctx.get().setPacketHandled(true);
}
@Override
public ResourceLocation id() {
return ID;
}
public static class PayloadHandler {
private static final PayloadHandler INSTANCE = new PayloadHandler();
public static PayloadHandler getInstance() {
return INSTANCE;
}
public void handleData(final PacketGeneralMessage pkt, final PlayPayloadContext ctx) {
ctx.workHandler().submitAsync(() -> {
if (FMLEnvironment.dist.isClient()) {
TurnBasedMinecraftMod.proxy.handlePacket(pkt, ctx);
}
}).exceptionally(e -> {
ctx.packetHandler().disconnect(Component.literal("Exception handling PacketGeneralMessage! " + e.getMessage()));
return null;
});
}
}
}

View file

@ -6,18 +6,18 @@
# 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 forge version
loaderVersion="[34,)" #mandatory (34 is current forge version)
loaderVersion="${loader_version_range}" #mandatory (34 is current forge version)
# A URL to refer people to when problems occur with this mod
issueTrackerURL="https://github.com/Stephen-Seo/TurnBasedMinecraftMod/issues" #optional
license="MIT"
license="${mod_license}"
# A list of mods - how many allowed here is determined by the individual mod loader
[[mods]] #mandatory
# The modid of the mod
modId="com_burnedkirby_turnbasedminecraft" #mandatory
modId="${mod_id}" #mandatory
# The version number of the mod - there's a few well known ${} variables useable here or just hardcode it
version="1.17.2" #mandatory
version="${mod_version}" #mandatory
# A display name for the mod
displayName="TurnBasedMinecraftMod" #mandatory
displayName="${mod_name}" #mandatory
# A URL to query for updates for this mod. See the JSON update specification <here>
#updateJSONURL="" #optional
# A URL for the "homepage" for this mod, displayed in the mod UI
@ -27,19 +27,20 @@ displayURL="https://github.com/Stephen-Seo/TurnBasedMinecraftMod" #optional
# A text field displayed in the mod UI
credits="Thanks for this mod goes to Java" #optional
# A text field displayed in the mod UI
authors="BurnedKirby" #optional
authors="${mod_authors}" #optional
# The description text for the mod (multi line!) (#mandatory)
description='''
Implements turn-based-battle in Minecraft.
'''
description='''${mod_description}'''
logoFile="assets/com_burnedkirby_turnbasedminecraft/tbmm_icon.png"
# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional.
[[dependencies.com_burnedkirby_turnbasedminecraft]] #optional
# the modid of the dependency
modId="forge" #mandatory
modId="neoforge" #mandatory
# Does this dependency have to exist - if not, ordering below must be specified
mandatory=true #mandatory
type="required" #mandatory
# The version range of the dependency
versionRange="[36,)" #mandatory
versionRange="${neo_version_range}" #mandatory
# An ordering relationship for the dependency - BEFORE or AFTER required if the relationship is not mandatory
ordering="NONE"
# Side this dependency is applied on - BOTH, CLIENT or SERVER
@ -47,7 +48,7 @@ Implements turn-based-battle in Minecraft.
# Here's another dependency
[[dependencies.com_burnedkirby_turnbasedminecraft]]
modId="minecraft"
mandatory=true
versionRange="[1.16.5,1.17)"
type="required"
versionRange="${minecraft_version_range}"
ordering="NONE"
side="BOTH"

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View file

@ -1,18 +0,0 @@
[
{
"modid": "com_burnedkirby_turnbasedminecraft",
"name": "Turn Based Minecraft",
"description": "Changes battles to be turn-based.",
"version": "1.17.2",
"mcversion": "1.16.3",
"url": "",
"updateUrl": "",
"authorList": ["Stephen Seo"],
"credits": "The Forge and FML guys, for making this possible.
Dependencies:
JavaMP3 by delthas, josephx86, GlaDOSik, and kevinstadler (MIT License)",
"logoFile": "",
"screenshots": [],
"dependencies": []
}
]