From 792eae771e902a25420d0ad367c43f570545bb60 Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Tue, 17 Mar 2026 18:12:40 +0100 Subject: build(gradle): bump mod version to 1.3.0 --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 958a1c5..afaca83 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.21.11 yarn_mappings=1.21.11+build.4 loader_version=0.18.4 # Mod Properties -mod_version=1.2.1 +mod_version=1.3.0 maven_group=world.anhgelus archives_base_name=Molehunt # Dependencies -- cgit v1.2.3 From 3b694a936c7138acc5eaca3da2ec528c2e8c0894 Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Wed, 18 Mar 2026 13:04:34 +0100 Subject: fix(timer): too long task converting into milliseconds instead of ticks --- .editorconfig | 2 ++ src/main/java/world/anhgelus/molehunt/game/Game.java | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..6d4b8c2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,2 @@ +[*] +end_of_line = crlf \ No newline at end of file diff --git a/src/main/java/world/anhgelus/molehunt/game/Game.java b/src/main/java/world/anhgelus/molehunt/game/Game.java index 98fe2b8..4f3234c 100644 --- a/src/main/java/world/anhgelus/molehunt/game/Game.java +++ b/src/main/java/world/anhgelus/molehunt/game/Game.java @@ -67,9 +67,9 @@ public class Game { timer.dds_runTask(new TickTask(() -> worldBorder.interpolateSize( Molehunt.CONFIG.getInitialWorldSize(), Molehunt.CONFIG.getFinalWorldSize(), - (long) (Molehunt.CONFIG.getGameDuration() - Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset()) * 60 * 1000, + (Molehunt.CONFIG.getGameDuration() - Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset()) * 60 * 20L, 0L - ), (long) Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset() * 60 * 1000)); + ), Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset() * 60 * 20L)); } final var title = new TitleS2CPacket(Text.translatable("molehunt.game.start.suspense")); @@ -114,8 +114,8 @@ public class Game { }); playerManager.sendToAll(timing); if (remaining == 0) end(); - }, 5 * 1000, 1000)); - }, 4 * 1000)); + }, 5 * 20, 20)); + }, 4 * 20)); } public void stop() { @@ -150,7 +150,7 @@ public class Game { pm.sendToAll(winner); pm.sendToAll(timing); moles.clear(); - }, 4 * 1000)); + }, 4 * 20)); } public Text getRemainingText() { -- cgit v1.2.3 From 7ba39f866a3ab293ce81b5397c1e2975241919cb Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Wed, 18 Mar 2026 13:11:45 +0100 Subject: style(): switch to tab and to lf --- .editorconfig | 7 +- .github/ISSUE_TEMPLATE/bug_report.md | 2 + .github/workflows/build-docs.yml | 128 +++---- README.md | 5 +- Writerside/cfg/buildprofiles.xml | 16 +- Writerside/topics/config-file.md | 22 +- Writerside/topics/configuration.md | 2 +- Writerside/topics/gamerules.md | 15 +- Writerside/topics/introduction.md | 11 +- Writerside/topics/resource-pack.md | 49 +-- Writerside/topics/usage.md | 7 +- build.gradle | 102 ++--- settings.gradle | 14 +- .../anhgelus/molehunt/client/MolehuntClient.java | 90 ++--- .../client/mixin/NoCustomizableSkinOverlay.java | 16 +- .../anhgelus/molehunt/client/mixin/NoNametags.java | 12 +- .../molehunt/client/mixin/NoPlayerListHud.java | 10 +- .../anhgelus/molehunt/client/mixin/NoSkin.java | 20 +- .../resources/assets/molehunt/lang/en_us.json | 52 +-- .../resources/assets/molehunt/lang/fr_fr.json | 52 +-- src/client/resources/molehunt.client.mixins.json | 26 +- .../java/world/anhgelus/molehunt/Molehunt.java | 377 +++++++++--------- .../world/anhgelus/molehunt/config/Config.java | 262 ++++++------- .../anhgelus/molehunt/config/ConfigPayload.java | 24 +- .../anhgelus/molehunt/config/SimpleConfig.java | 422 ++++++++++----------- .../java/world/anhgelus/molehunt/game/Game.java | 344 ++++++++--------- .../world/anhgelus/molehunt/game/GamePayload.java | 20 +- .../molehunt/mixin/NoJoinLeaveMessage.java | 12 +- .../anhgelus/molehunt/mixin/NoMsgCommand.java | 8 +- .../world/anhgelus/molehunt/mixin/NoPortals.java | 10 +- .../anhgelus/molehunt/mixin/WorldTimerAccess.java | 56 +-- .../world/anhgelus/molehunt/timer/TickTask.java | 118 +++--- .../world/anhgelus/molehunt/timer/TimerAccess.java | 96 ++--- .../world/anhgelus/molehunt/utils/TimeUtils.java | 93 ++--- src/main/resources/fabric.mod.json | 69 ++-- src/main/resources/molehunt.mixins.json | 26 +- 36 files changed, 1295 insertions(+), 1300 deletions(-) diff --git a/.editorconfig b/.editorconfig index 6d4b8c2..886d72a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,2 +1,7 @@ [*] -end_of_line = crlf \ No newline at end of file +end_of_line = lf +indent_style = tab +ij_smart_tabs = true + +[*.json] +tab_width = 2 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1d42630..4a4bc3f 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -12,6 +12,7 @@ assignees: '' **To Reproduce** + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' @@ -24,6 +25,7 @@ assignees: '' **Crash reports or relevant logs** + ```log log here ``` diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 84f9cb0..a129e0c 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -1,80 +1,80 @@ name: Build documentation on: - push: - branches: ["main"] - workflow_dispatch: + push: + branches: [ "main" ] + workflow_dispatch: permissions: - id-token: write - pages: write + id-token: write + pages: write env: - INSTANCE: 'Writerside/md' - ARTIFACT: 'webHelpMD2-all.zip' - DOCKER_VERSION: '241.18775' + INSTANCE: 'Writerside/md' + ARTIFACT: 'webHelpMD2-all.zip' + DOCKER_VERSION: '241.18775' jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 + build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 - - name: Build docs using Writerside Docker builder - uses: JetBrains/writerside-github-action@v4 - with: - instance: ${{ env.INSTANCE }} - artifact: ${{ env.ARTIFACT }} - docker-version: ${{ env.DOCKER_VERSION }} + - name: Build docs using Writerside Docker builder + uses: JetBrains/writerside-github-action@v4 + with: + instance: ${{ env.INSTANCE }} + artifact: ${{ env.ARTIFACT }} + docker-version: ${{ env.DOCKER_VERSION }} - - name: Save artifact with build results - uses: actions/upload-artifact@v4 - with: - name: docs - path: | - artifacts/${{ env.ARTIFACT }} - artifacts/report.json - retention-days: 7 - test: - needs: build - runs-on: ubuntu-latest - steps: - - name: Download artifacts - uses: actions/download-artifact@v4 - with: - name: docs - path: artifacts + - name: Save artifact with build results + uses: actions/upload-artifact@v4 + with: + name: docs + path: | + artifacts/${{ env.ARTIFACT }} + artifacts/report.json + retention-days: 7 + test: + needs: build + runs-on: ubuntu-latest + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: docs + path: artifacts - - name: Test documentation - uses: JetBrains/writerside-checker-action@v1 - with: - instance: ${{ env.INSTANCE }} - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - needs: [build, test] - runs-on: ubuntu-latest - steps: - - name: Download artifacts - uses: actions/download-artifact@v4 - with: - name: docs + - name: Test documentation + uses: JetBrains/writerside-checker-action@v1 + with: + instance: ${{ env.INSTANCE }} + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + needs: [ build, test ] + runs-on: ubuntu-latest + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: docs - - name: Unzip artifact - run: unzip -O UTF-8 -qq '${{ env.ARTIFACT }}' -d dir + - name: Unzip artifact + run: unzip -O UTF-8 -qq '${{ env.ARTIFACT }}' -d dir - - name: Setup Pages - uses: actions/configure-pages@v4 + - name: Setup Pages + uses: actions/configure-pages@v4 - - name: Package and upload Pages artifact - uses: actions/upload-pages-artifact@v3 - with: - path: dir + - name: Package and upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: dir - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/README.md b/README.md index 475b263..1e05f15 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,11 @@ _Almost_ everything in the mod can configured. ## Configuration -To change most values, you can play with the gamerules added by the mod with the +To change most values, you can play with the gamerules added by the mod with the `/gamerule` command. Every gamerule introduced by the mod starts with `molehunt:`. -To dive deeper into the configuration, [an online wiki is available](https://www.anhgelus.world/molehunt/configuration.html). +To dive deeper into the +configuration, [an online wiki is available](https://www.anhgelus.world/molehunt/configuration.html). ## Technologies diff --git a/Writerside/cfg/buildprofiles.xml b/Writerside/cfg/buildprofiles.xml index 8ddb9c7..1353666 100644 --- a/Writerside/cfg/buildprofiles.xml +++ b/Writerside/cfg/buildprofiles.xml @@ -1,13 +1,13 @@ - + - - - - true - - + + + + true + + diff --git a/Writerside/topics/config-file.md b/Writerside/topics/config-file.md index c70e347..56d4d94 100644 --- a/Writerside/topics/config-file.md +++ b/Writerside/topics/config-file.md @@ -1,6 +1,6 @@ # Config file -On top of the gamerules, you can edit a config file, named `molehunt.properties`. +On top of the gamerules, you can edit a config file, named `molehunt.properties`. This file is automatically generated when starting a server with the mod installed. This file will set the default settings when creating a new world, but that's it. @@ -11,8 +11,7 @@ different worlds. > If you only want to change the settings on a single world, or don't want to change > a lot, I would suggest [playing with the gamerules](gamerules.md) rather than the config > file, as it is easier and directly in-game -{style=note} - +> {style=note} ## Editing the config file @@ -24,10 +23,10 @@ similar names, even though different). To know what each setting does, you can check [the gamerules documention](gamerules.md). The config syntax is very simple: -- `name_of_the_setting = value` to set a setting to a `value`. Only one setting - can be set on a single line -- A line starting with a `#` is a comment, and will not be counted be the mod. +- `name_of_the_setting = value` to set a setting to a `value`. Only one setting + can be set on a single line +- A line starting with a `#` is a comment, and will not be counted be the mod. ## Troubleshooting the config file @@ -42,6 +41,7 @@ and that the file's name is `molehunt.properties`. ### Check that you use the config file's setting names, and not the gamerule names For example, to change the game duration in the config file: + ```yaml # Do this: game_duration = 30 @@ -58,6 +58,7 @@ You can see the list of all config file setting in [the default configuration fi A comment line starts with a `#`, not with `//` nor with anything else. Also, you can only set one variable on one line. For exemple, this is incorrect: + ```yaml # This is not a valid config file first_setting = 1 second_setting = 2 @@ -71,6 +72,7 @@ another_setting = A boolean value (one that can either be "on or off") can be set to `true` or `false`, nothing else. + ```yaml # Good my_boolean = true @@ -79,7 +81,7 @@ my_boolean = true my_boolean = false ``` -Every numerical value should be integers: there are no decimal values in this mod. +Every numerical value should be integers: there are no decimal values in this mod. And you should not put the unit after the value (do not put `50 blocks`, but only `50`). > If you have checked everything, and there's still a problem, don't hesitate to @@ -87,11 +89,11 @@ And you should not put the unit after the value (do not put `50 blocks`, but onl ## Default configuration -Here is the default configuration that is automatically generated. Every setting +Here is the default configuration that is automatically generated. Every setting is listed below. -To regenerate the default configuration, you can rename, move or delete your -current config file, and then run the server with the mod installed. +To regenerate the default configuration, you can rename, move or delete your +current config file, and then run the server with the mod installed. ```yaml # Molehunt mod configuration file diff --git a/Writerside/topics/configuration.md b/Writerside/topics/configuration.md index a258e4f..456b982 100644 --- a/Writerside/topics/configuration.md +++ b/Writerside/topics/configuration.md @@ -1,7 +1,7 @@ # Configuration _Almost_ everything in the mod can be modified. You can change the mod's behavior by -changing custom gamerules or editing a config file. +changing custom gamerules or editing a config file. To change the mod's text and default skin, you can use a custom resource pack and set it to be the default resource pack on your server. diff --git a/Writerside/topics/gamerules.md b/Writerside/topics/gamerules.md index 54d9290..939388e 100644 --- a/Writerside/topics/gamerules.md +++ b/Writerside/topics/gamerules.md @@ -1,11 +1,11 @@ # Gamerules -To change the mods behavior, you can change your world's gamerules. Every gamerule added +To change the mods behavior, you can change your world's gamerules. Every gamerule added by this mod starts with the prefix `molehunt:`. > If plan on making multiple worlds, and don't want to set the gamerules each time, > [edit the configuration file](config-file.md). -{style=tip} +> {style=tip} Here's a list of all the Molehunt gamerules. @@ -15,16 +15,16 @@ Here's a list of all the Molehunt gamerules. - `gameDurationMinutes`: sets the game's duration in minutes (default: `90 minutes`). - `molePercentage`: sets the mole percentage among all players (default: `25 %`). -- `moleCount`: the absolute mole amount. Overwrites `molePercentage`. To disable - this setting, set it to `-1` (default: `-1`). +- `moleCount`: the absolute mole amount. Overwrites `molePercentage`. To disable + this setting, set it to `-1` (default: `-1`). - `foodOnStart`: give food on start ### Client-side settings > These gamerules affect client-side features, but are still applied to all players. -> +> > Also, they will only be effective when the game starts. -{style=note} +> {style=note} - `showNametags`: players' nametags are shown (default: `false`). - `showSkins`: players' custom skin is visible. Setting this to false will @@ -40,6 +40,7 @@ Here's a list of all the Molehunt gamerules. - `initialWorldSize`: the world size when starting the game (default: `600 blocks`). - `finalWorldSize`: the target world size on the end of the game (default: `100 blocks`). -- `borderMovingStartingTimeOffsetMinutes`: the time before the world borders start to move in minutes (default: `10 minutes`). +- `borderMovingStartingTimeOffsetMinutes`: the time before the world borders start to move in minutes (default: + `10 minutes`). > Setting this to a value greater than `gameDuration` will make the borders never move. {style=note} diff --git a/Writerside/topics/introduction.md b/Writerside/topics/introduction.md index e2ef02c..cb32630 100644 --- a/Writerside/topics/introduction.md +++ b/Writerside/topics/introduction.md @@ -2,7 +2,8 @@ [Molehunt](https://modrinth.com/mod/molehunt-mod) is a mod creating the Molehunt game in Minecraft. You can watch this [video](https://www.youtube.com/watch?v=NJBjQ8T_1cc) to understand what it is. -If you are speaking French, I made this [30 seconds video](https://cdn.anhgelus.world/molehunt-presentation.mp4) explaining the concept. +If you are speaking French, I made this [30 seconds video](https://cdn.anhgelus.world/molehunt-presentation.mp4) +explaining the concept. ## Installation @@ -11,10 +12,10 @@ Download the mod for your version. The mod requires [Fabric-API](https://modrinth.com/mod/fabric-api) to works. [Simple Voice Chat](https://modrinth.com/plugin/simple-voice-chat) is highly recommended. -> If you use Simple Voice Chat, make sure to disable private groups, +> If you use Simple Voice Chat, make sure to disable private groups, > as they would ruin the immersion. -{style=tip} +> {style=tip} -The mod has to be installed on the server *and* on every client. The mod is required -to be installed on clients for some client-side features (such as hiding nametags +The mod has to be installed on the server *and* on every client. The mod is required +to be installed on clients for some client-side features (such as hiding nametags or changing skins). diff --git a/Writerside/topics/resource-pack.md b/Writerside/topics/resource-pack.md index b3bbf86..9b83906 100644 --- a/Writerside/topics/resource-pack.md +++ b/Writerside/topics/resource-pack.md @@ -3,14 +3,13 @@ If you want to customize visual elements of the mod, you can create your own custom resource pack. -Doing so will enable you to change or translate every text line used by +Doing so will enable you to change or translate every text line used by the mod, and also change to default skin that is applied to all players (if the [gamerule `showSkins`](gamerules.md#client-side-settings) is set to true). > After creating your resource pack, you can either force its use by setting it as > the server's resource pack, or make it optional (it's purely visuals anyway!) -{style=tip} - +> {style=tip} ## First steps @@ -19,6 +18,7 @@ inside of this folder, create a file named `pack.mcmeta`. This file is very impo the game that it is indeed a resource pack. Now, edit the `pack.mcmeta` file with your favorite text editor, and write the following: + ```json { "pack": { @@ -28,15 +28,16 @@ Now, edit the `pack.mcmeta` file with your favorite text editor, and write the f } ``` -> Note that the `pack_format` used here (34) corresponds to minecraft version 1.21.x. If you -> are making the resource pack for another version, you can check which pack format to use +> Note that the `pack_format` used here (34) corresponds to minecraft version 1.21.x. If you +> are making the resource pack for another version, you can check which pack format to use > [on the wiki](https://minecraft.wiki/w/Pack_format). -{style=note} +> {style=note} -You can now close the `pack.mcmeta` file. Now, inside your resource pack's main folder, -create a folder named `assets`, and inside it make another folder name `molehunt`. +You can now close the `pack.mcmeta` file. Now, inside your resource pack's main folder, +create a folder named `assets`, and inside it make another folder name `molehunt`. You file tree you look like that: + ``` 📁 MyAwesomeResourcePack ├── 📄 pack.mcmeta @@ -46,18 +47,18 @@ You file tree you look like that: > If you want, you can also add an icon to your resource pack: just add a png file named > `pack.png` in your resource pack's main folder. -{style=tip} - +> {style=tip} ## Adding a custom skin To add a custom skin, first you need to make one. You can either use -your own skin, or make a new one using a minecraft skin editor (there are +your own skin, or make a new one using a minecraft skin editor (there are a lot online). Then grab your skin file (make sure it's a `.png` file!), name it `skin.png` -and put it inside a `textures` folder, inside the `molehunt` folder. It should +and put it inside a `textures` folder, inside the `molehunt` folder. It should look like that: + ``` ... 📁 assets @@ -68,27 +69,27 @@ look like that: Now everyone in the game will be wearing your custom skin! - ## Changing the mod's text Finally, if the mod's text doesn't suit you, or if you want to translate -it to another language, you can! +it to another language, you can! > Note that french is already supported by default, so no need to translate > to it. -{style=tip} +> {style=tip} First, create a new folder in the `molehunt` folder named `lang`, then create a `en_us.json` file. > If you want to target another language, name the file according to your language > and region. For example: `fr_fr.json` for French in France. -{style=note} +> {style=note} Now copy the content of the [default `en_us.json` file](#default-en-us-json-language-file) in you language file, and start editing the lines you want to change! Finally, your file structure should look like that: + ``` ... 📁 assets @@ -98,15 +99,16 @@ Finally, your file structure should look like that: └── 📄 en_pt.json └── etc. ``` + (You can have only one, or multiple language files, it doesn't matter) -[Minecraft formatting codes](https://minecraft.wiki/w/Formatting_codes) are +[Minecraft formatting codes](https://minecraft.wiki/w/Formatting_codes) are supported in `titles` and `subtitles`. - ## Final file tree, and installing your resource pack If you followed every step of this tutorial, the final resource pack should look like this: + ``` 📁 MyAwesomeResourcePack ├── 📄 pack.mcmeta @@ -121,21 +123,20 @@ If you followed every step of this tutorial, the final resource pack should look └── etc. ``` -To install it on your client, simply put your awesome resource pack in the `resourcepacks` folder +To install it on your client, simply put your awesome resource pack in the `resourcepacks` folder of [your `.minecraft` folder](https://minecraft.wiki/w/.minecraft). If you want, you can zip it to make sharing it easier, but it is not required. - ## Default `en_us.json` language file Here's the default `en_us.json` file. You can use it as a template to customize the mod's text lines. -> The weird `§` and the character after it corresponds to a minecraft -> formatting code. It can change the text's color and format. You can -> learn more [on the wiki](https://minecraft.wiki/w/Formatting_codes). -{style=tip} +> The weird `§` and the character after it corresponds to a minecraft +> formatting code. It can change the text's color and format. You can +> learn more [on the wiki](https://minecraft.wiki/w/Formatting_codes). +> {style=tip} ```json { diff --git a/Writerside/topics/usage.md b/Writerside/topics/usage.md index 46bc5fb..6cb1c64 100644 --- a/Writerside/topics/usage.md +++ b/Writerside/topics/usage.md @@ -5,23 +5,24 @@ To start a game, execute `/molehunt start` (you must be OP). The game ends automatically if one of these two condition is met: + - Every alive player is a mole. - The timer has run out. The game does not automatically end when every mole is dead to allow for -some funny moments. But if needed, you can stop the game early by using +some funny moments. But if needed, you can stop the game early by using `/molehunt stop` (you must be OP). - ## Player commands The mod also provide a few commands for every player. If you forgot your role during the game, you can use `/molehunt role` This command will also provide you with some additional information : + - For survivors, it will give the mole count; - For moles and spectators, it will give the list of all moles. To some people, the timer above you hotbar could be annoying. To hide it, -use `/molehunt timer hide`. If you want to see it again, use +use `/molehunt timer hide`. If you want to see it again, use `/molehunt timer show`. diff --git a/build.gradle b/build.gradle index d34a196..baf537b 100644 --- a/build.gradle +++ b/build.gradle @@ -1,89 +1,89 @@ plugins { - id 'fabric-loom' version '1.15-SNAPSHOT' - id 'maven-publish' + id 'fabric-loom' version '1.15-SNAPSHOT' + id 'maven-publish' } version = project.mod_version group = project.maven_group base { - archivesName = project.archives_base_name + archivesName = project.archives_base_name } loom { - splitEnvironmentSourceSets() + splitEnvironmentSourceSets() - mods { - "molehunt" { - sourceSet sourceSets.main - sourceSet sourceSets.client - } - } + mods { + "molehunt" { + sourceSet sourceSets.main + sourceSet sourceSets.client + } + } } repositories { - // Add repositories to retrieve artifacts from in here. - // You should only use this when depending on other mods because - // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. - // See https://docs.gradle.org/current/userguide/declaring_repositories.html - // for more information about repositories. + // Add repositories to retrieve artifacts from in here. + // You should only use this when depending on other mods because + // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. + // See https://docs.gradle.org/current/userguide/declaring_repositories.html + // for more information about repositories. } dependencies { - // To change the versions see the gradle.properties file - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + // To change the versions see the gradle.properties file + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - // Fabric API. This is technically optional, but you probably want it anyway. - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + // Fabric API. This is technically optional, but you probably want it anyway. + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" } processResources { - inputs.property "version", project.version - inputs.property "minecraft_version", project.minecraft_version - inputs.property "loader_version", project.loader_version - filteringCharset "UTF-8" + inputs.property "version", project.version + inputs.property "minecraft_version", project.minecraft_version + inputs.property "loader_version", project.loader_version + filteringCharset "UTF-8" - filesMatching("fabric.mod.json") { - expand "version": project.version, - "minecraft_version": project.minecraft_version, - "loader_version": project.loader_version - } + filesMatching("fabric.mod.json") { + expand "version": project.version, + "minecraft_version": project.minecraft_version, + "loader_version": project.loader_version + } } tasks.withType(JavaCompile).configureEach { - it.options.release = 21 - it.options.encoding = "UTF-8" + it.options.release = 21 + it.options.encoding = "UTF-8" } java { - withSourcesJar() + withSourcesJar() - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } jar { - from("LICENSE") { - rename { "${it}_${inputs.properties.archivesName}"} - } + from("LICENSE") { + rename { "${it}_${inputs.properties.archivesName}" } + } } // configure the maven publication publishing { - publications { - create("mavenJava", MavenPublication) { - artifactId = project.archives_base_name - from components.java - } - } + publications { + create("mavenJava", MavenPublication) { + artifactId = project.archives_base_name + from components.java + } + } - // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. - repositories { - // Add repositories to publish to here. - // Notice: This block does NOT have the same function as the block in the top level. - // The repositories here will be used for publishing your artifact, not for - // retrieving dependencies. - } + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + repositories { + // Add repositories to publish to here. + // Notice: This block does NOT have the same function as the block in the top level. + // The repositories here will be used for publishing your artifact, not for + // retrieving dependencies. + } } diff --git a/settings.gradle b/settings.gradle index f91a4fe..027b233 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,9 +1,9 @@ pluginManagement { - repositories { - maven { - name = 'Fabric' - url = 'https://maven.fabricmc.net/' - } - gradlePluginPortal() - } + repositories { + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + gradlePluginPortal() + } } diff --git a/src/client/java/world/anhgelus/molehunt/client/MolehuntClient.java b/src/client/java/world/anhgelus/molehunt/client/MolehuntClient.java index 03198ee..f495d40 100644 --- a/src/client/java/world/anhgelus/molehunt/client/MolehuntClient.java +++ b/src/client/java/world/anhgelus/molehunt/client/MolehuntClient.java @@ -9,49 +9,49 @@ import world.anhgelus.molehunt.game.GamePayload; public class MolehuntClient implements ClientModInitializer { - private static boolean SHOW_SKINS = false; - private static boolean SHOW_NAMETAGS = false; - private static boolean SHOW_TAB = false; - - private static boolean GAME_STARTED = false; - - @Override - public void onInitializeClient() { - ClientPlayNetworking.registerGlobalReceiver(ConfigPayload.ID, (payload, context) -> context.client().execute(() -> { - SHOW_SKINS = payload.showSkins(); - SHOW_NAMETAGS = payload.showNametags(); - SHOW_TAB = payload.showTab(); - })); - ClientPlayNetworking.registerGlobalReceiver(GamePayload.ID, (payload, context) -> context.client().execute(() -> GAME_STARTED = payload.gameLaunched())); - - // Needed because else `client.options` is null - ClientLifecycleEvents.CLIENT_STARTED.register(client -> { - var options = client.options; - - options.setPlayerModelPart(PlayerModelPart.CAPE, true); - options.setPlayerModelPart(PlayerModelPart.HAT, true); - options.setPlayerModelPart(PlayerModelPart.JACKET, true); - options.setPlayerModelPart(PlayerModelPart.LEFT_SLEEVE, true); - options.setPlayerModelPart(PlayerModelPart.RIGHT_SLEEVE, true); - options.setPlayerModelPart(PlayerModelPart.LEFT_PANTS_LEG, true); - options.setPlayerModelPart(PlayerModelPart.RIGHT_PANTS_LEG, true); - }); - - } - - public static boolean showSkins() { - return SHOW_SKINS; - } - - public static boolean showNameTags() { - return SHOW_NAMETAGS; - } - - public static boolean showTab() { - return SHOW_TAB; - } - - public static boolean gameStarted() { - return GAME_STARTED; - } + private static boolean SHOW_SKINS = false; + private static boolean SHOW_NAMETAGS = false; + private static boolean SHOW_TAB = false; + + private static boolean GAME_STARTED = false; + + public static boolean showSkins() { + return SHOW_SKINS; + } + + public static boolean showNameTags() { + return SHOW_NAMETAGS; + } + + public static boolean showTab() { + return SHOW_TAB; + } + + public static boolean gameStarted() { + return GAME_STARTED; + } + + @Override + public void onInitializeClient() { + ClientPlayNetworking.registerGlobalReceiver(ConfigPayload.ID, (payload, context) -> context.client().execute(() -> { + SHOW_SKINS = payload.showSkins(); + SHOW_NAMETAGS = payload.showNametags(); + SHOW_TAB = payload.showTab(); + })); + ClientPlayNetworking.registerGlobalReceiver(GamePayload.ID, (payload, context) -> context.client().execute(() -> GAME_STARTED = payload.gameLaunched())); + + // Needed because else `client.options` is null + ClientLifecycleEvents.CLIENT_STARTED.register(client -> { + var options = client.options; + + options.setPlayerModelPart(PlayerModelPart.CAPE, true); + options.setPlayerModelPart(PlayerModelPart.HAT, true); + options.setPlayerModelPart(PlayerModelPart.JACKET, true); + options.setPlayerModelPart(PlayerModelPart.LEFT_SLEEVE, true); + options.setPlayerModelPart(PlayerModelPart.RIGHT_SLEEVE, true); + options.setPlayerModelPart(PlayerModelPart.LEFT_PANTS_LEG, true); + options.setPlayerModelPart(PlayerModelPart.RIGHT_PANTS_LEG, true); + }); + + } } diff --git a/src/client/java/world/anhgelus/molehunt/client/mixin/NoCustomizableSkinOverlay.java b/src/client/java/world/anhgelus/molehunt/client/mixin/NoCustomizableSkinOverlay.java index c2c0ab0..f253cd8 100644 --- a/src/client/java/world/anhgelus/molehunt/client/mixin/NoCustomizableSkinOverlay.java +++ b/src/client/java/world/anhgelus/molehunt/client/mixin/NoCustomizableSkinOverlay.java @@ -3,7 +3,6 @@ package world.anhgelus.molehunt.client.mixin; import net.minecraft.client.option.GameOptions; import net.minecraft.entity.player.PlayerModelPart; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -11,14 +10,9 @@ import world.anhgelus.molehunt.client.MolehuntClient; @Mixin(GameOptions.class) public abstract class NoCustomizableSkinOverlay { - @Shadow - private void setPlayerModelPart(PlayerModelPart part, boolean enabled) {} - - @Inject(at = @At("HEAD"), method = "setPlayerModelPart", cancellable = true) - public void togglePlayerModelPart(PlayerModelPart part, boolean enabled, CallbackInfo ci) { - if (MolehuntClient.showSkins()) return; - setPlayerModelPart(part, true); - ((GameOptions) (Object) this).sendClientSettings(); - ci.cancel(); - } + @Inject(at = @At("HEAD"), method = "setPlayerModelPart", cancellable = true) + public void togglePlayerModelPart(PlayerModelPart part, boolean enabled, CallbackInfo ci) { + if (MolehuntClient.showSkins()) return; + ci.cancel(); + } } diff --git a/src/client/java/world/anhgelus/molehunt/client/mixin/NoNametags.java b/src/client/java/world/anhgelus/molehunt/client/mixin/NoNametags.java index 555fb00..cea817d 100644 --- a/src/client/java/world/anhgelus/molehunt/client/mixin/NoNametags.java +++ b/src/client/java/world/anhgelus/molehunt/client/mixin/NoNametags.java @@ -7,7 +7,6 @@ import net.minecraft.client.render.state.CameraRenderState; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; -import net.minecraft.entity.player.PlayerEntity; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -16,9 +15,10 @@ import world.anhgelus.molehunt.client.MolehuntClient; @Mixin(EntityRenderer.class) public class NoNametags { - @Inject(at = @At("HEAD"), method = "render", cancellable = true) - private void renderLabelOrNot(S state, MatrixStack matrices, OrderedRenderCommandQueue queue, CameraRenderState cameraState, CallbackInfo ci) { - if (EntityType.PLAYER != state.entityType || MolehuntClient.showNameTags() || !MolehuntClient.gameStarted()) return; - ci.cancel(); - } + @Inject(at = @At("HEAD"), method = "render", cancellable = true) + private void renderLabelOrNot(S state, MatrixStack matrices, OrderedRenderCommandQueue queue, CameraRenderState cameraState, CallbackInfo ci) { + if (EntityType.PLAYER != state.entityType || MolehuntClient.showNameTags() || !MolehuntClient.gameStarted()) + return; + ci.cancel(); + } } \ No newline at end of file diff --git a/src/client/java/world/anhgelus/molehunt/client/mixin/NoPlayerListHud.java b/src/client/java/world/anhgelus/molehunt/client/mixin/NoPlayerListHud.java index 4473b12..d889f06 100644 --- a/src/client/java/world/anhgelus/molehunt/client/mixin/NoPlayerListHud.java +++ b/src/client/java/world/anhgelus/molehunt/client/mixin/NoPlayerListHud.java @@ -9,9 +9,9 @@ import world.anhgelus.molehunt.client.MolehuntClient; @Mixin(PlayerListHud.class) public class NoPlayerListHud { - @Inject(at = @At("HEAD"), method = "render", cancellable = true) - public void render(CallbackInfo ci) { - if (MolehuntClient.showTab() || !MolehuntClient.gameStarted()) return; - ci.cancel(); - } + @Inject(at = @At("HEAD"), method = "render", cancellable = true) + public void render(CallbackInfo ci) { + if (MolehuntClient.showTab() || !MolehuntClient.gameStarted()) return; + ci.cancel(); + } } diff --git a/src/client/java/world/anhgelus/molehunt/client/mixin/NoSkin.java b/src/client/java/world/anhgelus/molehunt/client/mixin/NoSkin.java index b6b67cc..945ef9b 100644 --- a/src/client/java/world/anhgelus/molehunt/client/mixin/NoSkin.java +++ b/src/client/java/world/anhgelus/molehunt/client/mixin/NoSkin.java @@ -14,14 +14,14 @@ import world.anhgelus.molehunt.client.MolehuntClient; @Mixin(AbstractClientPlayerEntity.class) public class NoSkin { - @Inject(at = @At("HEAD"), method = "getSkin", cancellable = true) - public void getSkin(CallbackInfoReturnable cir) { - if (MolehuntClient.showSkins() || !MolehuntClient.gameStarted()) return; - cir.setReturnValue(SkinTextures.create( - new AssetInfo.TextureAssetInfo(Identifier.of(Molehunt.MOD_ID, "skin")), - null, - null, - PlayerSkinType.WIDE - )); - } + @Inject(at = @At("HEAD"), method = "getSkin", cancellable = true) + public void getSkin(CallbackInfoReturnable cir) { + if (MolehuntClient.showSkins() || !MolehuntClient.gameStarted()) return; + cir.setReturnValue(SkinTextures.create( + new AssetInfo.TextureAssetInfo(Identifier.of(Molehunt.MOD_ID, "skin")), + null, + null, + PlayerSkinType.WIDE + )); + } } diff --git a/src/client/resources/assets/molehunt/lang/en_us.json b/src/client/resources/assets/molehunt/lang/en_us.json index 267230a..5bbd6f5 100644 --- a/src/client/resources/assets/molehunt/lang/en_us.json +++ b/src/client/resources/assets/molehunt/lang/en_us.json @@ -1,28 +1,28 @@ { - "commands.molehunt.error.game_not_started": "The Molehunt game has not been started yet.", - "commands.molehunt.timer.show": "Showing Molehunt timer.", - "commands.molehunt.timer.hide": "Hiding Molehunt timer.", - "commands.molehunt.role.mole": "§cYou are a Mole.\nKill all the survivors before the timer runs out.", - "commands.molehunt.role.mole.list": "§eThe moles are: %s", - "commands.molehunt.role.survivor": "§aYou are not the Mole. \nSurvive until the timer runs out, and try to discover who's the Mole.", - "commands.molehunt.role.survivor.mole_count": "§eThere are %d §emoles among you.", - "commands.molehunt.stop.success": "The Molehunt game has been stopped.", - "molehunt.game.end.suspense.title": "§eAnd the winners are...", - "molehunt.game.end.winners.moles.title": "§cThe Moles!", - "molehunt.game.end.winners.survivors.title": "§aNot the Moles!", - "molehunt.game.end.winners.subtitle": "§6The Moles were %s", - "molehunt.game.start.suspense": "§eYou are...", - "molehunt.game.start.mole.title": "§cThe Mole!", - "molehunt.game.start.mole.subtitle": "§eGet the list of moles with §6/molehunt role§e.", - "molehunt.game.start.survivor.title": "§aNot the Mole!", - "molehunt.game.start.survivor.subtitle": "§eTry to survive and find out who's the mole!", - "gamerule.molehunt:gameDuration": "Molehunt: Duration of a game", - "gamerule.molehunt:molePercentage": "Molehunt: Percentage of Mole", - "gamerule.molehunt:moleCount": "Molehunt: Number of Mole", - "gamerule.molehunt:showNametags": "Molehunt: Show players' nametag", - "gamerule.molehunt:showTab": "Molehunt: Enable the tab", - "gamerule.molehunt:showSkins": "Molehunt: Show players' skin", - "gamerule.molehunt:initialWorldSize": "Molehunt: Initial world size", - "gamerule.molehunt:finalWorldSize": "Molehunt: Final world size", - "gamerule.molehunt:borderMovingStartingTimeOffsetMinutes": "Molehunt: Time before moving the borders" + "commands.molehunt.error.game_not_started": "The Molehunt game has not been started yet.", + "commands.molehunt.timer.show": "Showing Molehunt timer.", + "commands.molehunt.timer.hide": "Hiding Molehunt timer.", + "commands.molehunt.role.mole": "§cYou are a Mole.\nKill all the survivors before the timer runs out.", + "commands.molehunt.role.mole.list": "§eThe moles are: %s", + "commands.molehunt.role.survivor": "§aYou are not the Mole. \nSurvive until the timer runs out, and try to discover who's the Mole.", + "commands.molehunt.role.survivor.mole_count": "§eThere are %d §emoles among you.", + "commands.molehunt.stop.success": "The Molehunt game has been stopped.", + "molehunt.game.end.suspense.title": "§eAnd the winners are...", + "molehunt.game.end.winners.moles.title": "§cThe Moles!", + "molehunt.game.end.winners.survivors.title": "§aNot the Moles!", + "molehunt.game.end.winners.subtitle": "§6The Moles were %s", + "molehunt.game.start.suspense": "§eYou are...", + "molehunt.game.start.mole.title": "§cThe Mole!", + "molehunt.game.start.mole.subtitle": "§eGet the list of moles with §6/molehunt role§e.", + "molehunt.game.start.survivor.title": "§aNot the Mole!", + "molehunt.game.start.survivor.subtitle": "§eTry to survive and find out who's the mole!", + "gamerule.molehunt:gameDuration": "Molehunt: Duration of a game", + "gamerule.molehunt:molePercentage": "Molehunt: Percentage of Mole", + "gamerule.molehunt:moleCount": "Molehunt: Number of Mole", + "gamerule.molehunt:showNametags": "Molehunt: Show players' nametag", + "gamerule.molehunt:showTab": "Molehunt: Enable the tab", + "gamerule.molehunt:showSkins": "Molehunt: Show players' skin", + "gamerule.molehunt:initialWorldSize": "Molehunt: Initial world size", + "gamerule.molehunt:finalWorldSize": "Molehunt: Final world size", + "gamerule.molehunt:borderMovingStartingTimeOffsetMinutes": "Molehunt: Time before moving the borders" } \ No newline at end of file diff --git a/src/client/resources/assets/molehunt/lang/fr_fr.json b/src/client/resources/assets/molehunt/lang/fr_fr.json index 62c10ca..cc5133d 100644 --- a/src/client/resources/assets/molehunt/lang/fr_fr.json +++ b/src/client/resources/assets/molehunt/lang/fr_fr.json @@ -1,28 +1,28 @@ { - "commands.molehunt.error.game_not_started": "La partie de Molehunt n'a pas encore commencé.", - "commands.molehunt.timer.show": "Le timer est maintenant affiché.", - "commands.molehunt.timer.hide": "Le timer est maintenant caché.", - "commands.molehunt.role.mole": "§cVous êtes une taupe.\nTuez tous les survivants avant la fin de la partie..", - "commands.molehunt.role.mole.list": "§eLes taupes sont : %s", - "commands.molehunt.role.survivor": "§aVous n'êtes pas la taupe. \nSurvivez jusqu'à la fin, et découvrez qui sont les moles.", - "commands.molehunt.role.survivor.mole_count": "§eIl y a %d §etaupes parmi vous.", - "commands.molehunt.stop.success": "La partie de Molehunt a été arrêtée.", - "molehunt.game.end.suspense.title": "§eEt les gagnants sont...", - "molehunt.game.end.winners.moles.title": "§cLes Taupes !", - "molehunt.game.end.winners.survivors.title": "§aPas les Taupes !", - "molehunt.game.end.winners.subtitle": "§Les Taupes sont", - "molehunt.game.start.suspense": "§eVous êtes...", - "molehunt.game.start.mole.title": "§cLa Taupe !", - "molehunt.game.start.mole.subtitle": "§eRécupérer la liste des taupes avec §6/molehunt moles", - "molehunt.game.start.survivor.title": "§aPas la taupe!", - "molehunt.game.start.survivor.subtitle": "§eEssaye de survivre et de trouver qui est la taupe !", - "gamerule.molehunt:gameDuration": "Molehunt : Durée d'une partie", - "gamerule.molehunt:molePercentage": "Molehunt : Pourcentage de Taupes", - "gamerule.molehunt:moleCount": "Molehunt : Nombre de Taupes", - "gamerule.molehunt:showNametags": "Molehunt : Affiche les nametags des joueurs", - "gamerule.molehunt:showTab": "Molehunt : Active la liste des joueurs", - "gamerule.molehunt:showSkins": "Molehunt : Affiche les skins des joueurs", - "gamerule.molehunt:initialWorldSize": "Molehunt : Taille initiale du monde", - "gamerule.molehunt:finalWorldSize": "Molehunt : Taille finale du monde", - "gamerule.molehunt:borderMovingStartingTimeOffsetMinutes": "Molehunt : Temps avant de bouger les bordures du monde" + "commands.molehunt.error.game_not_started": "La partie de Molehunt n'a pas encore commencé.", + "commands.molehunt.timer.show": "Le timer est maintenant affiché.", + "commands.molehunt.timer.hide": "Le timer est maintenant caché.", + "commands.molehunt.role.mole": "§cVous êtes une taupe.\nTuez tous les survivants avant la fin de la partie..", + "commands.molehunt.role.mole.list": "§eLes taupes sont : %s", + "commands.molehunt.role.survivor": "§aVous n'êtes pas la taupe. \nSurvivez jusqu'à la fin, et découvrez qui sont les moles.", + "commands.molehunt.role.survivor.mole_count": "§eIl y a %d §etaupes parmi vous.", + "commands.molehunt.stop.success": "La partie de Molehunt a été arrêtée.", + "molehunt.game.end.suspense.title": "§eEt les gagnants sont...", + "molehunt.game.end.winners.moles.title": "§cLes Taupes !", + "molehunt.game.end.winners.survivors.title": "§aPas les Taupes !", + "molehunt.game.end.winners.subtitle": "§Les Taupes sont", + "molehunt.game.start.suspense": "§eVous êtes...", + "molehunt.game.start.mole.title": "§cLa Taupe !", + "molehunt.game.start.mole.subtitle": "§eRécupérer la liste des taupes avec §6/molehunt moles", + "molehunt.game.start.survivor.title": "§aPas la taupe!", + "molehunt.game.start.survivor.subtitle": "§eEssaye de survivre et de trouver qui est la taupe !", + "gamerule.molehunt:gameDuration": "Molehunt : Durée d'une partie", + "gamerule.molehunt:molePercentage": "Molehunt : Pourcentage de Taupes", + "gamerule.molehunt:moleCount": "Molehunt : Nombre de Taupes", + "gamerule.molehunt:showNametags": "Molehunt : Affiche les nametags des joueurs", + "gamerule.molehunt:showTab": "Molehunt : Active la liste des joueurs", + "gamerule.molehunt:showSkins": "Molehunt : Affiche les skins des joueurs", + "gamerule.molehunt:initialWorldSize": "Molehunt : Taille initiale du monde", + "gamerule.molehunt:finalWorldSize": "Molehunt : Taille finale du monde", + "gamerule.molehunt:borderMovingStartingTimeOffsetMinutes": "Molehunt : Temps avant de bouger les bordures du monde" } \ No newline at end of file diff --git a/src/client/resources/molehunt.client.mixins.json b/src/client/resources/molehunt.client.mixins.json index 7b9c0f4..b966891 100644 --- a/src/client/resources/molehunt.client.mixins.json +++ b/src/client/resources/molehunt.client.mixins.json @@ -1,15 +1,15 @@ { - "required": true, - "minVersion": "0.8", - "package": "world.anhgelus.molehunt.client.mixin", - "compatibilityLevel": "JAVA_21", - "client": [ - "NoCustomizableSkinOverlay", - "NoNametags", - "NoPlayerListHud", - "NoSkin" - ], - "injectors": { - "defaultRequire": 1 - } + "required": true, + "minVersion": "0.8", + "package": "world.anhgelus.molehunt.client.mixin", + "compatibilityLevel": "JAVA_21", + "client": [ + "NoCustomizableSkinOverlay", + "NoNametags", + "NoPlayerListHud", + "NoSkin" + ], + "injectors": { + "defaultRequire": 1 + } } diff --git a/src/main/java/world/anhgelus/molehunt/Molehunt.java b/src/main/java/world/anhgelus/molehunt/Molehunt.java index d5df320..6486700 100644 --- a/src/main/java/world/anhgelus/molehunt/Molehunt.java +++ b/src/main/java/world/anhgelus/molehunt/Molehunt.java @@ -40,199 +40,186 @@ import static net.minecraft.server.command.CommandManager.literal; public class Molehunt implements ModInitializer { - public static final String MOD_ID = "molehunt"; - public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - public static Config CONFIG; - - public static final SimpleConfig CONFIG_FILE = Config.configFile(MOD_ID); - - public static final GameRule GAME_DURATION = GameRuleBuilder - .forInteger(CONFIG_FILE.getOrDefault("game_duration", 90)) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "gameDurationMinutes")); - - public static final GameRule MOLE_PERCENTAGE = GameRuleBuilder - .forInteger(CONFIG_FILE.getOrDefault("mole_percentage", 25)) - .range(0, 100) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "molePercentage")); - - public static final GameRule MOLE_COUNT = GameRuleBuilder - .forInteger(CONFIG_FILE.getOrDefault("mole_count", -1)) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "moleCount")); - - public static final GameRule SHOW_NAMETAGS = GameRuleBuilder - .forBoolean(CONFIG_FILE.getOrDefault("show_nametags", false)) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "showNametags")); - - public static final GameRule SHOW_TAB = GameRuleBuilder - .forBoolean(CONFIG_FILE.getOrDefault("show_tab", false)) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "showTab")); - - public static final GameRule SHOW_SKINS = GameRuleBuilder - .forBoolean(CONFIG_FILE.getOrDefault("show_skins", false)) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "showSkins")); - - public static final GameRule INITIAL_WORLD_SIZE = GameRuleBuilder - .forInteger(CONFIG_FILE.getOrDefault("initial_world_size", 600)) - .minValue(0) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "initialWorldSize")); - - public static final GameRule FINAL_WORLD_SIZE = GameRuleBuilder - .forInteger(CONFIG_FILE.getOrDefault("final_world_size", 100)) - .minValue(0) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "finalWorldSize")); - - public static final GameRule MOVING_STARTING_TIME_OFFSET = GameRuleBuilder - .forInteger(CONFIG_FILE.getOrDefault("border_moving_starting_time_offset", 30)) - .minValue(0) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "borderMovingStartingTimeOffsetMinutes")); - - public static final GameRule ENABLE_PORTALS = GameRuleBuilder - .forBoolean(CONFIG_FILE.getOrDefault("enable_portals", false)) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "enablePortals")); - - public static final GameRule FOOD_ON_START = GameRuleBuilder - .forBoolean(CONFIG_FILE.getOrDefault("food_on_start", true)) - .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "foodOnStart")); - - public Game game; - - public static HashMap timerVisibility = new HashMap<>(); - - private static void sendConfigPayload(T v, MinecraftServer server) { - if (CONFIG == null) return; - CONFIG.sendConfigPayload(); - } - - static { - GameRuleEvents.changeCallback(SHOW_NAMETAGS).register(Molehunt::sendConfigPayload); - GameRuleEvents.changeCallback(SHOW_TAB).register(Molehunt::sendConfigPayload); - GameRuleEvents.changeCallback(SHOW_SKINS).register(Molehunt::sendConfigPayload); - } - - @Override - public void onInitialize() { - LOGGER.info("Initializing Molehunt"); - - final var command = literal("molehunt"); - command.then(literal("start") - .requires(CommandManager.requirePermissionLevel(CommandManager.GAMEMASTERS_CHECK)) - .executes(context -> { - game = new Game(context.getSource().getServer()); - game.start(); - return Command.SINGLE_SUCCESS; - })); - command.then(literal("timer").requires(ServerCommandSource::isExecutedByPlayer).then( - literal("show").executes(context -> { - var player = context.getSource().getPlayer(); - assert player != null; - - timerVisibility.put(player.getUuid(), true); - context.getSource().sendFeedback(() -> Text.translatable("commands.molehunt.timer.show"), false); - - if (game == null || !game.started()) { - player.networkHandler.sendPacket(new OverlayMessageS2CPacket( - Text.translatable("commands.molehunt.error.game_not_started").formatted(Formatting.RED) - )); - } else { - player.networkHandler.sendPacket(new OverlayMessageS2CPacket(Text.of(game.getRemainingText()))); - } - - return Command.SINGLE_SUCCESS; - }) - ).then( - literal("hide").executes(context -> { - var player = context.getSource().getPlayer(); - assert player != null; - - timerVisibility.put(player.getUuid(), false); - context.getSource().sendFeedback(() -> Text.translatable("commands.molehunt.timer.hide"), false); - return Command.SINGLE_SUCCESS; - }) - )); - command.then(literal("role") - .requires(ServerCommandSource::isExecutedByPlayer) - .executes(context -> { - if (game == null || !game.started()) { - throw (new SimpleCommandExceptionType(Text.translatable("commands.molehunt.error.game_not_started"))).create(); - } - - final var source = context.getSource(); - final var player = source.getPlayer(); - assert player != null; - - if (game.isMole(player)) { - source.sendFeedback( - () -> Text.translatable("commands.molehunt.role.mole") - .append("\n\n") - .append(Text.translatable("commands.molehunt.role.mole.list", game.getMolesAsString())), - false); - } else if (player.isSpectator()) { - source.sendFeedback( - () -> Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMoles().size()), - false); - } else { - source.sendFeedback( - () -> Text.translatable("commands.molehunt.role.survivor") - .append("\n\n") - .append(Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMoles().size())), - false); - } - - return Command.SINGLE_SUCCESS; - })); - command.then(literal("stop") - .requires(CommandManager.requirePermissionLevel(CommandManager.GAMEMASTERS_CHECK)) - .executes(context -> { - if (game == null || !game.started()) { - throw (new SimpleCommandExceptionType(Text.translatable("commands.molehunt.error.game_not_started"))).create(); - } - - game.stop(); - - return Command.SINGLE_SUCCESS; - })); - - ServerLifecycleEvents.SERVER_STARTED.register(server -> CONFIG = new Config(server)); - - CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(command)); - - ServerMessageEvents.ALLOW_CHAT_MESSAGE.register((message, sender, params) -> false); - - ServerLivingEntityEvents.AFTER_DEATH.register((entity, damageSource) -> { - if (!(entity instanceof ServerPlayerEntity) || game == null) return; - if (!game.started()) return; - if (game.wonByMoles()) game.end(); - }); - - ServerPlayerEvents.AFTER_RESPAWN.register((oldPlayer, newPlayer, alive) -> { - if (game == null) return; - if (!game.started()) return; - newPlayer.changeGameMode(GameMode.SPECTATOR); - }); - - ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { - ServerPlayNetworking.send( - handler.player, - new ConfigPayload(CONFIG.nametagsEnabled(), CONFIG.skinsEnabled(), CONFIG.tabEnabled()) - ); - ServerPlayNetworking.send( - handler.player, - new GamePayload(game != null && game.started()) - ); - }); - - PayloadTypeRegistry.playS2C().register(ConfigPayload.ID, ConfigPayload.CODEC); - PayloadTypeRegistry.playS2C().register(GamePayload.ID, GamePayload.CODEC); - } + public static final String MOD_ID = "molehunt"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); + public static final SimpleConfig CONFIG_FILE = Config.configFile(MOD_ID); + public static final GameRule GAME_DURATION = GameRuleBuilder + .forInteger(CONFIG_FILE.getOrDefault("game_duration", 90)) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "gameDurationMinutes")); + public static final GameRule MOLE_PERCENTAGE = GameRuleBuilder + .forInteger(CONFIG_FILE.getOrDefault("mole_percentage", 25)) + .range(0, 100) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "molePercentage")); + public static final GameRule MOLE_COUNT = GameRuleBuilder + .forInteger(CONFIG_FILE.getOrDefault("mole_count", -1)) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "moleCount")); + public static final GameRule SHOW_NAMETAGS = GameRuleBuilder + .forBoolean(CONFIG_FILE.getOrDefault("show_nametags", false)) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "showNametags")); + public static final GameRule SHOW_TAB = GameRuleBuilder + .forBoolean(CONFIG_FILE.getOrDefault("show_tab", false)) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "showTab")); + public static final GameRule SHOW_SKINS = GameRuleBuilder + .forBoolean(CONFIG_FILE.getOrDefault("show_skins", false)) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "showSkins")); + public static final GameRule INITIAL_WORLD_SIZE = GameRuleBuilder + .forInteger(CONFIG_FILE.getOrDefault("initial_world_size", 600)) + .minValue(0) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "initialWorldSize")); + public static final GameRule FINAL_WORLD_SIZE = GameRuleBuilder + .forInteger(CONFIG_FILE.getOrDefault("final_world_size", 100)) + .minValue(0) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "finalWorldSize")); + public static final GameRule MOVING_STARTING_TIME_OFFSET = GameRuleBuilder + .forInteger(CONFIG_FILE.getOrDefault("border_moving_starting_time_offset", 30)) + .minValue(0) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "borderMovingStartingTimeOffsetMinutes")); + public static final GameRule ENABLE_PORTALS = GameRuleBuilder + .forBoolean(CONFIG_FILE.getOrDefault("enable_portals", false)) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "enablePortals")); + public static final GameRule FOOD_ON_START = GameRuleBuilder + .forBoolean(CONFIG_FILE.getOrDefault("food_on_start", true)) + .category(GameRuleCategory.MISC) + .buildAndRegister(Identifier.of(MOD_ID, "foodOnStart")); + public static Config CONFIG; + public static HashMap timerVisibility = new HashMap<>(); + + static { + GameRuleEvents.changeCallback(SHOW_NAMETAGS).register(Molehunt::sendConfigPayload); + GameRuleEvents.changeCallback(SHOW_TAB).register(Molehunt::sendConfigPayload); + GameRuleEvents.changeCallback(SHOW_SKINS).register(Molehunt::sendConfigPayload); + } + + public Game game; + + private static void sendConfigPayload(T v, MinecraftServer server) { + if (CONFIG == null) return; + CONFIG.sendConfigPayload(); + } + + @Override + public void onInitialize() { + LOGGER.info("Initializing Molehunt"); + + final var command = literal("molehunt"); + command.then(literal("start") + .requires(CommandManager.requirePermissionLevel(CommandManager.GAMEMASTERS_CHECK)) + .executes(context -> { + game = new Game(context.getSource().getServer()); + game.start(); + return Command.SINGLE_SUCCESS; + })); + command.then(literal("timer").requires(ServerCommandSource::isExecutedByPlayer).then( + literal("show").executes(context -> { + var player = context.getSource().getPlayer(); + assert player != null; + + timerVisibility.put(player.getUuid(), true); + context.getSource().sendFeedback(() -> Text.translatable("commands.molehunt.timer.show"), false); + + if (game == null || !game.started()) { + player.networkHandler.sendPacket(new OverlayMessageS2CPacket( + Text.translatable("commands.molehunt.error.game_not_started").formatted(Formatting.RED) + )); + } else { + player.networkHandler.sendPacket(new OverlayMessageS2CPacket(Text.of(game.getRemainingText()))); + } + + return Command.SINGLE_SUCCESS; + }) + ).then( + literal("hide").executes(context -> { + var player = context.getSource().getPlayer(); + assert player != null; + + timerVisibility.put(player.getUuid(), false); + context.getSource().sendFeedback(() -> Text.translatable("commands.molehunt.timer.hide"), false); + return Command.SINGLE_SUCCESS; + }) + )); + command.then(literal("role") + .requires(ServerCommandSource::isExecutedByPlayer) + .executes(context -> { + if (game == null || !game.started()) { + throw (new SimpleCommandExceptionType(Text.translatable("commands.molehunt.error.game_not_started"))).create(); + } + + final var source = context.getSource(); + final var player = source.getPlayer(); + assert player != null; + + if (game.isMole(player)) { + source.sendFeedback( + () -> Text.translatable("commands.molehunt.role.mole") + .append("\n\n") + .append(Text.translatable("commands.molehunt.role.mole.list", game.getMolesAsString())), + false); + } else if (player.isSpectator()) { + source.sendFeedback( + () -> Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMoles().size()), + false); + } else { + source.sendFeedback( + () -> Text.translatable("commands.molehunt.role.survivor") + .append("\n\n") + .append(Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMoles().size())), + false); + } + + return Command.SINGLE_SUCCESS; + })); + command.then(literal("stop") + .requires(CommandManager.requirePermissionLevel(CommandManager.GAMEMASTERS_CHECK)) + .executes(context -> { + if (game == null || !game.started()) { + throw (new SimpleCommandExceptionType(Text.translatable("commands.molehunt.error.game_not_started"))).create(); + } + + game.stop(); + + return Command.SINGLE_SUCCESS; + })); + + ServerLifecycleEvents.SERVER_STARTED.register(server -> CONFIG = new Config(server)); + + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> dispatcher.register(command)); + + ServerMessageEvents.ALLOW_CHAT_MESSAGE.register((message, sender, params) -> false); + + ServerLivingEntityEvents.AFTER_DEATH.register((entity, damageSource) -> { + if (!(entity instanceof ServerPlayerEntity) || game == null) return; + if (!game.started()) return; + if (game.wonByMoles()) game.end(); + }); + + ServerPlayerEvents.AFTER_RESPAWN.register((oldPlayer, newPlayer, alive) -> { + if (game == null) return; + if (!game.started()) return; + newPlayer.changeGameMode(GameMode.SPECTATOR); + }); + + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + ServerPlayNetworking.send( + handler.player, + new ConfigPayload(CONFIG.nametagsEnabled(), CONFIG.skinsEnabled(), CONFIG.tabEnabled()) + ); + ServerPlayNetworking.send( + handler.player, + new GamePayload(game != null && game.started()) + ); + }); + + PayloadTypeRegistry.playS2C().register(ConfigPayload.ID, ConfigPayload.CODEC); + PayloadTypeRegistry.playS2C().register(GamePayload.ID, GamePayload.CODEC); + } } diff --git a/src/main/java/world/anhgelus/molehunt/config/Config.java b/src/main/java/world/anhgelus/molehunt/config/Config.java index 08c3850..d65b569 100644 --- a/src/main/java/world/anhgelus/molehunt/config/Config.java +++ b/src/main/java/world/anhgelus/molehunt/config/Config.java @@ -6,135 +6,135 @@ import world.anhgelus.molehunt.Molehunt; public class Config { - private final MinecraftServer server; - - public Config(MinecraftServer server) { - this.server = server; - - sendConfigPayload(nametagsEnabled(), skinsEnabled(), tabEnabled()); - } - - public void sendConfigPayload() { - final var payload = new ConfigPayload(nametagsEnabled(), skinsEnabled(), tabEnabled()); - server.getPlayerManager().getPlayerList().forEach(p -> ServerPlayNetworking.send(p, payload)); - } - - public void sendConfigPayload(boolean showNametags, boolean showSkins, boolean showTab) { - final var payload = new ConfigPayload(showNametags, showSkins, showTab); - server.getPlayerManager().getPlayerList().forEach(p -> ServerPlayNetworking.send(p, payload)); - } - - public int getGameDuration() { - return server.getOverworld().getGameRules().getValue(Molehunt.GAME_DURATION); - } - - public int getMolePercentage() { - return server.getOverworld().getGameRules().getValue(Molehunt.MOLE_PERCENTAGE); - } - - public int getMoleCount() { - return server.getOverworld().getGameRules().getValue(Molehunt.MOLE_COUNT); - } - - public boolean nametagsEnabled() { - return server.getOverworld().getGameRules().getValue(Molehunt.SHOW_NAMETAGS); - } - - public boolean skinsEnabled() { - return server.getOverworld().getGameRules().getValue(Molehunt.SHOW_SKINS); - } - - public boolean tabEnabled() { - return server.getOverworld().getGameRules().getValue(Molehunt.SHOW_TAB); - } - - public int getInitialWorldSize() { - return server.getOverworld().getGameRules().getValue(Molehunt.INITIAL_WORLD_SIZE); - } - - public int getFinalWorldSize() { - return server.getOverworld().getGameRules().getValue(Molehunt.FINAL_WORLD_SIZE); - } - - public int getBorderShrinkingStartingTimeOffset() { - return server.getOverworld().getGameRules().getValue(Molehunt.MOVING_STARTING_TIME_OFFSET); - } - - public boolean portalsEnabled() { - return server.getOverworld().getGameRules().getValue(Molehunt.ENABLE_PORTALS); - } - - public boolean foodOnStart() { - return server.getOverworld().getGameRules().getValue(Molehunt.FOOD_ON_START); - } - - public static SimpleConfig configFile(String fileName) { - return SimpleConfig.of(fileName).provider(Config::defaultConfig).request(); - } - - private static String defaultConfig(String s) { - return """ - # Molehunt mod configuration file - # To regenerate the default configuration, delete, move or rename this file. - - # Game settings - - # The duration of a molehunt game, in minutes. - # Default: 90 minutes (1 hour 30 minutes). - game_duration = 90 - - # Mole percentage. - # For example, a mole percentage of 25% will get 1 mole every 4 players. - # Default: 25 %. - mole_percentage = 25 - - # Mole count (absolute). - # This setting will overwrite the mole_percentage setting. - # If set below 0, this setting is disabled. - # Default: -1. - mole_count = -1 - - # Give food on start - # Default: true - food_on_start = true - - - # Client-side settings (applies to all players) - - # Show nametags - # Default: false - show_nametags = false - - # Show skins - # Default: false - show_skins = false - - # Show tab - # Default: false - show_tab = false - - - # World border settings - - # Initial world size (in blocks). - # Default: 600 blocks. - initial_world_size = 600 - - # Final world size (in blocks). - # Default: 100 blocks. - final_world_size = 100 - - # Moving starting time offset (in minutes) - # The time before starting to move the world borders. - # If this value is greater than the game duration, borders will never move. - # Default: 30 minutes. - border_moving_starting_time_offset = 30 - - # Other - - # Enable portals (nether, end, end gateway). - # Default: false. - enable_portals = false - """; - } + private final MinecraftServer server; + + public Config(MinecraftServer server) { + this.server = server; + + sendConfigPayload(nametagsEnabled(), skinsEnabled(), tabEnabled()); + } + + public static SimpleConfig configFile(String fileName) { + return SimpleConfig.of(fileName).provider(Config::defaultConfig).request(); + } + + private static String defaultConfig(String s) { + return """ + # Molehunt mod configuration file + # To regenerate the default configuration, delete, move or rename this file. + + # Game settings + + # The duration of a molehunt game, in minutes. + # Default: 90 minutes (1 hour 30 minutes). + game_duration = 90 + + # Mole percentage. + # For example, a mole percentage of 25% will get 1 mole every 4 players. + # Default: 25 %. + mole_percentage = 25 + + # Mole count (absolute). + # This setting will overwrite the mole_percentage setting. + # If set below 0, this setting is disabled. + # Default: -1. + mole_count = -1 + + # Give food on start + # Default: true + food_on_start = true + + + # Client-side settings (applies to all players) + + # Show nametags + # Default: false + show_nametags = false + + # Show skins + # Default: false + show_skins = false + + # Show tab + # Default: false + show_tab = false + + + # World border settings + + # Initial world size (in blocks). + # Default: 600 blocks. + initial_world_size = 600 + + # Final world size (in blocks). + # Default: 100 blocks. + final_world_size = 100 + + # Moving starting time offset (in minutes) + # The time before starting to move the world borders. + # If this value is greater than the game duration, borders will never move. + # Default: 30 minutes. + border_moving_starting_time_offset = 30 + + # Other + + # Enable portals (nether, end, end gateway). + # Default: false. + enable_portals = false + """; + } + + public void sendConfigPayload() { + final var payload = new ConfigPayload(nametagsEnabled(), skinsEnabled(), tabEnabled()); + server.getPlayerManager().getPlayerList().forEach(p -> ServerPlayNetworking.send(p, payload)); + } + + public void sendConfigPayload(boolean showNametags, boolean showSkins, boolean showTab) { + final var payload = new ConfigPayload(showNametags, showSkins, showTab); + server.getPlayerManager().getPlayerList().forEach(p -> ServerPlayNetworking.send(p, payload)); + } + + public int getGameDuration() { + return server.getOverworld().getGameRules().getValue(Molehunt.GAME_DURATION); + } + + public int getMolePercentage() { + return server.getOverworld().getGameRules().getValue(Molehunt.MOLE_PERCENTAGE); + } + + public int getMoleCount() { + return server.getOverworld().getGameRules().getValue(Molehunt.MOLE_COUNT); + } + + public boolean nametagsEnabled() { + return server.getOverworld().getGameRules().getValue(Molehunt.SHOW_NAMETAGS); + } + + public boolean skinsEnabled() { + return server.getOverworld().getGameRules().getValue(Molehunt.SHOW_SKINS); + } + + public boolean tabEnabled() { + return server.getOverworld().getGameRules().getValue(Molehunt.SHOW_TAB); + } + + public int getInitialWorldSize() { + return server.getOverworld().getGameRules().getValue(Molehunt.INITIAL_WORLD_SIZE); + } + + public int getFinalWorldSize() { + return server.getOverworld().getGameRules().getValue(Molehunt.FINAL_WORLD_SIZE); + } + + public int getBorderShrinkingStartingTimeOffset() { + return server.getOverworld().getGameRules().getValue(Molehunt.MOVING_STARTING_TIME_OFFSET); + } + + public boolean portalsEnabled() { + return server.getOverworld().getGameRules().getValue(Molehunt.ENABLE_PORTALS); + } + + public boolean foodOnStart() { + return server.getOverworld().getGameRules().getValue(Molehunt.FOOD_ON_START); + } } diff --git a/src/main/java/world/anhgelus/molehunt/config/ConfigPayload.java b/src/main/java/world/anhgelus/molehunt/config/ConfigPayload.java index b43bd1b..f33e2c5 100644 --- a/src/main/java/world/anhgelus/molehunt/config/ConfigPayload.java +++ b/src/main/java/world/anhgelus/molehunt/config/ConfigPayload.java @@ -8,18 +8,18 @@ import net.minecraft.util.Identifier; import world.anhgelus.molehunt.Molehunt; public record ConfigPayload(boolean showNametags, boolean showSkins, boolean showTab) implements CustomPayload { - public static final Identifier CONFIG_PACKET_ID = Identifier.of(Molehunt.MOD_ID, "config"); + public static final Identifier CONFIG_PACKET_ID = Identifier.of(Molehunt.MOD_ID, "config"); - public static final CustomPayload.Id ID = new CustomPayload.Id<>(CONFIG_PACKET_ID); - public static final PacketCodec CODEC = PacketCodec.tuple( - PacketCodecs.BOOLEAN, ConfigPayload::showNametags, - PacketCodecs.BOOLEAN, ConfigPayload::showSkins, - PacketCodecs.BOOLEAN, ConfigPayload::showTab, - ConfigPayload::new - ); + public static final CustomPayload.Id ID = new CustomPayload.Id<>(CONFIG_PACKET_ID); + public static final PacketCodec CODEC = PacketCodec.tuple( + PacketCodecs.BOOLEAN, ConfigPayload::showNametags, + PacketCodecs.BOOLEAN, ConfigPayload::showSkins, + PacketCodecs.BOOLEAN, ConfigPayload::showTab, + ConfigPayload::new + ); - @Override - public Id getId() { - return ID; - } + @Override + public Id getId() { + return ID; + } } diff --git a/src/main/java/world/anhgelus/molehunt/config/SimpleConfig.java b/src/main/java/world/anhgelus/molehunt/config/SimpleConfig.java index 2b65829..6b7060a 100644 --- a/src/main/java/world/anhgelus/molehunt/config/SimpleConfig.java +++ b/src/main/java/world/anhgelus/molehunt/config/SimpleConfig.java @@ -38,216 +38,216 @@ import java.util.Scanner; public class SimpleConfig { - private static final Logger LOGGER = LogManager.getLogger("SimpleConfig"); - private final HashMap config = new HashMap<>(); - private final ConfigRequest request; - private boolean broken = false; - - public interface DefaultConfig { - String get( String namespace ); - - static String empty( String namespace ) { - return ""; - } - } - - public static class ConfigRequest { - - private final File file; - private final String filename; - private DefaultConfig provider; - - private ConfigRequest(File file, String filename ) { - this.file = file; - this.filename = filename; - this.provider = DefaultConfig::empty; - } - - /** - * Sets the default config provider, used to generate the - * config if it's missing. - * - * @param provider default config provider - * @return current config request object - * @see DefaultConfig - */ - public ConfigRequest provider( DefaultConfig provider ) { - this.provider = provider; - return this; - } - - /** - * Loads the config from the filesystem. - * - * @return config object - * @see SimpleConfig - */ - public SimpleConfig request() { - return new SimpleConfig( this ); - } - - private String getConfig() { - return provider.get( filename ) + "\n"; - } - - } - - /** - * Creates new config request object, ideally `namespace` - * should be the name of the mod id of the requesting mod - * - * @param filename - name of the config file - * @return new config request object - */ - public static ConfigRequest of( String filename ) { - Path path = FabricLoader.getInstance().getConfigDir(); - return new ConfigRequest( path.resolve( filename + ".properties" ).toFile(), filename ); - } - - private void createConfig() throws IOException { - - // try creating missing files - request.file.getParentFile().mkdirs(); - Files.createFile( request.file.toPath() ); - - // write default config data - PrintWriter writer = new PrintWriter(request.file, StandardCharsets.UTF_8); - writer.write( request.getConfig() ); - writer.close(); - - } - - private void loadConfig() throws IOException { - Scanner reader = new Scanner( request.file ); - for( int line = 1; reader.hasNextLine(); line ++ ) { - parseConfigEntry( reader.nextLine(), line ); - } - } - - private void parseConfigEntry( String entry, int line ) { - if( !entry.isEmpty() && !entry.startsWith( "#" ) ) { - String[] parts = entry.split("=", 2); - if( parts.length == 2 ) { - config.put( parts[0].stripTrailing(), parts[1].strip() ); - }else{ - throw new RuntimeException("Syntax error in config file on line " + line + "!"); - } - } - } - - private SimpleConfig( ConfigRequest request ) { - this.request = request; - String identifier = "Config '" + request.filename + "'"; - - if( !request.file.exists() ) { - LOGGER.info("{} is missing, generating default one...", identifier); - - try { - createConfig(); - } catch (IOException e) { - LOGGER.error("{} failed to generate!", identifier); - LOGGER.trace( e ); - broken = true; - } - } - - if( !broken ) { - try { - loadConfig(); - } catch (Exception e) { - LOGGER.error("{} failed to load!", identifier); - LOGGER.trace( e ); - broken = true; - } - } - - } - - /** - * Queries a value from config, returns `null` if the - * key does not exist. - * - * @return value corresponding to the given key - * @see SimpleConfig#getOrDefault - */ - @Deprecated - public String get( String key ) { - return config.get( key ); - } - - /** - * Returns string value from config corresponding to the given - * key, or the default string if the key is missing. - * - * @return value corresponding to the given key, or the default value - */ - public String getOrDefault( String key, String def ) { - String val = get(key); - return val == null ? def : val; - } - - /** - * Returns integer value from config corresponding to the given - * key, or the default integer if the key is missing or invalid. - * - * @return value corresponding to the given key, or the default value - */ - public int getOrDefault( String key, int def ) { - try { - return Integer.parseInt( get(key) ); - } catch (Exception e) { - return def; - } - } - - /** - * Returns boolean value from config corresponding to the given - * key, or the default boolean if the key is missing. - * - * @return value corresponding to the given key, or the default value - */ - public boolean getOrDefault( String key, boolean def ) { - String val = get(key); - if( val != null ) { - return val.equalsIgnoreCase("true"); - } - - return def; - } - - /** - * Returns double value from config corresponding to the given - * key, or the default string if the key is missing or invalid. - * - * @return value corresponding to the given key, or the default value - */ - public double getOrDefault( String key, double def ) { - try { - return Double.parseDouble( get(key) ); - } catch (Exception e) { - return def; - } - } - - /** - * If any error occurred during loading or reading from the config - * a 'broken' flag is set, indicating that the config's state - * is undefined and should be discarded using `delete()` - * - * @return the 'broken' flag of the configuration - */ - public boolean isBroken() { - return broken; - } - - /** - * deletes the config file from the filesystem - * - * @return true if the operation was successful - */ - public boolean delete() { - LOGGER.warn("Config '{}' was removed from existence! Restart the game to regenerate it.", request.filename); - return request.file.delete(); - } + private static final Logger LOGGER = LogManager.getLogger("SimpleConfig"); + private final HashMap config = new HashMap<>(); + private final ConfigRequest request; + private boolean broken = false; + + private SimpleConfig(ConfigRequest request) { + this.request = request; + String identifier = "Config '" + request.filename + "'"; + + if (!request.file.exists()) { + LOGGER.info("{} is missing, generating default one...", identifier); + + try { + createConfig(); + } catch (IOException e) { + LOGGER.error("{} failed to generate!", identifier); + LOGGER.trace(e); + broken = true; + } + } + + if (!broken) { + try { + loadConfig(); + } catch (Exception e) { + LOGGER.error("{} failed to load!", identifier); + LOGGER.trace(e); + broken = true; + } + } + + } + + /** + * Creates new config request object, ideally `namespace` + * should be the name of the mod id of the requesting mod + * + * @param filename - name of the config file + * @return new config request object + */ + public static ConfigRequest of(String filename) { + Path path = FabricLoader.getInstance().getConfigDir(); + return new ConfigRequest(path.resolve(filename + ".properties").toFile(), filename); + } + + private void createConfig() throws IOException { + + // try creating missing files + request.file.getParentFile().mkdirs(); + Files.createFile(request.file.toPath()); + + // write default config data + PrintWriter writer = new PrintWriter(request.file, StandardCharsets.UTF_8); + writer.write(request.getConfig()); + writer.close(); + + } + + private void loadConfig() throws IOException { + Scanner reader = new Scanner(request.file); + for (int line = 1; reader.hasNextLine(); line++) { + parseConfigEntry(reader.nextLine(), line); + } + } + + private void parseConfigEntry(String entry, int line) { + if (!entry.isEmpty() && !entry.startsWith("#")) { + String[] parts = entry.split("=", 2); + if (parts.length == 2) { + config.put(parts[0].stripTrailing(), parts[1].strip()); + } else { + throw new RuntimeException("Syntax error in config file on line " + line + "!"); + } + } + } + + /** + * Queries a value from config, returns `null` if the + * key does not exist. + * + * @return value corresponding to the given key + * @see SimpleConfig#getOrDefault + */ + @Deprecated + public String get(String key) { + return config.get(key); + } + + /** + * Returns string value from config corresponding to the given + * key, or the default string if the key is missing. + * + * @return value corresponding to the given key, or the default value + */ + public String getOrDefault(String key, String def) { + String val = get(key); + return val == null ? def : val; + } + + /** + * Returns integer value from config corresponding to the given + * key, or the default integer if the key is missing or invalid. + * + * @return value corresponding to the given key, or the default value + */ + public int getOrDefault(String key, int def) { + try { + return Integer.parseInt(get(key)); + } catch (Exception e) { + return def; + } + } + + /** + * Returns boolean value from config corresponding to the given + * key, or the default boolean if the key is missing. + * + * @return value corresponding to the given key, or the default value + */ + public boolean getOrDefault(String key, boolean def) { + String val = get(key); + if (val != null) { + return val.equalsIgnoreCase("true"); + } + + return def; + } + + /** + * Returns double value from config corresponding to the given + * key, or the default string if the key is missing or invalid. + * + * @return value corresponding to the given key, or the default value + */ + public double getOrDefault(String key, double def) { + try { + return Double.parseDouble(get(key)); + } catch (Exception e) { + return def; + } + } + + /** + * If any error occurred during loading or reading from the config + * a 'broken' flag is set, indicating that the config's state + * is undefined and should be discarded using `delete()` + * + * @return the 'broken' flag of the configuration + */ + public boolean isBroken() { + return broken; + } + + /** + * deletes the config file from the filesystem + * + * @return true if the operation was successful + */ + public boolean delete() { + LOGGER.warn("Config '{}' was removed from existence! Restart the game to regenerate it.", request.filename); + return request.file.delete(); + } + + public interface DefaultConfig { + static String empty(String namespace) { + return ""; + } + + String get(String namespace); + } + + public static class ConfigRequest { + + private final File file; + private final String filename; + private DefaultConfig provider; + + private ConfigRequest(File file, String filename) { + this.file = file; + this.filename = filename; + this.provider = DefaultConfig::empty; + } + + /** + * Sets the default config provider, used to generate the + * config if it's missing. + * + * @param provider default config provider + * @return current config request object + * @see DefaultConfig + */ + public ConfigRequest provider(DefaultConfig provider) { + this.provider = provider; + return this; + } + + /** + * Loads the config from the filesystem. + * + * @return config object + * @see SimpleConfig + */ + public SimpleConfig request() { + return new SimpleConfig(this); + } + + private String getConfig() { + return provider.get(filename) + "\n"; + } + + } } \ No newline at end of file diff --git a/src/main/java/world/anhgelus/molehunt/game/Game.java b/src/main/java/world/anhgelus/molehunt/game/Game.java index 4f3234c..35c45fa 100644 --- a/src/main/java/world/anhgelus/molehunt/game/Game.java +++ b/src/main/java/world/anhgelus/molehunt/game/Game.java @@ -25,176 +25,176 @@ import java.util.stream.Collectors; public class Game { - public final int defaultTime = Molehunt.CONFIG.getGameDuration() * 60; - private final MinecraftServer server; - private final List moles = new ArrayList<>(); - private final TitleFadeS2CPacket timing = new TitleFadeS2CPacket(20, 40, 20); - private int remaining = defaultTime; - private boolean started = false; - - public Game(MinecraftServer server) { - this.server = server; - } - - public void start() { - final int n = Molehunt.CONFIG.getMoleCount() < 0 - ? Math.floorDiv(server.getCurrentPlayerCount(), Math.floorDiv(100, Molehunt.CONFIG.getMolePercentage())) - : Molehunt.CONFIG.getMoleCount(); - - final var playerManager = server.getPlayerManager(); - - final var players = new ArrayList<>(playerManager.getPlayerList()); - for (int i = 0; i < n && !players.isEmpty(); i++) { - final var r = ThreadLocalRandom.current().nextInt(0, players.size()); - final var mole = players.get(r); - if (mole == null) throw new IllegalStateException("Mole is null!"); - moles.add(mole.getUuid()); - players.remove(r); - } - - final var gamerules = server.getOverworld().getGameRules(); - // immutable gamerules - gamerules.setValue(GameRules.SHOW_DEATH_MESSAGES, false, server); - gamerules.setValue(GameRules.ANNOUNCE_ADVANCEMENTS, false, server); - // gamerules for the start - gamerules.setValue(GameRules.DO_IMMEDIATE_RESPAWN, true, server); - - final var timer = TimerAccess.getTimerFromOverworld(server); - - final var worldBorder = server.getOverworld().getWorldBorder(); - worldBorder.setSize(Molehunt.CONFIG.getInitialWorldSize()); - if (Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset() < Molehunt.CONFIG.getGameDuration()) { - timer.dds_runTask(new TickTask(() -> worldBorder.interpolateSize( - Molehunt.CONFIG.getInitialWorldSize(), - Molehunt.CONFIG.getFinalWorldSize(), - (Molehunt.CONFIG.getGameDuration() - Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset()) * 60 * 20L, - 0L - ), Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset() * 60 * 20L)); - } - - final var title = new TitleS2CPacket(Text.translatable("molehunt.game.start.suspense")); - playerManager.getPlayerList().forEach(p -> { - p.getInventory().clear(); - p.kill(p.getEntityWorld()); - p.networkHandler.sendPacket(timing); - p.networkHandler.sendPacket(title); - p.changeGameMode(GameMode.SURVIVAL); - if (Molehunt.CONFIG.foodOnStart()) p.giveItemStack(new ItemStack(Items.COOKED_BEEF, 64)); - }); - - server.setDefaultGameMode(GameMode.SPECTATOR); - - timer.dds_runTask(new TickTask(() -> { - playerManager.getPlayerList().forEach(p -> { - p.networkHandler.sendPacket(timing); - if (moles.contains(p.getUuid())) { - p.networkHandler.sendPacket(new TitleS2CPacket(Text.translatable("molehunt.game.start.mole.title"))); - p.networkHandler.sendPacket(new SubtitleS2CPacket(Text.translatable("molehunt.game.start.mole.subtitle"))); - } else { - p.networkHandler.sendPacket(new TitleS2CPacket(Text.translatable("molehunt.game.start.survivor.title"))); - p.networkHandler.sendPacket(new SubtitleS2CPacket(Text.translatable("molehunt.game.start.survivor.subtitle"))); - } - // reset health and food level - p.setHealth(p.getMaxHealth()); - p.getHungerManager().setFoodLevel(20); - p.getHungerManager().setSaturationLevel(5.0f); - }); - // reset gamerules after the start - gamerules.setValue(GameRules.DO_IMMEDIATE_RESPAWN, false, server); - // reset time and weather - server.getOverworld().setTimeOfDay(0); - server.getOverworld().resetWeather(); - changeState(true); - timer.dds_runTask(new TickTask(() -> { - remaining--; - playerManager.getPlayerList().forEach(player -> { - if (Molehunt.timerVisibility.getOrDefault(player.getUuid(), true)) { - player.networkHandler.sendPacket(new OverlayMessageS2CPacket(Text.of(getRemainingText()))); - } - }); - playerManager.sendToAll(timing); - if (remaining == 0) end(); - }, 5 * 20, 20)); - }, 4 * 20)); - } - - public void stop() { - server.getPlayerManager().broadcast(Text.translatable("commands.molehunt.stop.success"), false); - end(); - } - - public void end() { - final var timer = TimerAccess.getTimerFromOverworld(server); - timer.dds_cancel(); - - final var worldBorder = server.getOverworld().getWorldBorder(); - // Stops the border shrinking. - worldBorder.setSize(worldBorder.getSize()); - - changeState(false); - final var pm = server.getPlayerManager(); - final var winnerSuspense = new TitleS2CPacket(Text.translatable("molehunt.game.end.suspense.title")); - pm.getPlayerList().forEach(p -> { - p.networkHandler.sendPacket(timing); - p.networkHandler.sendPacket(winnerSuspense); - p.changeGameMode(GameMode.CREATIVE); - }); - timer.dds_runTask(new TickTask(() -> { - TitleS2CPacket winner; - if (wonByMoles()) { - winner = new TitleS2CPacket(Text.translatable("molehunt.game.end.winners.moles.title")); - } else { - winner = new TitleS2CPacket(Text.translatable("molehunt.game.end.winners.survivors.title")); - } - pm.sendToAll(new SubtitleS2CPacket(Text.translatable("molehunt.game.end.winners.subtitle", getMolesAsString()))); - pm.sendToAll(winner); - pm.sendToAll(timing); - moles.clear(); - }, 4 * 20)); - } - - public Text getRemainingText() { - return Text.of("§c" + TimeUtils.generateShortString(remaining)); - } - - public List getMoles() { - return moles.stream() - .map(uuid -> server.getPlayerManager().getPlayer(uuid)) - .filter(Objects::nonNull) - .filter(p -> !p.isSpectator()) - .toList(); - } - - public String getMolesAsString() { - return getMoles().stream() - .map(PlayerEntity::getDisplayName) - .filter(Objects::nonNull) - .map(Object::toString) - .collect(Collectors.joining(", ")); - } - - public boolean isMole(ServerPlayerEntity player) { - return moles.contains(player.getUuid()); - } - - public boolean wonByMoles() { - return new HashSet<>(moles).containsAll( - server.getPlayerManager() - .getPlayerList() - .stream() - .filter(p -> !p.isSpectator() && !p.isCreative()) - .map(Entity::getUuid) - .toList() - ); - } - - public boolean started() { - return started; - } - - private void changeState(boolean hasStarted) { - started = hasStarted; - final var payload = new GamePayload(hasStarted); - server.getPlayerManager().getPlayerList().forEach(p -> ServerPlayNetworking.send(p, payload)); - } + public final int defaultTime = Molehunt.CONFIG.getGameDuration() * 60; + private final MinecraftServer server; + private final List moles = new ArrayList<>(); + private final TitleFadeS2CPacket timing = new TitleFadeS2CPacket(20, 40, 20); + private int remaining = defaultTime; + private boolean started = false; + + public Game(MinecraftServer server) { + this.server = server; + } + + public void start() { + final int n = Molehunt.CONFIG.getMoleCount() < 0 + ? Math.floorDiv(server.getCurrentPlayerCount(), Math.floorDiv(100, Molehunt.CONFIG.getMolePercentage())) + : Molehunt.CONFIG.getMoleCount(); + + final var playerManager = server.getPlayerManager(); + + final var players = new ArrayList<>(playerManager.getPlayerList()); + for (int i = 0; i < n && !players.isEmpty(); i++) { + final var r = ThreadLocalRandom.current().nextInt(0, players.size()); + final var mole = players.get(r); + if (mole == null) throw new IllegalStateException("Mole is null!"); + moles.add(mole.getUuid()); + players.remove(r); + } + + final var gamerules = server.getOverworld().getGameRules(); + // immutable gamerules + gamerules.setValue(GameRules.SHOW_DEATH_MESSAGES, false, server); + gamerules.setValue(GameRules.ANNOUNCE_ADVANCEMENTS, false, server); + // gamerules for the start + gamerules.setValue(GameRules.DO_IMMEDIATE_RESPAWN, true, server); + + final var timer = TimerAccess.getTimerFromOverworld(server); + + final var worldBorder = server.getOverworld().getWorldBorder(); + worldBorder.setSize(Molehunt.CONFIG.getInitialWorldSize()); + if (Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset() < Molehunt.CONFIG.getGameDuration()) { + timer.dds_runTask(new TickTask(() -> worldBorder.interpolateSize( + Molehunt.CONFIG.getInitialWorldSize(), + Molehunt.CONFIG.getFinalWorldSize(), + (Molehunt.CONFIG.getGameDuration() - Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset()) * 60 * 20L, + 0L + ), Molehunt.CONFIG.getBorderShrinkingStartingTimeOffset() * 60 * 20L)); + } + + final var title = new TitleS2CPacket(Text.translatable("molehunt.game.start.suspense")); + playerManager.getPlayerList().forEach(p -> { + p.getInventory().clear(); + p.kill(p.getEntityWorld()); + p.networkHandler.sendPacket(timing); + p.networkHandler.sendPacket(title); + p.changeGameMode(GameMode.SURVIVAL); + if (Molehunt.CONFIG.foodOnStart()) p.giveItemStack(new ItemStack(Items.COOKED_BEEF, 64)); + }); + + server.setDefaultGameMode(GameMode.SPECTATOR); + + timer.dds_runTask(new TickTask(() -> { + playerManager.getPlayerList().forEach(p -> { + p.networkHandler.sendPacket(timing); + if (moles.contains(p.getUuid())) { + p.networkHandler.sendPacket(new TitleS2CPacket(Text.translatable("molehunt.game.start.mole.title"))); + p.networkHandler.sendPacket(new SubtitleS2CPacket(Text.translatable("molehunt.game.start.mole.subtitle"))); + } else { + p.networkHandler.sendPacket(new TitleS2CPacket(Text.translatable("molehunt.game.start.survivor.title"))); + p.networkHandler.sendPacket(new SubtitleS2CPacket(Text.translatable("molehunt.game.start.survivor.subtitle"))); + } + // reset health and food level + p.setHealth(p.getMaxHealth()); + p.getHungerManager().setFoodLevel(20); + p.getHungerManager().setSaturationLevel(5.0f); + }); + // reset gamerules after the start + gamerules.setValue(GameRules.DO_IMMEDIATE_RESPAWN, false, server); + // reset time and weather + server.getOverworld().setTimeOfDay(0); + server.getOverworld().resetWeather(); + changeState(true); + timer.dds_runTask(new TickTask(() -> { + remaining--; + playerManager.getPlayerList().forEach(player -> { + if (Molehunt.timerVisibility.getOrDefault(player.getUuid(), true)) { + player.networkHandler.sendPacket(new OverlayMessageS2CPacket(Text.of(getRemainingText()))); + } + }); + playerManager.sendToAll(timing); + if (remaining == 0) end(); + }, 5 * 20, 20)); + }, 4 * 20)); + } + + public void stop() { + server.getPlayerManager().broadcast(Text.translatable("commands.molehunt.stop.success"), false); + end(); + } + + public void end() { + final var timer = TimerAccess.getTimerFromOverworld(server); + timer.dds_cancel(); + + final var worldBorder = server.getOverworld().getWorldBorder(); + // Stops the border shrinking. + worldBorder.setSize(worldBorder.getSize()); + + changeState(false); + final var pm = server.getPlayerManager(); + final var winnerSuspense = new TitleS2CPacket(Text.translatable("molehunt.game.end.suspense.title")); + pm.getPlayerList().forEach(p -> { + p.networkHandler.sendPacket(timing); + p.networkHandler.sendPacket(winnerSuspense); + p.changeGameMode(GameMode.CREATIVE); + }); + timer.dds_runTask(new TickTask(() -> { + TitleS2CPacket winner; + if (wonByMoles()) { + winner = new TitleS2CPacket(Text.translatable("molehunt.game.end.winners.moles.title")); + } else { + winner = new TitleS2CPacket(Text.translatable("molehunt.game.end.winners.survivors.title")); + } + pm.sendToAll(new SubtitleS2CPacket(Text.translatable("molehunt.game.end.winners.subtitle", getMolesAsString()))); + pm.sendToAll(winner); + pm.sendToAll(timing); + moles.clear(); + }, 4 * 20)); + } + + public Text getRemainingText() { + return Text.of("§c" + TimeUtils.generateShortString(remaining)); + } + + public List getMoles() { + return moles.stream() + .map(uuid -> server.getPlayerManager().getPlayer(uuid)) + .filter(Objects::nonNull) + .filter(p -> !p.isSpectator()) + .toList(); + } + + public String getMolesAsString() { + return getMoles().stream() + .map(PlayerEntity::getDisplayName) + .filter(Objects::nonNull) + .map(Object::toString) + .collect(Collectors.joining(", ")); + } + + public boolean isMole(ServerPlayerEntity player) { + return moles.contains(player.getUuid()); + } + + public boolean wonByMoles() { + return new HashSet<>(moles).containsAll( + server.getPlayerManager() + .getPlayerList() + .stream() + .filter(p -> !p.isSpectator() && !p.isCreative()) + .map(Entity::getUuid) + .toList() + ); + } + + public boolean started() { + return started; + } + + private void changeState(boolean hasStarted) { + started = hasStarted; + final var payload = new GamePayload(hasStarted); + server.getPlayerManager().getPlayerList().forEach(p -> ServerPlayNetworking.send(p, payload)); + } } diff --git a/src/main/java/world/anhgelus/molehunt/game/GamePayload.java b/src/main/java/world/anhgelus/molehunt/game/GamePayload.java index 66e3209..1532fa9 100644 --- a/src/main/java/world/anhgelus/molehunt/game/GamePayload.java +++ b/src/main/java/world/anhgelus/molehunt/game/GamePayload.java @@ -8,16 +8,16 @@ import net.minecraft.util.Identifier; import world.anhgelus.molehunt.Molehunt; public record GamePayload(boolean gameLaunched) implements CustomPayload { - public static final Identifier GAME_PACKET_ID = Identifier.of(Molehunt.MOD_ID, "game"); + public static final Identifier GAME_PACKET_ID = Identifier.of(Molehunt.MOD_ID, "game"); - public static final CustomPayload.Id ID = new CustomPayload.Id<>(GAME_PACKET_ID); - public static final PacketCodec CODEC = PacketCodec.tuple( - PacketCodecs.BOOLEAN, GamePayload::gameLaunched, - GamePayload::new - ); + public static final CustomPayload.Id ID = new CustomPayload.Id<>(GAME_PACKET_ID); + public static final PacketCodec CODEC = PacketCodec.tuple( + PacketCodecs.BOOLEAN, GamePayload::gameLaunched, + GamePayload::new + ); - @Override - public Id getId() { - return ID; - } + @Override + public Id getId() { + return ID; + } } diff --git a/src/main/java/world/anhgelus/molehunt/mixin/NoJoinLeaveMessage.java b/src/main/java/world/anhgelus/molehunt/mixin/NoJoinLeaveMessage.java index a82a21e..0dfd624 100644 --- a/src/main/java/world/anhgelus/molehunt/mixin/NoJoinLeaveMessage.java +++ b/src/main/java/world/anhgelus/molehunt/mixin/NoJoinLeaveMessage.java @@ -9,10 +9,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(PlayerManager.class) public class NoJoinLeaveMessage { - @Inject(at = @At("HEAD"), method = "broadcast*", cancellable = true) - public void broadcastNoJoinLeaveMessage(Text message, boolean overlay, CallbackInfo ci) { - final var content = message.getContent().toString(); - if (content.startsWith("translation{key='multiplayer.player.joined")) ci.cancel(); - else if (content.startsWith("translation{key='multiplayer.player.left")) ci.cancel(); - } + @Inject(at = @At("HEAD"), method = "broadcast*", cancellable = true) + public void broadcastNoJoinLeaveMessage(Text message, boolean overlay, CallbackInfo ci) { + final var content = message.getContent().toString(); + if (content.startsWith("translation{key='multiplayer.player.joined")) ci.cancel(); + else if (content.startsWith("translation{key='multiplayer.player.left")) ci.cancel(); + } } diff --git a/src/main/java/world/anhgelus/molehunt/mixin/NoMsgCommand.java b/src/main/java/world/anhgelus/molehunt/mixin/NoMsgCommand.java index 2727143..f698f1c 100644 --- a/src/main/java/world/anhgelus/molehunt/mixin/NoMsgCommand.java +++ b/src/main/java/world/anhgelus/molehunt/mixin/NoMsgCommand.java @@ -10,8 +10,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(MessageCommand.class) public class NoMsgCommand { - @Inject(at = @At("HEAD"), method = "register", cancellable = true) - private static void register(CommandDispatcher dispatcher, CallbackInfo ci) { - ci.cancel(); - } + @Inject(at = @At("HEAD"), method = "register", cancellable = true) + private static void register(CommandDispatcher dispatcher, CallbackInfo ci) { + ci.cancel(); + } } diff --git a/src/main/java/world/anhgelus/molehunt/mixin/NoPortals.java b/src/main/java/world/anhgelus/molehunt/mixin/NoPortals.java index a71e6d1..2648f25 100644 --- a/src/main/java/world/anhgelus/molehunt/mixin/NoPortals.java +++ b/src/main/java/world/anhgelus/molehunt/mixin/NoPortals.java @@ -11,9 +11,9 @@ import world.anhgelus.molehunt.Molehunt; @Mixin(PortalManager.class) public class NoPortals { - @Inject(at = @At("HEAD"), method = "tick", cancellable = true) - public void disableTick(ServerWorld world, Entity entity, boolean canUsePortals, CallbackInfoReturnable cir) { - if (Molehunt.CONFIG == null || Molehunt.CONFIG.portalsEnabled()) return; - cir.setReturnValue(false); - } + @Inject(at = @At("HEAD"), method = "tick", cancellable = true) + public void disableTick(ServerWorld world, Entity entity, boolean canUsePortals, CallbackInfoReturnable cir) { + if (Molehunt.CONFIG == null || Molehunt.CONFIG.portalsEnabled()) return; + cir.setReturnValue(false); + } } diff --git a/src/main/java/world/anhgelus/molehunt/mixin/WorldTimerAccess.java b/src/main/java/world/anhgelus/molehunt/mixin/WorldTimerAccess.java index cd8a1b4..1e0ba12 100644 --- a/src/main/java/world/anhgelus/molehunt/mixin/WorldTimerAccess.java +++ b/src/main/java/world/anhgelus/molehunt/mixin/WorldTimerAccess.java @@ -14,32 +14,32 @@ import java.util.function.BooleanSupplier; @Mixin(ServerWorld.class) public class WorldTimerAccess implements TimerAccess { - @Unique - private final List tasks = new ArrayList<>(); - - @Unique - private final List tasksToAdd = new ArrayList<>(); - - @Inject(method = "tick", at = @At("TAIL")) - private void onTick(BooleanSupplier shouldKeepTicking, CallbackInfo ci) { - tasks.stream().filter(TickTask::isRunning).forEach(TickTask::tick); - tasks.addAll(tasksToAdd); - tasksToAdd.clear(); - } - - @Override - public void dds_runTask(TimerAccess.TickTask task) { - tasksToAdd.add(task); - } - - @Override - public void dds_cancel() { - tasks.stream().filter(TickTask::isRunning).forEach(TickTask::cancel); - tasks.clear(); - } - - @Override - public List dds_getTasks() { - return tasks.stream().filter(TickTask::isRunning).toList(); - } + @Unique + private final List tasks = new ArrayList<>(); + + @Unique + private final List tasksToAdd = new ArrayList<>(); + + @Inject(method = "tick", at = @At("TAIL")) + private void onTick(BooleanSupplier shouldKeepTicking, CallbackInfo ci) { + tasks.stream().filter(TickTask::isRunning).forEach(TickTask::tick); + tasks.addAll(tasksToAdd); + tasksToAdd.clear(); + } + + @Override + public void dds_runTask(TimerAccess.TickTask task) { + tasksToAdd.add(task); + } + + @Override + public void dds_cancel() { + tasks.stream().filter(TickTask::isRunning).forEach(TickTask::cancel); + tasks.clear(); + } + + @Override + public List dds_getTasks() { + return tasks.stream().filter(TickTask::isRunning).toList(); + } } \ No newline at end of file diff --git a/src/main/java/world/anhgelus/molehunt/timer/TickTask.java b/src/main/java/world/anhgelus/molehunt/timer/TickTask.java index 8c74b89..1cc83e2 100644 --- a/src/main/java/world/anhgelus/molehunt/timer/TickTask.java +++ b/src/main/java/world/anhgelus/molehunt/timer/TickTask.java @@ -4,69 +4,69 @@ package world.anhgelus.molehunt.timer; * Represents a complete task called each tick */ public class TickTask implements TimerAccess.TickTask { - public final long ticksDelay; - public final long ticksRepeat; - public final boolean repeating; - public final TimerAccess.Task task; - private boolean cancelled = false; - private long currentTicking; + public final long ticksDelay; + public final long ticksRepeat; + public final boolean repeating; + public final TimerAccess.Task task; + private boolean cancelled = false; + private long currentTicking; - /** - * Create a new repeating TickTask - * - * @param task Task to run after the delay or the repeat time - * @param ticksDelay Delay before the first task's run - * @param ticksRepeat Repeat each tick (if the repeat is 0, it will repeat each tick, if it is below 0, it will not repeat) - * @throws IllegalArgumentException if ticksDelay is below 0 - */ - public TickTask(TimerAccess.Task task, long ticksDelay, long ticksRepeat) { - if (ticksDelay < 0) throw new IllegalArgumentException("Ticks delay must be non-negative"); - this.ticksDelay = ticksDelay; - this.ticksRepeat = ticksRepeat; - this.task = task; - repeating = ticksRepeat >= 0; - currentTicking = ticksDelay; - } + /** + * Create a new repeating TickTask + * + * @param task Task to run after the delay or the repeat time + * @param ticksDelay Delay before the first task's run + * @param ticksRepeat Repeat each tick (if the repeat is 0, it will repeat each tick, if it is below 0, it will not repeat) + * @throws IllegalArgumentException if ticksDelay is below 0 + */ + public TickTask(TimerAccess.Task task, long ticksDelay, long ticksRepeat) { + if (ticksDelay < 0) throw new IllegalArgumentException("Ticks delay must be non-negative"); + this.ticksDelay = ticksDelay; + this.ticksRepeat = ticksRepeat; + this.task = task; + repeating = ticksRepeat >= 0; + currentTicking = ticksDelay; + } - /** - * Create a new delayed TickTask - * - * @param task Task to run after the delay or the repeat time - * @param ticksDelay Delay before the first task's run - * @throws IllegalArgumentException if ticksDelay or if ticksRepeat is below 0 - */ - public TickTask(TimerAccess.Task task, long ticksDelay) { - if (ticksDelay < 0) throw new IllegalArgumentException("Ticks delay must be non-negative"); - this.ticksDelay = ticksDelay; - this.ticksRepeat = -1; - this.task = task; - repeating = false; - currentTicking = ticksDelay; - } + /** + * Create a new delayed TickTask + * + * @param task Task to run after the delay or the repeat time + * @param ticksDelay Delay before the first task's run + * @throws IllegalArgumentException if ticksDelay or if ticksRepeat is below 0 + */ + public TickTask(TimerAccess.Task task, long ticksDelay) { + if (ticksDelay < 0) throw new IllegalArgumentException("Ticks delay must be non-negative"); + this.ticksDelay = ticksDelay; + this.ticksRepeat = -1; + this.task = task; + repeating = false; + currentTicking = ticksDelay; + } - public void tick() { - if (--currentTicking > 0) return; - task.run(); - if (repeating) { - currentTicking = ticksRepeat; - } else { - cancel(); - } - } + public void tick() { + if (--currentTicking > 0) return; + task.run(); + if (repeating) { + currentTicking = ticksRepeat; + } else { + cancel(); + } + } - public long cancel() { - if (cancelled) throw new IllegalStateException("Task already cancelled"); - cancelled = true; - return currentTicking; - } + public long cancel() { + if (cancelled) throw new IllegalStateException("Task already cancelled"); + cancelled = true; + return currentTicking; + } - public boolean isRunning() { - return !cancelled; - } + public boolean isRunning() { + return !cancelled; + } - @Override - public long getTickingBeforeRun() { - if (cancelled) return -1; - return currentTicking; - } + @Override + public long getTickingBeforeRun() { + if (cancelled) return -1; + return currentTicking; + } } \ No newline at end of file diff --git a/src/main/java/world/anhgelus/molehunt/timer/TimerAccess.java b/src/main/java/world/anhgelus/molehunt/timer/TimerAccess.java index 2e02b12..32ee611 100644 --- a/src/main/java/world/anhgelus/molehunt/timer/TimerAccess.java +++ b/src/main/java/world/anhgelus/molehunt/timer/TimerAccess.java @@ -6,60 +6,60 @@ import net.minecraft.world.World; import java.util.List; public interface TimerAccess { - /** - * Get the timer linked to the overworld - * - * @param server Current server - * @return TimerAccess linked to the overworld - */ - static TimerAccess getTimerFromOverworld(MinecraftServer server) { - final var timer = (TimerAccess) server.getWorld(World.OVERWORLD); - if (timer == null) - throw new NullPointerException("Impossible to get TimerAccess from the overworld (it is null)"); - return timer; - } + /** + * Get the timer linked to the overworld + * + * @param server Current server + * @return TimerAccess linked to the overworld + */ + static TimerAccess getTimerFromOverworld(MinecraftServer server) { + final var timer = (TimerAccess) server.getWorld(World.OVERWORLD); + if (timer == null) + throw new NullPointerException("Impossible to get TimerAccess from the overworld (it is null)"); + return timer; + } - /** - * Run a task (called each tick ticked) - * - * @param task Task to run - */ - void dds_runTask(TimerAccess.TickTask task); + /** + * Run a task (called each tick ticked) + * + * @param task Task to run + */ + void dds_runTask(TimerAccess.TickTask task); - void dds_cancel(); + void dds_cancel(); - /** - * @return All non-cancelled tasks - */ - List dds_getTasks(); + /** + * @return All non-cancelled tasks + */ + List dds_getTasks(); - interface TickTask { - /** - * Tick the task - */ - void tick(); + interface TickTask { + /** + * Tick the task + */ + void tick(); - /** - * Cancel the task - * - * @return the remaining ticks before the run of the Task - * @throws IllegalStateException if the task is already cancelled - */ - long cancel(); + /** + * Cancel the task + * + * @return the remaining ticks before the run of the Task + * @throws IllegalStateException if the task is already cancelled + */ + long cancel(); - boolean isRunning(); + boolean isRunning(); - /** - * @return the number of ticks before run of the task (if the task is cancelled, returns -1) - */ - long getTickingBeforeRun(); - } + /** + * @return the number of ticks before run of the task (if the task is cancelled, returns -1) + */ + long getTickingBeforeRun(); + } - /** - * Represents a task to run after ticking - */ - @FunctionalInterface - interface Task { - void run(); - } + /** + * Represents a task to run after ticking + */ + @FunctionalInterface + interface Task { + void run(); + } } diff --git a/src/main/java/world/anhgelus/molehunt/utils/TimeUtils.java b/src/main/java/world/anhgelus/molehunt/utils/TimeUtils.java index 2b96606..952f2d2 100644 --- a/src/main/java/world/anhgelus/molehunt/utils/TimeUtils.java +++ b/src/main/java/world/anhgelus/molehunt/utils/TimeUtils.java @@ -2,50 +2,51 @@ package world.anhgelus.molehunt.utils; public class TimeUtils { - private record Time(long hours, long minutes, long seconds) {} - - public static String generateString(long time) { - final var pt = generateTime(time); - - StringBuilder sb = new StringBuilder(); - if (pt.hours != 0) { - sb.append(pt.hours).append(" hours "); - } - if (pt.minutes != 0 || pt.hours != 0) { - sb.append(pt.minutes).append(" minutes "); - } - sb.append(pt.seconds).append(" seconds"); - - return sb.toString(); - } - - public static String generateShortString(long time) { - final var pt = generateTime(time); - - return padLeft(pt.hours) + ":" + - padLeft(pt.minutes) + ":" + - padLeft(pt.seconds); - } - - private static Time generateTime(long time) { - long hours = 0; - if (time > 3600) { - hours = Math.floorDiv(time, 3600); - } - long minutes = 0; - if (hours != 0 || time > 60) { - minutes = Math.floorDiv(time - hours * 3600, 60); - } - long seconds = (long) Math.floor(time - hours * 3600 - minutes * 60); - return new Time(hours, minutes, seconds); - } - - private static String padLeft(long n) { - if (n < 10 && n != 0) { - return "0" + Math.round(n); - } else if (n == 0) { - return "00"; - } - return Long.toString(Math.round(n)); - } + public static String generateString(long time) { + final var pt = generateTime(time); + + StringBuilder sb = new StringBuilder(); + if (pt.hours != 0) { + sb.append(pt.hours).append(" hours "); + } + if (pt.minutes != 0 || pt.hours != 0) { + sb.append(pt.minutes).append(" minutes "); + } + sb.append(pt.seconds).append(" seconds"); + + return sb.toString(); + } + + public static String generateShortString(long time) { + final var pt = generateTime(time); + + return padLeft(pt.hours) + ":" + + padLeft(pt.minutes) + ":" + + padLeft(pt.seconds); + } + + private static Time generateTime(long time) { + long hours = 0; + if (time > 3600) { + hours = Math.floorDiv(time, 3600); + } + long minutes = 0; + if (hours != 0 || time > 60) { + minutes = Math.floorDiv(time - hours * 3600, 60); + } + long seconds = (long) Math.floor(time - hours * 3600 - minutes * 60); + return new Time(hours, minutes, seconds); + } + + private static String padLeft(long n) { + if (n < 10 && n != 0) { + return "0" + Math.round(n); + } else if (n == 0) { + return "00"; + } + return Long.toString(Math.round(n)); + } + + private record Time(long hours, long minutes, long seconds) { + } } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 09a65fe..43d56c8 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -1,37 +1,36 @@ { - "schemaVersion": 1, - "id": "molehunt", - "version": "${version}", - "name": "Molehunt", - "description": "Molehunt mod", - "authors": [ - "Anhgelus Morhtuuzh" - ], - "contact": {}, - "license": "AGPL-3.0", - "icon": "assets/molehunt/icon.png", - "environment": "*", - "entrypoints": { - "client": [ - "world.anhgelus.molehunt.client.MolehuntClient" - ], - "server": [ - - ], - "main": [ - "world.anhgelus.molehunt.Molehunt" - ] - }, - "mixins": [ - "molehunt.mixins.json", - { - "config": "molehunt.client.mixins.json", - "environment": "client" - } - ], - "depends": { - "fabricloader": ">=${loader_version}", - "fabric-api": "*", - "minecraft": "${minecraft_version}" - } + "schemaVersion": 1, + "id": "molehunt", + "version": "${version}", + "name": "Molehunt", + "description": "Molehunt mod", + "authors": [ + "Anhgelus Morhtuuzh" + ], + "contact": {}, + "license": "AGPL-3.0", + "icon": "assets/molehunt/icon.png", + "environment": "*", + "entrypoints": { + "client": [ + "world.anhgelus.molehunt.client.MolehuntClient" + ], + "server": [ + ], + "main": [ + "world.anhgelus.molehunt.Molehunt" + ] + }, + "mixins": [ + "molehunt.mixins.json", + { + "config": "molehunt.client.mixins.json", + "environment": "client" + } + ], + "depends": { + "fabricloader": ">=${loader_version}", + "fabric-api": "*", + "minecraft": "${minecraft_version}" + } } diff --git a/src/main/resources/molehunt.mixins.json b/src/main/resources/molehunt.mixins.json index 2dc5bb9..8013886 100644 --- a/src/main/resources/molehunt.mixins.json +++ b/src/main/resources/molehunt.mixins.json @@ -1,15 +1,15 @@ { - "required": true, - "minVersion": "0.8", - "package": "world.anhgelus.molehunt.mixin", - "compatibilityLevel": "JAVA_21", - "mixins": [ - "NoJoinLeaveMessage", - "NoMsgCommand", - "NoPortals", - "WorldTimerAccess" - ], - "injectors": { - "defaultRequire": 1 - } + "required": true, + "minVersion": "0.8", + "package": "world.anhgelus.molehunt.mixin", + "compatibilityLevel": "JAVA_21", + "mixins": [ + "NoJoinLeaveMessage", + "NoMsgCommand", + "NoPortals", + "WorldTimerAccess" + ], + "injectors": { + "defaultRequire": 1 + } } -- cgit v1.2.3 From 02965b5cf44e64f12fd41fb32e0a7cc300541753 Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Wed, 18 Mar 2026 13:22:53 +0100 Subject: fix(): cannot launch game due to invalid gamerule names --- .../java/world/anhgelus/molehunt/Molehunt.java | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/world/anhgelus/molehunt/Molehunt.java b/src/main/java/world/anhgelus/molehunt/Molehunt.java index 6486700..74687d1 100644 --- a/src/main/java/world/anhgelus/molehunt/Molehunt.java +++ b/src/main/java/world/anhgelus/molehunt/Molehunt.java @@ -46,51 +46,51 @@ public class Molehunt implements ModInitializer { public static final GameRule GAME_DURATION = GameRuleBuilder .forInteger(CONFIG_FILE.getOrDefault("game_duration", 90)) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "gameDurationMinutes")); + .buildAndRegister(Identifier.of(MOD_ID, "game_duration_minutes")); public static final GameRule MOLE_PERCENTAGE = GameRuleBuilder .forInteger(CONFIG_FILE.getOrDefault("mole_percentage", 25)) .range(0, 100) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "molePercentage")); + .buildAndRegister(Identifier.of(MOD_ID, "mole_percentage")); public static final GameRule MOLE_COUNT = GameRuleBuilder .forInteger(CONFIG_FILE.getOrDefault("mole_count", -1)) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "moleCount")); + .buildAndRegister(Identifier.of(MOD_ID, "mole_count")); public static final GameRule SHOW_NAMETAGS = GameRuleBuilder .forBoolean(CONFIG_FILE.getOrDefault("show_nametags", false)) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "showNametags")); + .buildAndRegister(Identifier.of(MOD_ID, "show_nametags")); public static final GameRule SHOW_TAB = GameRuleBuilder .forBoolean(CONFIG_FILE.getOrDefault("show_tab", false)) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "showTab")); + .buildAndRegister(Identifier.of(MOD_ID, "show_tab")); public static final GameRule SHOW_SKINS = GameRuleBuilder .forBoolean(CONFIG_FILE.getOrDefault("show_skins", false)) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "showSkins")); + .buildAndRegister(Identifier.of(MOD_ID, "show_skins")); public static final GameRule INITIAL_WORLD_SIZE = GameRuleBuilder .forInteger(CONFIG_FILE.getOrDefault("initial_world_size", 600)) .minValue(0) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "initialWorldSize")); + .buildAndRegister(Identifier.of(MOD_ID, "initial_world_size")); public static final GameRule FINAL_WORLD_SIZE = GameRuleBuilder .forInteger(CONFIG_FILE.getOrDefault("final_world_size", 100)) .minValue(0) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "finalWorldSize")); + .buildAndRegister(Identifier.of(MOD_ID, "final_world_size")); public static final GameRule MOVING_STARTING_TIME_OFFSET = GameRuleBuilder .forInteger(CONFIG_FILE.getOrDefault("border_moving_starting_time_offset", 30)) .minValue(0) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "borderMovingStartingTimeOffsetMinutes")); + .buildAndRegister(Identifier.of(MOD_ID, "border_moving_starting_time_offset_minutes")); public static final GameRule ENABLE_PORTALS = GameRuleBuilder .forBoolean(CONFIG_FILE.getOrDefault("enable_portals", false)) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "enablePortals")); + .buildAndRegister(Identifier.of(MOD_ID, "enable_portals")); public static final GameRule FOOD_ON_START = GameRuleBuilder .forBoolean(CONFIG_FILE.getOrDefault("food_on_start", true)) .category(GameRuleCategory.MISC) - .buildAndRegister(Identifier.of(MOD_ID, "foodOnStart")); + .buildAndRegister(Identifier.of(MOD_ID, "food_on_start")); public static Config CONFIG; public static HashMap timerVisibility = new HashMap<>(); -- cgit v1.2.3 From 5221052b004117e8aa2763c2a8085372391b13c4 Mon Sep 17 00:00:00 2001 From: Anhgelus Morhtuuzh Date: Wed, 18 Mar 2026 13:39:58 +0100 Subject: fix(game): #18 (last one was not fixing) --- README.md | 4 ++-- src/main/java/world/anhgelus/molehunt/Molehunt.java | 4 ++-- src/main/java/world/anhgelus/molehunt/game/Game.java | 18 +++++++++++------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 1e05f15..000882d 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Molehunt is a Minecraft mod creating the game with the same name in this cubic game. -A complete wiki is available [here](https://www.anhgelus.world/molehunt/introduction.html). +A complete wiki is available [here](https://william.herges.fr/molehunt/introduction.html). ## Usage @@ -38,7 +38,7 @@ To change most values, you can play with the gamerules added by the mod with the `/gamerule` command. Every gamerule introduced by the mod starts with `molehunt:`. To dive deeper into the -configuration, [an online wiki is available](https://www.anhgelus.world/molehunt/configuration.html). +configuration, [an online wiki is available](https://william.herges.fr/molehunt/configuration.html). ## Technologies diff --git a/src/main/java/world/anhgelus/molehunt/Molehunt.java b/src/main/java/world/anhgelus/molehunt/Molehunt.java index 74687d1..d31be6b 100644 --- a/src/main/java/world/anhgelus/molehunt/Molehunt.java +++ b/src/main/java/world/anhgelus/molehunt/Molehunt.java @@ -166,13 +166,13 @@ public class Molehunt implements ModInitializer { false); } else if (player.isSpectator()) { source.sendFeedback( - () -> Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMoles().size()), + () -> Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMolesCount()), false); } else { source.sendFeedback( () -> Text.translatable("commands.molehunt.role.survivor") .append("\n\n") - .append(Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMoles().size())), + .append(Text.translatable("commands.molehunt.role.survivor.mole_count", game.getMolesCount())), false); } diff --git a/src/main/java/world/anhgelus/molehunt/game/Game.java b/src/main/java/world/anhgelus/molehunt/game/Game.java index 35c45fa..98784c3 100644 --- a/src/main/java/world/anhgelus/molehunt/game/Game.java +++ b/src/main/java/world/anhgelus/molehunt/game/Game.java @@ -22,6 +22,7 @@ import world.anhgelus.molehunt.utils.TimeUtils; import java.util.*; import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; +import java.util.stream.Stream; public class Game { @@ -157,17 +158,19 @@ public class Game { return Text.of("§c" + TimeUtils.generateShortString(remaining)); } - public List getMoles() { + private Stream getMoles() { return moles.stream() .map(uuid -> server.getPlayerManager().getPlayer(uuid)) .filter(Objects::nonNull) - .filter(p -> !p.isSpectator()) - .toList(); + .filter(p -> !p.isSpectator() && !p.isCreative()); + } + + public int getMolesCount() { + return getMoles().toArray().length; } public String getMolesAsString() { - return getMoles().stream() - .map(PlayerEntity::getDisplayName) + return getMoles().map(PlayerEntity::getDisplayName) .filter(Objects::nonNull) .map(Object::toString) .collect(Collectors.joining(", ")); @@ -178,7 +181,8 @@ public class Game { } public boolean wonByMoles() { - return new HashSet<>(moles).containsAll( + final var moles = getMoles().map(PlayerEntity::getUuid).toList(); + return !moles.isEmpty() && new HashSet<>(moles).containsAll( server.getPlayerManager() .getPlayerList() .stream() @@ -195,6 +199,6 @@ public class Game { private void changeState(boolean hasStarted) { started = hasStarted; final var payload = new GamePayload(hasStarted); - server.getPlayerManager().getPlayerList().forEach(p -> ServerPlayNetworking.send(p, payload)); + server.getPlayerManager().sendToAll(ServerPlayNetworking.createS2CPacket(payload)); } } -- cgit v1.2.3