80 Commits

Author SHA1 Message Date
Oliver
5f5d5302cc fancynpcs: Remove newline in VERSION file 2025-12-05 18:57:22 +01:00
Oliver
dc80615146 Add support for 1.21.11-rc2 2025-12-05 18:51:27 +01:00
Oliver
7fb487a344 Add support for 1.21.11-pre5 2025-12-04 14:32:32 +01:00
Oliver
e837ad89d3 fancydialogs: Update changelog path in snapshot deployment config 2025-12-03 16:58:10 +01:00
Oliver
47bb6f7a10 ci: Use FancyVerteiler (#170)
* ci: Use FancyVerteiler for FD snapshot

* Update configs

* Revert some stuff

* Use FancyVerteiler for all plugins

* Fixes

* Fix

* Delete deployment tool
2025-12-03 16:11:23 +01:00
Oliver
54572f1736 fancynpcs, fancyholograms, fancydialogs: Add support for 1.21.11-pre4 2025-12-01 20:55:39 +01:00
Oliver
fb79b5eaed fancynpcs, fancyholograms, fancydialogs: Update FancyAnalytics 2025-11-27 14:45:47 +01:00
Oliver
ef5109444e fancyholograms, fancydialogs: Use 1.21.11-pre3 2025-11-26 20:11:24 +01:00
Oliver
878fee61e7 fancynpcs: Use 1.21.11-pre3 2025-11-26 19:59:06 +01:00
Oliver
c7fb3b0b92 packets, fancynpcs: Update to 1.21.11-pre3 2025-11-25 18:35:43 +01:00
Oliver
9aecf99744 fancynpcs: Update version to 2.8.1 2025-11-25 18:05:01 +01:00
Oliver
1bdf350594 fancyvisuals: Update README.md 2025-11-25 18:00:45 +01:00
Oliver
b285b8f364 docs: Add built in placeholders of FancyCore 2025-11-25 14:33:37 +01:00
Oliver
9cba1bfb31 docs: Update event and punishment service references; add Placeholders API documentation 2025-11-25 13:48:12 +01:00
Oliver
0336844633 docs: Add blog post "introducing hytale plugins" 2025-11-24 18:15:01 +01:00
Oliver
62f387e6b9 docs: Update getting started page for FancyCore 2025-11-24 18:15:01 +01:00
Oliver
4ce6acf325 docs: Add punishment API and some disclaimers for FancyCore 2025-11-24 18:15:01 +01:00
Oliver
1bc13362c1 docs: Add chat and server commands for FancyCore 2025-11-24 18:15:01 +01:00
Oliver
e1c57f8e1c docs: Add economy related commands for FancyCore 2025-11-24 18:15:01 +01:00
Oliver
bcd526db5b docs: Add player related commands for FancyCore 2025-11-24 18:15:01 +01:00
Oliver
a22db1cbb1 docs: Add docs about event system in FancyCore 2025-11-24 18:15:01 +01:00
Oliver
18518f9c19 docs: Add some command documentation for FancyCore 2025-11-24 18:15:01 +01:00
Oliver
30898973c3 docs: Add docs for FancyCore 2025-11-24 18:15:01 +01:00
Oliver
217c4c36cc docs: Add banner and logo of FancyCore 2025-11-24 18:15:01 +01:00
Oliver
6d130bd93e docs: Add dialog examples by reunionsmp 2025-11-24 16:41:53 +01:00
Oliver
22f5ccca29 fancydialogs: Fixed player getting kicked when no button or action is defined
Updated version to 1.0.1
2025-11-23 11:36:50 +01:00
Oliver
1422d42322 docs: More docs for FancyDialogs 2025-11-23 11:12:12 +01:00
Oliver
474a1c3e54 fancydialogs: Update version to 1.0.0 2025-11-23 11:06:17 +01:00
Oliver
169ec91269 docs: Polish docs for FancyDialogs 2025-11-23 11:05:15 +01:00
Oliver
d6dc456f2a fancynpcs: Wrap packets in Npc#update method in bundle packet (1.12.9+) 2025-11-21 21:10:48 +01:00
Oliver
da7bc075aa Update to 1.21.11-pre2 2025-11-21 20:56:00 +01:00
Oliver
00be6cc835 fancyholograms: Update version to 2.8.0.160 2025-11-21 15:02:23 +01:00
Alex
1919b3da4d Added argument validation in SetLineCMD to prevent index errors (#155) 2025-11-21 15:00:55 +01:00
橙汁喵
529821ced6 fancyholograms: reload cannot load hologram (#152) 2025-11-21 15:00:26 +01:00
Oliver
0a6aa9da80 fancynpcs: Try to fix npcs disappearing 2025-11-21 14:34:07 +01:00
Oliver
d7c6f1bc81 fancynpcs, fancyholograms: Drop support for 1.19.4 2025-11-21 14:02:01 +01:00
Oliver
a35c2ac786 Update to 1.21.11-pre1 2025-11-21 13:52:51 +01:00
Oliver
c0998aabdb jdb: Fix index not deleting 2025-11-20 14:46:16 +01:00
Oliver
09363fe010 jdb: Add basic document indexing 2025-11-20 14:38:23 +01:00
Oliver
6c1ff8a77a config: Add VERSION file and configure publishing to maven repo 2025-11-20 12:29:25 +01:00
Oliver
0d8665e5e5 config: Add ConfigJSON 2025-11-20 12:26:58 +01:00
Oliver
b2416a14b2 jdb: Add VERSION file 2025-11-20 11:20:34 +01:00
Oliver
ec842f7287 jdb: Add countDocuments method 2025-11-20 11:06:00 +01:00
Oliver
6fe7cbabbd fancynpcs, packets: Update to 25w46a 2025-11-18 12:29:29 +01:00
Oliver
0d378fa951 config: Use java 17 instead of 17 2025-11-18 11:50:29 +01:00
Oliver
ccf9fe0d59 fancynpcs: Update version to 2.8.0.309 2025-11-18 11:35:00 +01:00
Oliver
b3fc33cb95 fancynpcs: load USE_MINECRAFT_USERCACHE_FEATURE_FLAG 2025-11-18 11:34:48 +01:00
Oliver
e1ba7dd888 Merge pull request #153 from FancyInnovations/fix/folia-visibility-issues
fancynpcs: Add enable-folia-visibility-fix feature flag
2025-11-18 11:33:51 +01:00
Oliver
8735da08a6 Merge branch 'main' into fix/folia-visibility-issues 2025-11-18 11:33:10 +01:00
Oliver
540b3ad738 fancynpcs: Add enable-folia-visibility-fix fflag 2025-11-18 11:32:06 +01:00
Oliver
5c5f82736b Rollback ChatColorHandler 6.0.0 2025-11-09 11:34:12 +01:00
Oliver
a2a2d39d7e dev builds for 1.21.11 2025-11-08 13:41:45 +01:00
Oliver
3388ae6d80 fancynpcs: Update version to 2.8.0.307 2025-11-08 13:36:49 +01:00
Oliver
ab5826be3c docs: Add npc rotate command and inverted need_permission 2025-11-08 13:36:33 +01:00
TheosRee
24c1907eec fancynpcs, fancyholograms: Use sets of Version Strings for checking if a version is valid (#142)
* use set for checking if a version is valid

* use Paper PR for snapshot reference

---------

Co-authored-by: TheosRee <theosree@users.noreply.github.com>
2025-11-08 13:30:57 +01:00
Oliver
d36af3cd00 Update gradle plugins 2025-11-08 13:30:57 +01:00
Oliver
bfd39c60b0 Update gradle wrapper to 9.2.0 2025-11-08 13:30:57 +01:00
Oliver
02fa1f0fa6 Remove publishing to hangar and modrinth via gradle plugins 2025-11-08 13:30:57 +01:00
Oliver
1ee7bdcd98 fancynpcs: Update changelog 2025-11-08 13:30:57 +01:00
Oliver
a27fd2e0c4 fancyholograms, fancynpcs: Update changelog 2025-11-08 13:30:57 +01:00
Oliver
d74fd4bab1 fancyholograms v2 & v3, fancydialogs: Add support for 1.21.11 2025-11-08 13:30:57 +01:00
Oliver
7d5b86fd14 packets: Add support for 1.21.11 2025-11-08 13:30:57 +01:00
Oliver
fb2beeb5b2 fancynpcs: Fix version number typos 2025-11-08 13:30:57 +01:00
Oliver
bbd361ea0d fancynpcs: Add support for 1.21.11 2025-11-08 13:30:57 +01:00
Alex
d9333f12f5 fancynpcs: Implemented inversed permission checks -> "!" prefix for perms (#139)
* Implemented feature from here: https://github.com/FancyInnovations/FancyPlugins/issues/86

* Implemented feature from here: https://github.com/FancyInnovations/FancyPlugins/issues/50
2025-11-08 13:14:05 +01:00
Oliver
455165b0f6 common: Ignore directories when loading language files 2025-11-05 12:43:53 +01:00
Oliver
f29bd13387 fancynpcs: Filter language files to only include .yml extensions 2025-11-05 12:37:22 +01:00
Oliver
7cd24f18f3 fancynpcs: Only use minecraft usercache if fflag is enabled 2025-11-05 12:28:23 +01:00
Oliver
9774f57ea6 fancydialogs: Add expectedUserInput field to ConfirmationDialog 2025-11-05 12:26:24 +01:00
Oliver
232f041df0 fancydialogs: Fix cast exception caused by close_timeout config option 2025-11-04 20:26:35 +01:00
Oliver
47e0714ec7 fancyholograms v3: Add total_amount_attached_traits metric 2025-11-04 20:22:38 +01:00
envizar
414da48403 fancynpcs: Add swing_arm_on_update option (#135) 2025-11-04 20:02:00 +01:00
Oliver
ac2a4f6e93 fancynpcs: Fix mirror skin for 1.21.9 2025-11-04 19:06:14 +01:00
Oliver
49f2dfd79a fancyholograms v3: Refactor trait commands and add warning if using dev build 2025-10-15 16:44:25 +02:00
Oliver
bef84f0366 fancydialogs: Add dialog close timeout 2025-10-15 16:26:50 +02:00
Oliver
1b2ec76eb5 fancydialogs: Remove tutorial command 2025-10-15 16:26:24 +02:00
Oliver
a85384df0c fancydialogs: Update dependencies 2025-10-15 16:26:09 +02:00
Oliver
2df8f839aa Update links in README.md 2025-10-14 23:19:46 +02:00
Oliver
a74073abd2 packets: Fix 1.21.9 tests 2025-10-14 22:17:00 +02:00
Oliver
f71c783163 fancynpcs: Always respawn npcs with a delay when using Folia 2025-10-06 21:31:42 +02:00
243 changed files with 4820 additions and 2237 deletions

View File

@@ -2,8 +2,9 @@ name: Deploy FancyDialogs (release)
on: on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
deploy-plugin: deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -27,25 +28,20 @@ jobs:
- name: Modify gradlew permissions - name: Modify gradlew permissions
run: chmod +x ./gradlew run: chmod +x ./gradlew
- name: Build deployment tool - name: Build
run: ./gradlew :tools:deployment:shadowJar
- name: Build FancyDialogs for Modrinth
env: env:
RELEASE_CHANNEL: 'release' RELEASE_CHANNEL: 'release'
RELEASE_PLATFORM: 'modrinth'
run: ./gradlew :plugins:fancydialogs:shadowJar run: ./gradlew :plugins:fancydialogs:shadowJar
- name: Deploy to Modrinth - name: Deploy
env: uses: fancyinnovations/fancyverteiler@main
MODRINTH_API_KEY: ${{ secrets.MODRINTH_API_KEY }} with:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} config_path: "/plugins/fancydialogs/release_deployment_config.json"
run: modrinth_api_key: ${{ secrets.MODRINTH_API_KEY }}
cd tools/deployment/build/libs && discord_webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
java -jar deployment.jar modrinth ../../../../plugins/fancydialogs/release_deployment_config.json true
- name: Publish to reposilite (releases) # - name: Publish to reposilite (releases)
run: ./gradlew :plugins:fancydialogs:fd-api:publishAllPublicationsToFancyinnovationsReleasesRepository # run: ./gradlew :plugins:fancydialogs:fd-api:publishAllPublicationsToFancyinnovationsReleasesRepository
- name: Publish to reposilite (snapshots) # - name: Publish to reposilite (snapshots)
run: ./gradlew :plugins:fancydialogs:fd-api:publishAllPublicationsToFancyinnovationsSnapshotsRepository # run: ./gradlew :plugins:fancydialogs:fd-api:publishAllPublicationsToFancyinnovationsSnapshotsRepository

View File

@@ -2,8 +2,9 @@ name: Deploy FancyHolograms v2 (release)
on: on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
deploy-plugin: deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -27,25 +28,20 @@ jobs:
- name: Modify gradlew permissions - name: Modify gradlew permissions
run: chmod +x ./gradlew run: chmod +x ./gradlew
- name: Build deployment tool - name: Build
run: ./gradlew :tools:deployment:shadowJar
- name: Build FancyHolograms v2 for Modrinth
env: env:
RELEASE_CHANNEL: 'release' RELEASE_CHANNEL: 'release'
RELEASE_PLATFORM: 'modrinth'
run: ./gradlew :plugins:fancyholograms-v2:shadowJar run: ./gradlew :plugins:fancyholograms-v2:shadowJar
- name: Deploy to Modrinth - name: Deploy
env: uses: fancyinnovations/fancyverteiler@main
MODRINTH_API_KEY: ${{ secrets.MODRINTH_API_KEY }} with:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} config_path: "/plugins/fancyholograms-v2/release_deployment_config.json"
run: modrinth_api_key: ${{ secrets.MODRINTH_API_KEY }}
cd tools/deployment/build/libs && discord_webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
java -jar deployment.jar modrinth ../../../../plugins/fancyholograms-v2/release_deployment_config.json true
- name: Publish to reposilite (releases) # - name: Publish to reposilite (releases)
run: ./gradlew :plugins:fancyholograms-v2:api:publishAllPublicationsToFancyinnovationsReleasesRepository # run: ./gradlew :plugins:fancyholograms-v2:api:publishAllPublicationsToFancyinnovationsReleasesRepository
- name: Publish to reposilite (snapshots) # - name: Publish to reposilite (snapshots)
run: ./gradlew :plugins:fancyholograms-v2:api:publishAllPublicationsToFancyinnovationsSnapshotsRepository # run: ./gradlew :plugins:fancyholograms-v2:api:publishAllPublicationsToFancyinnovationsSnapshotsRepository

View File

@@ -2,8 +2,9 @@ name: Deploy FancyHolograms (release)
on: on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
deploy-plugin: deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -27,25 +28,20 @@ jobs:
- name: Modify gradlew permissions - name: Modify gradlew permissions
run: chmod +x ./gradlew run: chmod +x ./gradlew
- name: Build deployment tool - name: Build
run: ./gradlew :tools:deployment:shadowJar
- name: Build FancyHolograms for Modrinth
env: env:
RELEASE_CHANNEL: 'release' RELEASE_CHANNEL: 'release'
RELEASE_PLATFORM: 'modrinth'
run: ./gradlew :plugins:fancyholograms:shadowJar run: ./gradlew :plugins:fancyholograms:shadowJar
- name: Deploy to Modrinth - name: Deploy
env: uses: fancyinnovations/fancyverteiler@main
MODRINTH_API_KEY: ${{ secrets.MODRINTH_API_KEY }} with:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} config_path: "/plugins/fancyholograms/release_deployment_config.json"
run: modrinth_api_key: ${{ secrets.MODRINTH_API_KEY }}
cd tools/deployment/build/libs && discord_webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
java -jar deployment.jar modrinth ../../../../plugins/fancyholograms/release_deployment_config.json true
- name: Publish to reposilite (releases) # - name: Publish to reposilite (releases)
run: ./gradlew :plugins:fancyholograms:fh-api:publishAllPublicationsToFancyinnovationsReleasesRepository # run: ./gradlew :plugins:fancyholograms:fh-api:publishAllPublicationsToFancyinnovationsReleasesRepository
- name: Publish to reposilite (snapshots) # - name: Publish to reposilite (snapshots)
run: ./gradlew :plugins:fancyholograms:fh-api:publishAllPublicationsToFancyinnovationsSnapshotsRepository # run: ./gradlew :plugins:fancyholograms:fh-api:publishAllPublicationsToFancyinnovationsSnapshotsRepository

View File

@@ -2,8 +2,9 @@ name: Deploy FancyNpcs (release)
on: on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
deploy-plugin: deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -27,25 +28,20 @@ jobs:
- name: Modify gradlew permissions - name: Modify gradlew permissions
run: chmod +x ./gradlew run: chmod +x ./gradlew
- name: Build deployment tool - name: Build
run: ./gradlew :tools:deployment:shadowJar
- name: Build FancyNpcs for Modrinth
env: env:
RELEASE_CHANNEL: 'release' RELEASE_CHANNEL: 'release'
RELEASE_PLATFORM: 'modrinth'
run: ./gradlew :plugins:fancynpcs:shadowJar run: ./gradlew :plugins:fancynpcs:shadowJar
- name: Deploy to Modrinth - name: Deploy
env: uses: fancyinnovations/fancyverteiler@main
MODRINTH_API_KEY: ${{ secrets.MODRINTH_API_KEY }} with:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} config_path: "/plugins/fancynpcs/release_deployment_config.json"
run: modrinth_api_key: ${{ secrets.MODRINTH_API_KEY }}
cd tools/deployment/build/libs && discord_webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
java -jar deployment.jar modrinth ../../../../plugins/fancynpcs/release_deployment_config.json true
- name: Publish to reposilite (releases) # - name: Publish to reposilite (releases)
run: ./gradlew :plugins:fancynpcs:fn-api:publishAllPublicationsToFancyinnovationsReleasesRepository # run: ./gradlew :plugins:fancynpcs:fn-api:publishAllPublicationsToFancyinnovationsReleasesRepository
- name: Publish to reposilite (snapshots) # - name: Publish to reposilite (snapshots)
run: ./gradlew :plugins:fancynpcs:fn-api:publishAllPublicationsToFancyinnovationsSnapshotsRepository # run: ./gradlew :plugins:fancynpcs:fn-api:publishAllPublicationsToFancyinnovationsSnapshotsRepository

View File

@@ -2,8 +2,9 @@ name: Deploy FancyDialogs (snapshot)
on: on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
deploy-fancydialogs: deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -27,22 +28,17 @@ jobs:
- name: Modify gradlew permissions - name: Modify gradlew permissions
run: chmod +x ./gradlew run: chmod +x ./gradlew
- name: Build deployment tool - name: Build
run: ./gradlew :tools:deployment:shadowJar
- name: Build FancyDialogs for Modrinth
env: env:
RELEASE_CHANNEL: 'snapshot' RELEASE_CHANNEL: 'snapshot'
RELEASE_PLATFORM: 'modrinth'
run: ./gradlew :plugins:fancydialogs:shadowJar run: ./gradlew :plugins:fancydialogs:shadowJar
- name: Deploy to Modrinth - name: Deploy
env: uses: fancyinnovations/fancyverteiler@main
MODRINTH_API_KEY: ${{ secrets.MODRINTH_API_KEY }} with:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} config_path: "/plugins/fancydialogs/snapshot_deployment_config.json"
run: modrinth_api_key: ${{ secrets.MODRINTH_API_KEY }}
cd tools/deployment/build/libs && discord_webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
java -jar deployment.jar modrinth ../../../../plugins/fancydialogs/snapshot_deployment_config.json true
- name: Publish to reposilite (snapshots) # - name: Publish to reposilite (snapshots)
run: ./gradlew :plugins:fancydialogs:fd-api:publishAllPublicationsToFancyinnovationsSnapshotsRepository # run: ./gradlew :plugins:fancydialogs:fd-api:publishAllPublicationsToFancyinnovationsSnapshotsRepository

View File

@@ -2,8 +2,9 @@ name: Deploy FancyHolograms v2 (snapshot)
on: on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
deploy-fancyholograms: deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -27,22 +28,17 @@ jobs:
- name: Modify gradlew permissions - name: Modify gradlew permissions
run: chmod +x ./gradlew run: chmod +x ./gradlew
- name: Build deployment tool - name: Build
run: ./gradlew :tools:deployment:shadowJar
- name: Build FancyHolograms v2 for Modrinth
env: env:
RELEASE_CHANNEL: 'snapshot' RELEASE_CHANNEL: 'snapshot'
RELEASE_PLATFORM: 'modrinth'
run: ./gradlew :plugins:fancyholograms-v2:shadowJar run: ./gradlew :plugins:fancyholograms-v2:shadowJar
- name: Deploy to Modrinth - name: Deploy
env: uses: fancyinnovations/fancyverteiler@main
MODRINTH_API_KEY: ${{ secrets.MODRINTH_API_KEY }} with:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} config_path: "/plugins/fancyholograms-v2/snapshot_deployment_config.json"
run: modrinth_api_key: ${{ secrets.MODRINTH_API_KEY }}
cd tools/deployment/build/libs && discord_webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
java -jar deployment.jar modrinth ../../../../plugins/fancyholograms-v2/snapshot_deployment_config.json true
- name: Publish to reposilite (snapshots) # - name: Publish to reposilite (snapshots)
run: ./gradlew :plugins:fancyholograms-v2:api:publishAllPublicationsToFancyinnovationsSnapshotsRepository # run: ./gradlew :plugins:fancyholograms-v2:api:publishAllPublicationsToFancyinnovationsSnapshotsRepository

View File

@@ -2,8 +2,9 @@ name: Deploy FancyHolograms (snapshot)
on: on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
deploy-plugin: deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -27,22 +28,17 @@ jobs:
- name: Modify gradlew permissions - name: Modify gradlew permissions
run: chmod +x ./gradlew run: chmod +x ./gradlew
- name: Build deployment tool - name: Build
run: ./gradlew :tools:deployment:shadowJar
- name: Build FancyHolograms for Modrinth
env: env:
RELEASE_CHANNEL: 'snapshot' RELEASE_CHANNEL: 'snapshot'
RELEASE_PLATFORM: 'modrinth'
run: ./gradlew :plugins:fancyholograms:shadowJar run: ./gradlew :plugins:fancyholograms:shadowJar
- name: Deploy to Modrinth - name: Deploy
env: uses: fancyinnovations/fancyverteiler@main
MODRINTH_API_KEY: ${{ secrets.MODRINTH_API_KEY }} with:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} config_path: "/plugins/fancyholograms/snapshot_deployment_config.json"
run: modrinth_api_key: ${{ secrets.MODRINTH_API_KEY }}
cd tools/deployment/build/libs && discord_webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
java -jar deployment.jar modrinth ../../../../plugins/fancyholograms/snapshot_deployment_config.json true
- name: Publish to reposilite (snapshots) # - name: Publish to reposilite (snapshots)
run: ./gradlew :plugins:fancyholograms:fh-api:publishAllPublicationsToFancyinnovationsSnapshotsRepository # run: ./gradlew :plugins:fancyholograms:fh-api:publishAllPublicationsToFancyinnovationsSnapshotsRepository

View File

@@ -2,8 +2,9 @@ name: Deploy FancyNpcs (snapshot)
on: on:
workflow_dispatch: workflow_dispatch:
jobs: jobs:
deploy-plugin: deploy:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -27,36 +28,17 @@ jobs:
- name: Modify gradlew permissions - name: Modify gradlew permissions
run: chmod +x ./gradlew run: chmod +x ./gradlew
- name: Build deployment tool - name: Build
run: ./gradlew :tools:deployment:shadowJar
- name: Build FancyNpcs for Modrinth
env: env:
RELEASE_CHANNEL: 'snapshot' RELEASE_CHANNEL: 'snapshot'
RELEASE_PLATFORM: 'modrinth'
run: ./gradlew :plugins:fancynpcs:shadowJar run: ./gradlew :plugins:fancynpcs:shadowJar
- name: Deploy to Modrinth - name: Deploy
env: uses: fancyinnovations/fancyverteiler@main
MODRINTH_API_KEY: ${{ secrets.MODRINTH_API_KEY }} with:
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} config_path: "/plugins/fancynpcs/snapshot_deployment_config.json"
run: modrinth_api_key: ${{ secrets.MODRINTH_API_KEY }}
cd tools/deployment/build/libs && discord_webhook_url: ${{ secrets.DISCORD_WEBHOOK_URL }}
java -jar deployment.jar modrinth ../../../../plugins/fancynpcs/snapshot_deployment_config.json true
# - name: Build FancyNpcs for Hangar # - name: Publish to reposilite (snapshots)
# env: # run: ./gradlew :plugins:fancynpcs:fn-api:publishAllPublicationsToFancyinnovationsSnapshotsRepository
# RELEASE_CHANNEL: 'snapshot'
# RELEASE_PLATFORM: 'hangar'
# run: ./gradlew :plugins:fancynpcs:shadowJar
#
# - name: Deploy to Hangar
# env:
# HANGAR_API_KEY: "${{ secrets.HANGAR_API_KEY }}"
# DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
# run:
# cd tools/deployment/build/libs &&
# java -jar deployment.jar hangar ../../../../plugins/fancynpcs/snapshot_deployment_config.json true
- name: Publish to reposilite (snapshots)
run: ./gradlew :plugins:fancynpcs:fn-api:publishAllPublicationsToFancyinnovationsSnapshotsRepository

View File

@@ -8,8 +8,8 @@
[![Hangar](https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/available/hangar_vector.svg)](https://hangar.papermc.io/Oliver) [![Hangar](https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/available/hangar_vector.svg)](https://hangar.papermc.io/Oliver)
[![Unsupported spigot](https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/unsupported/spigot_vector.svg)]() [![Unsupported spigot](https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/unsupported/spigot_vector.svg)]()
[![Website](https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/documentation/website_vector.svg)](https://fancyplugins.de) [![Website](https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/documentation/website_vector.svg)](https://fancyinnovations.com)
[![Documentation](https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/documentation/ghpages_vector.svg)](https://docs.fancyplugins.de) [![Documentation](https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/documentation/ghpages_vector.svg)](https://docs.fancyinnovations.com)
[![discord-plural](https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/discord-plural_46h.png)](https://discord.gg/ZUgYCEJUEx) [![discord-plural](https://cdn.jsdelivr.net/npm/@intergrav/devins-badges@3/assets/compact/social/discord-plural_46h.png)](https://discord.gg/ZUgYCEJUEx)
@@ -35,7 +35,6 @@ This is a [monorepo](docs/src/development-guidelines/monorepo.md) for all plugin
- Packets: packet handling library (also called FancySitula) - Packets: packet handling library (also called FancySitula)
**Tools:** **Tools:**
- Deployment: deploy plugins to platforms like modrinth
- Quick E2E: generate a quick end-to-end environment for testing - Quick E2E: generate a quick end-to-end environment for testing
## Usage ## Usage

View File

@@ -1,10 +1,8 @@
plugins { plugins {
id("com.gradleup.shadow") version "9.0.0-beta17" apply false id("com.gradleup.shadow") version "9.2.2" apply false
id("io.papermc.paperweight.userdev") version "2.0.0-beta.17" apply false id("io.papermc.paperweight.userdev") version "2.0.0-beta.19" apply false
id("xyz.jpenilla.run-paper") version "2.3.1" apply false id("xyz.jpenilla.run-paper") version "3.0.2" apply false
id("de.eldoria.plugin-yml.paper") version "0.7.1" apply false id("de.eldoria.plugin-yml.paper") version "0.8.0" apply false
id("io.papermc.hangar-publish-plugin") version "0.1.3" apply false
id("com.modrinth.minotaur") version "2.+" apply false
} }
allprojects { allprojects {

View File

@@ -0,0 +1,93 @@
---
authors:
- name: Oliver Schlüter
email: oliver@fancyinnovations.com
link: https://github.com/OliverSchlueter
avatar: https://avatars.githubusercontent.com/u/79666085?v=4
date: 2025-11-24
title: "Introducing Hytale Plugins"
description: "The first Hytale plugin by FancyInnovations will be: FancyCore, a powerful plugin that provides a wide range of features and tools for Hytale server owners."
---
![](../static/blogs/introducing-hytale-plugins/hytale-plugins.png)
[Hytale](https://hytale.com/) is finally heading into early access, and I couldnt be more excited. With that, Im thrilled to announce that **FancyInnovations will be creating server-side plugins for the Hytale ecosystem**.
The moment I read the [“Hytale is saved!”](https://hytale.com/news/2025/11/hytale-is-saved) announcement, my brain immediately jumped into brainstorming mode.
After digging through the currently available information about Hytale modding, one thing became very clear:
**Hytale needs a plugin that provides a strong set of essential features — a foundation others can build on.**
And thats exactly what Im creating.
## Introducing FancyCore
With FancyCore I want to create a platform where gamemode specific plugins can be built on. It will cover many features you probably would expect from a core plugin.
Lets look at some features:
- Teleportation (teleport, teleport request, teleport all, spawn, warps, player homes, …)
- World (create, teleport, change day time, weather, spawn protection, …)
- Inventory (kits, virtual backpacks, …)
- Economy (balance, pay, sell items, shops, …)
- Chat (chat format, player-to-player messages, nicknames, help, rules, broadcast, mute chat, clear chat, chat rooms, …)
- Moderation (report, warn, kick, mute, ban, chat / command history, vanish, sudo, …)
- Permissions (groups, permissions, …)
- Server (list online players, uptime, tps, mspt, cpu usage, ram usage, disk usage, …)
- Player (gamemode, playtime, fly, heal, feed, god, ping, …)
- Easy to use API
Notable API features:
- Permissions API
- Economy API
- Placeholder API
Other features for the future:
- Discord integration
- Built-in WebUI
This is a long list of features and not all will be available on day 1.
As I am writing this blog post, there is no public Hytale API documentation, so all I can do at the moment is write all the business logic and implement the actual commands and other Hytale specific features as soon as the API documentation is available.
For now, it will be a big all-in-one plugin, in the future I might create separate plugins for each category, but that's not final yet.
**FancyCore will be a Hytale only plugin**, I dont plan to create a Minecraft plugin out of this at the moment.
For now the plan is to get FancyCore working for Hytale as soon as possible while, but while keeping a good quality.
The plugin will be free and open-source, just like all Minecraft plugins. You can already take a look at the new mono-repo for Hytale plugins [here](https://github.com/FancyInnovations/HytalePlugins).
Some parts that dont require the Hytale server dependency are already being worked on.
Feel free to take a look and contribute to it if you want.
Parts of the documentation is also already written (mostly the commands). You can take a look at it here.
From what Ive seen, you wont be able to upload Hytale plugins to Modrinth (just speculations).
The only popular platform that supports distribution of Hytale plugins is Curseforge.
I'm currently not sure if I want to distribute FancyCore there.
In the meanwhile Ive been programming a little download service myself to distribute Hytale plugins, so they will for sure be available on the fancyinnovations.com website.
I know the community is currently working on alternative platforms as well, so we will see how that develops.
## FancyAnalytics
Alongside FancyCore, Ill also be releasing FancyAnalytics for Hytale — a toolset for gathering analytics from your Hytale server or plugins.
It will include:
* A Hytale plugin for collecting metrics such as online players, TPS, entity counts, CPU usage, and more
* An SDK for plugin developers to track usage metrics, including support for custom data points
This gives developers powerful insight into how their plugins are used — and helps server owners better understand performance.
## Conclusion
If youre as excited as I am about Hytale — and FancyCore — then join our Discord community!
Assign yourself the “FancyCore” role to get all the latest updates.
I'm currently working on it daily and will share progress updates there.
If you have any suggestions or feature requests for FancyCore, feel free to share them in the `#core-discussion` channel or DM me directly (`real_oliver`).
Theres also a dedicated channel for general Hytale news.
(The release date for early access will be announced this week!)
*Oliver*

View File

@@ -0,0 +1,2 @@
icon: code
order: 7

View File

@@ -0,0 +1,30 @@
---
icon: dot
order: 9
---
# Events API
FancyCore has its own event system that allows you to listen to various events that happen in the FancyCore system.
## Registering an event listener
Example for registering a listener for the `PlayerReportedEvent`:
```java
EventService eventService = EventService.get();
eventService.registerListener(PlayerReportedEvent.class, (event) -> {
System.out.println("PlayerReportedEvent fired with report id: " + event.getReport().id());
});
```
## Available events
### Player events
| Event | Description |
|-----------------------|-------------------------------------------------------------------------------|
| `PlayerModifiedEvent` | Event fired when a player's data is modified (through FancyPlayer's setters). |
| `PlayerReportedEvent` | Fired when a player is reported. |
| `PlayerPunishedEvent` | Fired when a player receives a punishment (warning, kick, mute or ban). |

View File

@@ -0,0 +1,51 @@
---
icon: dot
order: 10
---
# Getting started
## Include the API in your project
To include the FancyCore API in your project, you need to add the following dependency to your `build.gradle.kts` or `pom.xml` file.
**Gradle:**
```kotlin
repositories {
maven("https://repo.fancyinnovations.com/releases")
}
```
```kotlin
dependencies {
compileOnly("com.fancyinnovations:FancyCore:VERSION")
}
```
**Maven:**
```xml
<repository>
<id>fancyinnovations-releases</id>
<name>FancyInnovations Repository</name>
<url>https://repo.fancyinnovations.com/releases</url>
</repository>
```
```xml
<dependency>
<groupId>com.fancyinnovations</groupId>
<artifactId>FancyCore</artifactId>
<version>VERSION</version>
<scope>provided</scope>
</dependency>
```
Replace `VERSION` with the version of the API you want to use. You can find the latest version on the download pages or in the GitHub releases.
## JavaDocs and help
You can find the JavaDocs for the FancyDialogs API [here](https://repo.fancyinnovations.com/javadoc/releases/com/fancyinnovations/FancyCore/latest).
Join the [FancyInnovations Discord](https://discord.gg/ZUgYCEJUEx) for help and support. There is a dedicated channel for help about the api (`#core-api`).
```

View File

@@ -0,0 +1,48 @@
---
icon: dot
order: 7
---
# Placeholder API
FancyCore includes a Placeholders API that allows you to create and manage custom placeholders for use in various plugins.
## Parse placeholders
To parse placeholders in a string, use the `PlaceholderService`'s `parse` method. Here's an example:
```java
PlaceholderService placeholderService = PlaceholderService.get();
String parsedString = placeholderService.parse(player, "Hello, {player_name}! Your rank is {player_rank}.");
```
## Creating a custom placeholder
To create a custom placeholder, implement the `PlaceholderProvider` interface and register it with the `PlaceholderService`. Here's an example of creating a simple placeholder that returns a player's rank:
```java
public class PlayerRankPlaceholder implements PlaceholderProvider {
@Override
public String getName() {
return "Player Rank Placeholder";
}
@Override
public String getIdentifier() {
return "player_rank";
}
@Override
public String parse(FancyPlayer player, String input) {
return player.getRank().getName();
}
}
```
You can then register your placeholder provider with the `PlaceholderService`:
```java
PlaceholderService placeholderService = PlaceholderService.get();
placeholderService.registerPlaceholderProvider(new PlayerRankPlaceholder());
```

View File

@@ -0,0 +1,38 @@
---
icon: dot
order: 8
---
# Punishment API
FancyCore provides a comprehensive Punishment API that allows you to manage player punishments such as warnings, kicks, mutes, and bans.
## Using the Punishment Service
With the Punishment Service, you can easily issue various types of punishments to players. Below are examples of how to use the Punishment Service:
```java
PunishmentService punishmentService = PunishmentService.get();
punishmentService.warnPlayer(player, staff, "reason", duration);
punishmentService.mutePlayer(player, staff, "reason"); // Permanent mute
punishmentService.mutePlayer(player, staff, "reason", 1000*60*60*4); // Temporary mute (4 hours)
punishmentService.kickPlayer(player, staff, "reason");
punishmentService.banPlayer(player, staff, "reason", duration); // Permanent ban
punishmentService.banPlayer(player, staff, "reason", 1000*60*60*24); // Temporary ban (1 day)
```
You can also retrieve existing punishments for a player:
```java
List<Punishment> punishments = punishmentService.getPunishmentsForPlayer(player);
```
Player reports are also managed through the Punishment Service:
```java
punishmentService.reportPlayer(player, staff, "reason");
```

View File

@@ -0,0 +1,2 @@
icon: log
order: 5

View File

@@ -0,0 +1,9 @@
---
icon: dot
title: V0
order: 1
---
# FancyCore v0.x.x

View File

@@ -0,0 +1,99 @@
---
icon: dot
title: Chat
---
![](../../static/commands.png)
# Commands for the chat system
!!!warning
The command list is not complete and not all commands are properly documented yet.
Some commands might not be implemented yet.
!!!
## Messages
### Message
Description: Sends a private message to the specified player.<br/>
Syntax: ``/Message (player) (message)`` or ``/Msg (player) (message)``<br/>
Permission: ``fancycore.commands.message``
### Reply
Description: Replies to the last private message received.<br/>
Syntax: ``/Reply (message)`` or ``/R (message)``<br/>
Permission: ``fancycore.commands.reply``
### Message Spy
Description: Toggles message spying to see private messages between other players.<br/>
Syntax: ``/MessageSpy`` or ``/MsgSpy``<br/>
Permission: ``fancycore.commands.messagespy``
### ToggleMessages
Description: Toggles the ability to receive private messages.<br/>
Syntax: ``/ToggleMessages`` or ``/ToggleMsg``<br/>
Permission: ``fancycore.commands.togglemessages``
## Chat rooms
### CreateChatRoom
Description: Creates a new chat room with the specified name.<br/>
Syntax: ``/CreateChatRoom (name)`` or ``/CCR (name)``<br/>
Permission: ``fancycore.commands.createchatroom``
### JoinChatRoom
Description: Joins the specified chat room.<br/>
Syntax: ``/JoinChatRoom (name)`` or ``/JCR (name)``<br/>
Permission: ``fancycore.commands.joinchatroom``
### LeaveChatRoom
Description: Leaves the current chat room.<br/>
Syntax: ``/LeaveChatRoom`` or ``/LCR``<br/>
Permission: ``fancycore.commands.leavechatroom``
### ListChatRooms
Description: Lists all available chat rooms on the server.<br/>
Syntax: ``/ListChatRooms`` or ``/LCRs``<br/>
Permission: ``fancycore.commands.listchatrooms``
### ChatRoomInfo
Description: Displays information about the specified chat room.<br/>
Syntax: ``/ChatRoomInfo (name)`` or ``/CRInfo (name)``<br/>
Permission: ``fancycore.commands.chatroominfo``
## Chat Management
### ClearChat
Description: Clears the chat for all players on the server.<br/>
Syntax: ``/ClearChat`` or ``/CC``<br/>
Permission: ``fancycore.commands.clearchat``
### SlowChat
Description: Sets a slow mode for chat, limiting how often players can send messages.<br/>
Syntax: ``/SlowChat (seconds)`` or ``/Slow (seconds)``<br/>
Permission: ``fancycore.commands.slowchat``
### MuteChat
Description: Mutes the chat for all players, preventing them from sending messages.<br/>
Syntax: ``/MuteChat``<br/>
Permission: ``fancycore.commands.mutechat``
### UnmuteChat
Description: Unmutes the chat, allowing players to send messages again.<br/>
Syntax: ``/UnmuteChat``<br/>
Permission: ``fancycore.commands.unmutechat``

View File

@@ -0,0 +1,2 @@
order: 9
icon: command-palette

View File

@@ -0,0 +1,49 @@
---
icon: dot
title: Economy
---
![](../../static/commands.png)
# Commands for the economy system
!!!warning
The command list is not complete and not all commands are properly documented yet.
Some commands might not be implemented yet.
!!!
### Balance
Description: Displays the balance of the specified player or your own balance if no player is specified.<br/>
Syntax: ``/Balance [player]``<br/>
Permission: ``fancycore.commands.balance``
### Pay
Description: Transfers a specified amount of money from your balance to another player's balance.<br/>
Syntax: ``/Pay (player) (amount)``<br/>
Permission: ``fancycore.commands.pay``
### Set Balance
Description: Sets the balance of the specified player to a given amount.<br/>
Syntax: ``/SetBalance (player) (amount)``<br/>
Permission: ``fancycore.commands.setbalance``
### Add Balance
Description: Adds a specified amount of money to the balance of the specified player.<br/>
Syntax: ``/AddBalance (player) (amount)``<br/>
Permission: ``fancycore.commands.addbalance``
### Remove Balance
Description: Removes a specified amount of money from the balance of the specified player.<br/>
Syntax: ``/RemoveBalance (player) (amount)``<br/>
Permission: ``fancycore.commands.removebalance``
### Top Balances
Description: Displays a leaderboard of players with the highest balances.<br/>
Syntax: ``/TopBalances [page]``<br/>
Permission: ``fancycore.commands.topbalances``

View File

@@ -0,0 +1,79 @@
---
icon: dot
title: Inventory
---
![](../../static/commands.png)
# Commands for the inventory system
!!!warning
The command list is not complete and not all commands are properly documented yet.
Some commands might not be implemented yet.
!!!
## Kits
### Create Kit
Description: Creates a new kit with the specified name. It contains all items in your inventory<br/>
Syntax: ``/CreateKit (name)``<br/>
Permission: ``fancycore.commands.createkit``
### Delete Kit
Description: Deletes the specified kit.<br/>
Syntax: ``/DeleteKit (name)``<br/>
Permission: ``fancycore.commands.deletekit``
### Give Kit
Description: Gives the specified kit to the targeted player(s).<br/>
Syntax: ``/Kit (name) [player]``<br/>
Permission: ``fancycore.commands.kit.(name)``
### List Kits
Description: Lists all available kits.<br/>
Syntax: ``/Kits`` or ``/ListKits``<br/>
Permission: ``fancycore.commands.listkits``
## Backpacks
### Open Backpack
Description: Opens the specified backpack of the targeted player.<br/>
Syntax: ``/Backpack (name) [player]``<br/>
Permission: ``fancycore.commands.backpack``
### Create Backpack
Description: Creates a new backpack with the specified name and size.<br/>
Syntax: ``/CreateBackpack (name) (size)``<br/>
Permission: ``fancycore.commands.createbackpack``
### Delete Backpack
Description: Deletes the specified backpack.<br/>
Syntax: ``/DeleteBackpack (name)``<br/>
Permission: ``fancycore.commands.deletebackpack``
### List Backpacks
Description: Lists all available backpacks.<br/>
Syntax: ``/Backpacks`` or ``/ListBackpacks``<br/>
Permission: ``fancycore.commands.listbackpacks``
## Utilities
### Clear Inventory
Description: Clears the inventory of the targeted player(s).<br/>
Syntax: ``/ClearInventory [player]``<br/>
Permission: ``fancycore.commands.clearinventory``
### Open another Player's Inventory
Description: Opens the inventory of the targeted player.<br/>
Syntax: ``/OpenInventory (player)`` or ``/Invsee (player)``<br/>
Permission: ``fancycore.commands.openinventory``

View File

@@ -0,0 +1,110 @@
---
icon: dot
title: Moderation
---
![](../../static/commands.png)
# Commands for the moderation system
!!!warning
The command list is not complete and not all commands are properly documented yet.
Some commands might not be implemented yet.
!!!
## Report
### Report a Player
Description: Reports a player for misconduct.<br/>
Syntax: ``/Report (player) [reason]``<br/>
Permission: ``fancycore.commands.report``
### List Reports
Description: Lists all active player reports.<br/>
Syntax: ``/Reports list``<br/>
Permission: ``fancycore.commands.reports.list``
### View Report Details
Description: Views details of a specific report.<br/>
Syntax: ``/Reports view (reportID)``<br/>
Permission: ``fancycore.commands.reports.view``
### Close Report
Description: Closes a specific report.<br/>
Syntax: ``/Reports close (reportID)``<br/>
Permission: ``fancycore.commands.reports.close``
## Warn
### Warn a Player
Description: Issues a warning to a player.<br/>
Syntax: ``/Warn (player) [reason]``<br/>
Permission: ``fancycore.commands.warn``
## Mute
### Mute a Player
Description: Mutes a player, preventing them from sending chat messages.<br/>
Syntax: ``/Mute (player) [reason]``<br/>
Permission: ``fancycore.commands.mute``
### Temporary Mute a Player
Description: Temporarily mutes a player for a specified duration.<br/>
Syntax: ``/Tempmute (player) (duration) [reason]``<br/>
Permission: ``fancycore.commands.tempmute``
### Unmute a Player
Description: Unmutes a player.<br/>
Syntax: ``/Unmute (player)``<br/>
Permission: ``fancycore.commands.unmute``
## Kick
### Kick a Player
Description: Kicks a player from the server.<br/>
Syntax: ``/Kick (player) [reason]``<br/>
Permission: ``fancycore.commands.kick``
## Ban
### Ban a Player
Description: Bans a player from the server.<br/>
Syntax: ``/Ban (player) [reason]``<br/>
Permission: ``fancycore.commands.ban``
### Temporary Ban a Player
Description: Temporarily bans a player from the server for a specified duration.<br/>
Syntax: ``/Tempban (player) (duration) [reason]``<br/>
Permission: ``fancycore.commands.tempban``
### Unban a Player
Description: Unbans a player from the server.<br/>
Syntax: ``/Unban (player)``<br/>
Permission: ``fancycore.commands.unban``
## Logs
### View Moderation Logs
Description: Views the moderation logs.<br/>
Syntax: ``/Modlogs [player]``<br/>
Permission: ``fancycore.commands.modlogs``
### View Chat Logs
Description: Views the chat logs.<br/>
Syntax: ``/Chatlogs [player] [--withCommands]``<br/>
Permission: ``fancycore.commands.chatlogs``

View File

@@ -0,0 +1,107 @@
---
icon: dot
title: Permissions
---
![](../../static/commands.png)
# Commands for the permissions system
!!!warning
The command list is not complete and not all commands are properly documented yet.
Some commands might not be implemented yet.
!!!
## Groups
### Create Group
Description: Creates a new group with the specified name.<br/>
Syntax: ``/Groups create (name)``<br/>
Permission: ``fancycore.commands.creategroup``
### Delete Group
Description: Deletes the specified permission group.<br/>
Syntax: ``/Groups delete (name)``<br/>
Permission: ``fancycore.commands.deletegroup``
### List Groups
Description: Lists all available permission groups.<br/>
Syntax: ``/Groups list``<br/>
Permission: ``fancycore.commands.listgroups``
### Info Group
Description: Displays information about the specified permission group.<br/>
Syntax: ``/Groups info (name)``<br/>
Permission: ``fancycore.commands.infogroup``
### Set Parent Group
Description: Sets the parent group for the specified permission group.<br/>
Syntax: ``/Groups parent (group) set (parent)``<br/>
Permission: ``fancycore.commands.setparentgroup``
### Add Permission to Group
Description: Adds the specified permission to the permission group.<br/>
Syntax: ``/Groups permission (group) add (permission)``<br/>
Permission: ``fancycore.commands.addpermtogroup``
### Remove Permission from Group
Description: Removes the specified permission from the permission group.<br/>
Syntax: ``/Groups permission (group) remove (permission)``<br/>
Permission: ``fancycore.commands.removepermfromgroup``
### Set Prefix for Group
Description: Sets the prefix for the specified permission group.<br/>
Syntax: ``/Groups prefix (group) set (prefix)``<br/>
Permission: ``fancycore.commands.setprefixforgroup``
### Set Suffix for Group
Description: Sets the suffix for the specified permission group.<br/>
Syntax: ``/Groups suffix (group) set (suffix)``<br/>
Permission: ``fancycore.commands.setsuffixforgroup``
### Add Player to Group
Description: Adds the specified player to the permission group.<br/>
Syntax: ``/Groups player (player) add (group)``<br/>
Permission: ``fancycore.commands.addplayertogroup``
### Remove Player from Group
Description: Removes the specified player from the permission group.<br/>
Syntax: ``/Groups player (player) remove (group)``<br/>
Permission: ``fancycore.commands.removeplayerfromgroup``
## Player Permissions
### Add Permission to Player
Description: Adds the specified permission to the targeted player.<br/>
Syntax: ``/Permission add (permission) [player]``<br/>
Permission: ``fancycore.commands.addpermtoplayer``
### Remove Permission from Player
Description: Removes the specified permission from the targeted player.<br/>
Syntax: ``/Permission remove (permission) [player]``<br/>
Permission: ``fancycore.commands.removepermfromplayer``
### Check Player Permission
Description: Checks if the targeted player has the specified permission.<br/>
Syntax: ``/Permission check (permission) [player]``<br/>
Permission: ``fancycore.commands.checkplayerperm``
### List Player Permissions
Description: Lists all permissions of the targeted player.<br/>
Syntax: ``/Permission list [player]``<br/>
Permission: ``fancycore.commands.listplayerperms``

View File

@@ -0,0 +1,91 @@
---
icon: dot
title: Player
---
![](../../static/commands.png)
# Commands for the player system
!!!warning
The command list is not complete and not all commands are properly documented yet.
Some commands might not be implemented yet.
!!!
### Gamemode
Description: Changes the gamemode of a player.<br/>
Syntax: ``/Gamemode (gamemode) [player]`` or ``/GM (gamemode)``<br/>
Permission: ``fancycore.commands.gamemode``
### Gamemode explorer
Description: Changes the gamemode of a player to explorer mode.<br/>
Syntax: ``/gme [player]``<br/>
Permission: ``fancycore.commands.gamemode``
### Gamemode creative
Description: Changes the gamemode of a player to creative mode.<br/>
Syntax: ``/gmc [player]``<br/>
Permission: ``fancycore.commands.gamemode``
### Fly
Description: Toggles fly mode for a player.<br/>
Syntax: ``/Fly [player]``<br/>
Permission: ``fancycore.commands.fly``
### Speed
Description: Sets the walk and fly speed of a player.<br/>
Syntax: ``/Speed (speed) [player]``<br/>
Permission: ``fancycore.commands.speed``
### Heal
Description: Heals a player to full health.<br/>
Syntax: ``/Heal [player]``<br/>
Permission: ``fancycore.commands.heal``
### Feed
Description: Feeds a player to full hunger.<br/>
Syntax: ``/Feed [player]``<br/>
Permission: ``fancycore.commands.feed``
### God mode
Description: Toggles god mode for a player.<br/>
Syntax: ``/God [player]``<br/>
Permission: ``fancycore.commands.god``
### Vanish
Description: Toggles vanish mode for a player.<br/>
Syntax: ``/Vanish [player]``<br/>
Permission: ``fancycore.commands.vanish``
### Playtime
Description: Displays the playtime of a player.<br/>
Syntax: ``/Playtime [player]``<br/>
Permission: ``fancycore.commands.playtime``
### Seen
Description: Displays the last seen time of a player.<br/>
Syntax: ``/Seen (player)``<br/>
Permission: ``fancycore.commands.seen``
### Near
Description: Lists players near the command sender within a specified radius.<br/>
Syntax: ``/Near [radius]``<br/>
Permission: ``fancycore.commands.near``
### Ping
Description: Displays the ping of a player.<br/>
Syntax: ``/Ping [player]``<br/>
Permission: ``fancycore.commands.ping``

View File

@@ -0,0 +1,91 @@
---
icon: dot
title: Server
---
![](../../static/commands.png)
# Commands for the server system
!!!warning
The command list is not complete and not all commands are properly documented yet.
Some commands might not be implemented yet.
!!!
## Server control
### Restart
Description: Restarts the server after a specified delay.<br/>
Syntax: ``/Restart (delay)``<br/>
Permission: ``fancycore.commands.restart``
### Stop
Description: Stops the server after a specified delay.<br/>
Syntax: ``/Stop (delay)``<br/>
Permission: ``fancycore.commands.stop``
### Save All
Description: Forces the server to save all data immediately.<br/>
Syntax: ``/SaveAll``<br/>
Permission: ``fancycore.commands.saveall``
## Server health
### Health
Description: Displays an overview of the server's health status.<br/>
Syntax: ``/Health``<br/>
Permission: ``fancycore.commands.health``
### TPS
Description: Displays the current ticks per second (TPS) of the server.<br/>
Syntax: ``/Health tps``<br/>
Permission: ``fancycore.commands.health.tps``
### Memory
Description: Displays the current memory usage of the server.<br/>
Syntax: ``/Health memory``<br/>
Permission: ``fancycore.commands.health.memory``
### Uptime
Description: Displays the server's uptime since the last restart.<br/>
Syntax: ``/Health uptime``<br/>
Permission: ``fancycore.commands.health.uptime``
### CPU Usage
Description: Displays the current CPU usage of the server.<br/>
Syntax: ``/Health cpu``<br/>
Permission: ``fancycore.commands.health.cpu``
### Entity Count
Description: Displays the total number of entities currently loaded on the server.<br/>
Syntax: ``/Health entities``<br/>
Permission: ``fancycore.commands.health.entities``
### Player Count
Description: Displays the current number of players online on the server.<br/>
Syntax: ``/Health players``<br/>
Permission: ``fancycore.commands.health.players``
## Players
### List online players
Description: Lists all players currently online on the server.<br/>
Syntax: ``/OnlinePlayers``<br/>
Permission: ``fancycore.commands.onlineplayers``
### List all registered players
Description: Lists all players registered on the server.<br/>
Syntax: ``/RegisteredPlayers``<br/>
Permission: ``fancycore.commands.registeredplayers``

View File

@@ -0,0 +1,129 @@
---
icon: dot
title: Teleportation
---
![](../../static/commands.png)
# Commands for the teleportation system
!!!warning
The command list is not complete and not all commands are properly documented yet.
Some commands might not be implemented yet.
!!!
## Player Teleportation
### Teleport to another player
Description: Teleports you or the specified player to another player's location.<br/>
Syntax: ``/TP (target player) [destination player]`` or ``/Teleport (target player) [destination player]``<br/>
Permission: ``fancycore.commands.tp``
### Teleport another player to you
Description: Teleports the specified player to your location.<br/>
Syntax: ``/TPHere (player)`` or ``/TeleportHere (player)``<br/>
Permission: ``fancycore.commands.tphere``
### Teleport all players to you
Description: Teleports all players on the server to your location.<br/>
Syntax: ``/TPAll`` or ``/TeleportAll``<br/>
Permission: ``fancycore.commands.tpall``
### Teleport to specific coordinates
Description: Teleports you to the specified coordinates<br/>
Syntax: ``/TPPos (x) (y) (z) [world]`` or ``/TeleportPos (x) (y) (z) [world]``<br/>
Permission: ``fancycore.commands.tppos``
### Request teleport to another player
Description: Sends a teleport request to another player to teleport to their location.<br/>
Syntax: ``/TPR (player)``, ``/TPRequest (player)`` or ``/TeleportRequest (player)``<br/>
Permission: ``fancycore.commands.tprequest``
### Accept teleport request
Description: Accepts a pending teleport request from another player.<br/>
Syntax: ``/TPA [player]``, ``/TPAccept [player]`` or ``/TeleportAccept [player]``<br/>
Permission: ``fancycore.commands.tpaccept``
### Deny teleport request
Description: Denies a pending teleport request from another player.<br/>
Syntax: ``/TPD [player]``, ``/TPDeny [player]`` or ``/TeleportDeny [player]``<br/>
Permission: ``fancycore.commands.tpdeny``
### Teleport back to previous location
Description: Teleports you back to your previous location before your last teleport.<br/>
Syntax: ``/Back``<br/>
Permission: ``fancycore.commands.back``
### Teleport to last death location
Description: Teleports you to the location where you last died.<br/>
Syntax: ``/DeathBack``, ``/DeathTP`` or ``/DeathTeleport``<br/>
Permission: ``fancycore.commands.deathback``
## Spawn
### Set spawn point
Description: Sets the server's spawn point to your current location.<br/>
Syntax: ``/SetSpawn``<br/>
Permission: ``fancycore.commands.setspawn``
### Teleport to spawn point
Description: Teleports you to the server's spawn point.<br/>
Syntax: ``/Spawn``<br/>
Permission: ``fancycore.commands.spawn``
## Warps
### Create a warp point
Description: Creates a warp point at your current location with the specified name.<br/>
Syntax: ``/CreateWarp (name)``<br/>
Permission: ``fancycore.commands.createwarp``
### Delete a warp point
Description: Deletes the warp point with the specified name.<br/>
Syntax: ``/DeleteWarp (name)``<br/>
Permission: ``fancycore.commands.deletewarp``
### Teleport to a warp point
Description: Teleports you to the warp point with the specified name.<br/>
Syntax: ``/Warp (name)``<br/>
Permission: ``fancycore.commands.warp.(name)``
### List all warp points
Description: Lists all available warp points on the server.<br/>
Syntax: ``/ListWarps``, ``/Warps``<br/>
Permission: ``fancycore.commands.listwarps``
## Homes
### Set home point
Description: Sets your home point to your current location.<br/>
Syntax: ``/SetHome (name)``<br/>
Permission: ``fancycore.commands.sethome``
### Delete home point
Description: Deletes your home point with the specified name.<br/>
Syntax: ``/DeleteHome (name)``<br/>
Permission: ``fancycore.commands.deletehome``
### Teleport to home point
Description: Teleports you to your home point with the specified name or the first home if no name is provided.<br/>
Syntax: ``/Home [name]``<br/>
Permission: ``fancycore.commands.home``

View File

@@ -0,0 +1,59 @@
---
icon: dot
title: World
---
![](../../static/commands.png)
# Commands for the world management system
!!!warning
The command list is not complete and not all commands are properly documented yet.
Some commands might not be implemented yet.
!!!
## World Management
### Create a new world
Description: Creates a new world with the specified name.<br/>
Syntax: ``/CreateWorld (world name) [type]``<br/>
Permission: ``fancycore.commands.createworld``
### Copy an existing world
Description: Creates a copy of the specified world.<br/>
Syntax: ``/CopyWorld (source world name) (new world name)``<br/>
Permission: ``fancycore.commands.copyworld``
### Delete an existing world
Description: Deletes the specified world from the server.<br/>
Syntax: ``/DeleteWorld (world name)``<br/>
Permission: ``fancycore.commands.deleteworld``
### List all worlds
Description: Lists all available worlds on the server.<br/>
Syntax: ``/ListWorlds``, ``/Worlds``<br/>
Permission: ``fancycore.commands.listworlds``
### Teleport to a world
Description: Teleports you to the specified world.<br/>
Syntax: ``/World (world name)``<br/>
Permission: ``fancycore.commands.world``
## Utility Commands
### Set weather
Description: Sets the weather in the current world.<br/>
Syntax: ``/SetWeather (sun|rain)``<br/>
Permission: ``fancycore.commands.setweather``
### Set time
Description: Sets the time of day in the current world.<br/>
Syntax: ``/SetTime (time)``<br/>
Permission: ``fancycore.commands.settime``

View File

@@ -0,0 +1,33 @@
---
title: FancyCore [Hytale]
icon: package
order: 90
---
#
![](../static/logos-and-banners/fancycore-banner.png)
!!!
Essential features every Hytale server needs. From permission management over world management to economy and more.
!!!
## Features
With FancyCore, you get a wide variety of features that are essential for running a Hytale server:
- **Permissions**: permission management system to control access to commands and features
- **Economy**: robust economy system with virtual currency, shops, and trading
- **Chat**: advanced chat management with channels, formatting, nicknames and msgs
- **Moderation**: tools for server admins including bans, kicks, warnings, and logs
- **World**: create and manage multiple worlds with different settings and environments
- **Inventory**: manage player inventories, kits and player backpacks
- **Teleportation**: spawn point, warps, player homes, and teleport requests
- **Player**: utility commands such as fly, speed, gamemode, heal, and more
- **Server**: view server stats and manage plugins
- **API**: comprehensive API for developers to extend and customize FancyCore
- **And much more!**
FancyCore is designed to provide all the essential features needed to build a successful Hytale server, while being easy to use and highly customizable.
We are trying to get a usable version out as soon as possible.
If you don't want to miss any updates, join our [Discord](https://discord.gg/ZUgYCEJUEx) and assign yourself the "FancyCore" role.

10
docs/src/fancycore/faq.md Normal file
View File

@@ -0,0 +1,10 @@
---
order: 6
icon: book
---
# FAQ
### Is FancyCore available for Minecraft?
No, FancyCore is a Hytale only plugin. There are no plans to make it available for Minecraft at this time.

View File

@@ -0,0 +1,29 @@
---
order: 10
icon: info
---
# Getting started
!!!danger
Be aware that this plugin is only made for Hytale servers. Only the latest version of Hytale is supported.
!!!
## Installation
To install FancyCore, you need to download the latest version from one of the following sources:
[!button size="s" icon="download" iconAlign="left" text="SOON" target="blank"]()
!!!warning
It's not yet decided on which platforms FancyCore will be available.
You keep an eye on the discord server for updates: [FancyInnovations Discord](https://discord.gg/ZUgYCEJUEx)
!!!
After downloading the plugin, you can install it by placing the downloaded file in the `plugins` folder of your server.
Restart your server and you are ready to go!
To check if the plugin is installed correctly, you can use the command `/fancycore version`. If the plugin is installed correctly, it will show you the version of the plugin.
You can now learn more about the commands in the `Commands` section of the documentation or learn how to configure the plugin in the `Tutorials` section.
The API documentation can be found in the `Api` section.

View File

@@ -0,0 +1,14 @@
---
order: 8
icon: paste
---
# Placeholders
FancyCore provides a set of built-in placeholders that can be used in various parts of the system.
You can use placeholders in almost any text field within FancyCore.
FancyCore also offers an API for creating and parse placeholders programmatically, read more about it in the [API documentation](../api/placeholders.md).
## Built-in Placeholders
* [Player related placeholders](player.md)

View File

@@ -0,0 +1,19 @@
---
icon: dot
title: Player
---
# Player placeholders
| Name | Identfier | Description | Examples outputs |
|------------------------------------------|---------------------------|------------------------------------------------------------|----------------------------------------|
| Player balance (formatted) | `player_balance` | Displays the player's current balance (formatted) | "0", "123", "123.45", "13,123.97" |
| Player balance (raw) | `player_balance_raw` | Displays the player's current balance (raw) | "0", "123", "123.45", "13123.9417" |
| Player chat color (hex) | `player_chat_color` | Displays the player's chat color in hex format | "#FF0000", "#00FF00", "#0000FF" |
| Player first time joined | `player_first_joined` | Displays the date and time the player first joined | "2023-01-01 12:00:00" |
| Player first time joined (raw timestamp) | `player_first_joined_raw` | Displays the raw timestamp of when the player first joined | "1672531200" |
| Player name | `player_name` | Displays the player's name | "Simon", "OliverHD" |
| Player nickname | `player_nickname` | Displays the player's nickname | "Oli" |
| Player play time (formatted) | `player_play_time` | Displays the player's total play time (formatted) | "0s", "5m 30s", "2h 15m" |
| Player play time (ms) | `player_play_time_ms` | Displays the player's total play time in milliseconds | "0", "330000", "8100000" |
| Player UUID | `player_uuid` | Displays the player's UUID | "9b605d04-5a59-4353-bba3-2ddf570eb38a" |

View File

@@ -0,0 +1,2 @@
order: 7
icon: mortar-board

View File

@@ -0,0 +1,23 @@
---
icon: dot
order: 2
---
![](../../static/changelog_v1_x_x.png)
#
## v1.0.1 [!badge variant="info" text="2025-11-23"] [!badge variant="danger" text="Hotfix"]
- Fixed player kick issue when no button or action is defined. ([#147](https://github.com/FancyInnovations/FancyPlugins/issues/147))
## v1.0.0 [!badge variant="info" text="2025-11-23"]
- Create dialogs using the [JSON schema](https://docs.fancyinnovations.com/fancydialogs/tutorials/json-schema/)
- PlaceholderAPI and MiniMessage support in dialog texts
- Execute actions when dialog buttons are clicked
- Open a dialog when the user joins the server for the first time (see `welcome_dialog_id` in the config)
- A quick actions dialog which can be opened with the `/qa` or `/quickactions` commands
- FancyNpcs ingegration to open dialogs when interacting with NPCs (see [docs](https://docs.fancyinnovations.com/fancydialogs/tutorials/open-dialog-npc-action/))
- API for other plugins to open dialogs (see [docs](https://docs.fancyinnovations.com/fancydialogs/api/getting-started/))

View File

@@ -71,7 +71,7 @@ Unregisters a dialog by its ID.
## Joined Players Cache ## Joined Players Cache
## Clear joined players cache ### Clear joined players cache
Clears the cache of players who have joined a dialog. Clears the cache of players who have joined a dialog.

View File

@@ -1,5 +1,5 @@
--- ---
title: FancyDialogs [WIP] title: FancyDialogs
icon: browser icon: browser
order: 90 order: 90
--- ---
@@ -21,11 +21,6 @@ FancyDialogs uses the new dialog feature, Minecraft introduced in **1.21.6** and
The plugin will only for **Paper** servers on **1.21.6** or newer! The plugin will only for **Paper** servers on **1.21.6** or newer!
!!! !!!
!!!warning
FancyDialogs is still in development and some features are not yet implemented.
See the [TODO](#todo) section for more information.
!!!
**Core advantages of FancyDialogs:** **Core advantages of FancyDialogs:**
- Simple custom dialog creation (in JSON format or in code) - Simple custom dialog creation (in JSON format or in code)
- A lot of different dialog components (text, buttons, input fields, etc.) - A lot of different dialog components (text, buttons, input fields, etc.)
@@ -52,17 +47,3 @@ Common use cases are:
- Confirmation dialogs for critical actions - Confirmation dialogs for critical actions
- Shop UIs (replacing inventories UIs) - Shop UIs (replacing inventories UIs)
- Dialogs for quests - Dialogs for quests
## TODO
- [X] Create dialogs in JSON format
- [X] Create dialogs in code
- [X] Customize dialog content and buttons
- [X] Open dialogs for players (via commands or code)
- [X] Welcome dialog for new players
- [X] FancyNpcs integration (open_dialog action)
- [X] Confirmation and notice dialogs (API)
- [x] Add button action system
- [ ] Add support for the quick action hotkey
- [ ] Add tutorial features
- [ ] Add input controls

View File

@@ -9,6 +9,10 @@ The following examples show how to use FancyDialogs in different ways. They are
Almost all examples are made by the community. If you have a nice example that you want to share, feel free come to our discord server and show it to us. Almost all examples are made by the community. If you have a nice example that you want to share, feel free come to our discord server and show it to us.
![Provided by reunionsmp.com](../static/fancydialogs/examples/reunionsmp-1.png)
![Provided by reunionsmp.com](../static/fancydialogs/examples/reunionsmp-2.png)
![Provided by oliver](../static/fancydialogs/examples/oliver-welcome_to_fd.png) ![Provided by oliver](../static/fancydialogs/examples/oliver-welcome_to_fd.png)
![Provided by oliver](../static/fancydialogs/examples/oliver-welcome.png) ![Provided by oliver](../static/fancydialogs/examples/oliver-welcome.png)

View File

@@ -1,6 +1,6 @@
--- ---
icon: dot icon: dot
order: 9 order: 7
--- ---
# Open dialog npc action # Open dialog npc action

View File

@@ -0,0 +1,13 @@
---
icon: dot
order: 8
---
# Quick actions
FancyDialogs doesn't support the quick-actions hotkey, but has a command to open a quick action dialog.
To open the quick actions dialog, use the command: `/qa` or `/quickactions`.
You can customize the quick actions dialog in the `plugins/FancyDialogs/data/dialogs/quick_actions.json` file.
If you want to disable the quick actions dialog, you can set the `disable-quick-actions-dialog` option to true in the `plugins/FancyDialogs/featureFlags.yml` file.

View File

@@ -0,0 +1,16 @@
---
icon: dot
order: 9
---
# Welcome dialog
You can configure a dialog to be shown to players when they join the server for the first time.
A default welcome dialog is included with FancyDialogs, but you can customize it or create your own welcome dialog.
You can find the default welcome dialog in the `plugins/FancyDialogs/data/dialogs/welcome.json` file.
Feel free to edit this file to customize the welcome dialog to your liking.
If you want to use another dialog as the welcome dialog, you can change the id in the `plugins/FancyDialogs/config.yml` file by changing the `welcome_dialog_id` option to the ID of your desired dialog.
To completely disable the welcome dialog, you can set the `disable-welcome-dialog` to true in the `plugins/FancyDialogs/featureFlags.yml` file.

View File

@@ -7,6 +7,17 @@ order: 2
# #
## v2.8.1 [!badge variant="info" text="2025-11-25"]
- Removed support for 1.19.4
- Fixed npcs randomly disappearing
- Fixed skin mirroring for 1.21.9
- Added inverted permission check for `need_permission` action (use prefix `!` to invert)
- Added `/npc rotate <npc> <yaw> <pitch>` command to set NPC orientation
- Added `swing_arm_on_update` config option
- Added `use-minecraft-usercache` feature flag
## v2.8.0 [!badge variant="info" text="2025-10-10"] ## v2.8.0 [!badge variant="info" text="2025-10-10"]
- Added support for 1.21.9 and 1.21.10 - Added support for 1.21.9 and 1.21.10

View File

@@ -177,6 +177,13 @@ Teleports NPC to specified location.
- **Syntax**: `/npc move_to (npc) (x) (y) (z) [world] [--look-in-my-direction]` - **Syntax**: `/npc move_to (npc) (x) (y) (z) [world] [--look-in-my-direction]`
- **Permissions**: `fancynpcs.command.npc.move_to` - **Permissions**: `fancynpcs.command.npc.move_to`
### Rotate npc
Sets the yaw and pitch of the specified NPC.
- **Syntax**: `/npc rotate (npc) (yaw) (pitch)`
- **Permissions**: `fancynpcs.command.npc.rotate`
### Center npc location ### Center npc location
Centers the NPC to the specified location. Centers the NPC to the specified location.

View File

@@ -122,6 +122,10 @@ Syntax: `need_permission (permission)`
Example: `/npc action (npc) (trigger) add need_permission my.cool.permission` Example: `/npc action (npc) (trigger) add need_permission my.cool.permission`
!!!info
If you add the `!` prefix to the permission, the action will be inverted. This means that the action list will be canceled if the player has the permission.
!!!
### play_sound ### play_sound
Plays a sound to the player. This action is useful for creating audio feedback for the player when interacting with the NPC. Plays a sound to the player. This action is useful for creating audio feedback for the player when interacting with the NPC.

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

View File

@@ -1,6 +1,5 @@
fancylibVersion=37 fancylibVersion=37
fancysitulaVersion=0.0.13 fancysitulaVersion=0.0.13
jdbVersion=1.0.1
plugintestsVersion=1.0.0 plugintestsVersion=1.0.0
org.gradle.parallel=false org.gradle.parallel=false
org.gradle.caching=true org.gradle.caching=true

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@@ -57,6 +57,13 @@ public class Translator {
} }
for (File langFile : langFiles) { for (File langFile : langFiles) {
if (!langFile.isFile()) {
continue;
}
if (!langFile.getName().endsWith(".yml")) {
continue;
}
languages.add(loadLanguageFile(langFile)); languages.add(loadLanguageFile(langFile));
} }

1
libraries/config/VERSION Normal file
View File

@@ -0,0 +1 @@
1.0.0

View File

@@ -14,7 +14,7 @@ repositories {
} }
dependencies { dependencies {
compileOnly("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT") compileOnly("io.papermc.paper:paper-api:1.20-R0.1-SNAPSHOT")
compileOnly("de.oliver.FancyAnalytics:logger:0.0.8") compileOnly("de.oliver.FancyAnalytics:logger:0.0.8")
compileOnly("org.jetbrains:annotations:26.0.2") compileOnly("org.jetbrains:annotations:26.0.2")
@@ -24,9 +24,41 @@ dependencies {
} }
tasks { tasks {
publishing {
repositories {
maven {
name = "fancyinnovationsReleases"
url = uri("https://repo.fancyinnovations.com/releases")
credentials(PasswordCredentials::class)
authentication {
isAllowInsecureProtocol = true
create<BasicAuthentication>("basic")
}
}
maven {
name = "fancyinnovationsSnapshots"
url = uri("https://repo.fancyinnovations.com/snapshots")
credentials(PasswordCredentials::class)
authentication {
isAllowInsecureProtocol = true
create<BasicAuthentication>("basic")
}
}
}
publications {
create<MavenPublication>("maven") {
groupId = "de.oliver"
artifactId = "config"
version = getCFGVersion()
from(project.components["java"])
}
}
}
compileJava { compileJava {
options.encoding = Charsets.UTF_8.name() options.encoding = Charsets.UTF_8.name()
options.release.set(21) options.release.set(17) //TODO change to 21, once 1.19.4 support is dropped
} }
java { java {
@@ -47,5 +79,9 @@ tasks {
} }
java { java {
toolchain.languageVersion.set(JavaLanguageVersion.of(21)) toolchain.languageVersion.set(JavaLanguageVersion.of(17)) //TODO change to 21, once 1.19.4 support is dropped
}
fun getCFGVersion(): String {
return file("VERSION").readText()
} }

View File

@@ -0,0 +1,233 @@
package com.fancyinnovations.config;
import com.google.gson.*;
import de.oliver.fancyanalytics.logger.ExtendedFancyLogger;
import de.oliver.fancyanalytics.logger.properties.ThrowableProperty;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ConfigJSON {
private final ExtendedFancyLogger logger;
private final File configFile;
private final Map<String, ConfigField<?>> fields;
private final Map<String, Object> values;
private final Gson gson;
public ConfigJSON(ExtendedFancyLogger logger, String configFilePath) {
this.logger = logger;
this.configFile = new File(configFilePath);
this.fields = new ConcurrentHashMap<>();
this.values = new ConcurrentHashMap<>();
this.gson = new GsonBuilder()
.serializeNulls()
.setPrettyPrinting()
.create();
}
public void addField(ConfigField<?> field) {
fields.put(field.path(), field);
}
public Map<String, ConfigField<?>> getFields() {
return fields;
}
public <T> T get(String path) {
ConfigField<?> field = fields.get(path);
if (field == null) {
return null;
}
if (field.forceDefault()) {
return (T) field.defaultValue();
}
Object value = values.computeIfAbsent(path, k -> field.defaultValue());
return (T) field.type().cast(value);
}
public void reload() {
if (!configFile.exists()) {
try {
File parent = configFile.getParentFile();
if (parent != null && !parent.exists()) {
parent.mkdirs();
}
if (!configFile.createNewFile()) {
logger.error("Failed to create config file: " + configFile.getAbsolutePath());
return;
}
} catch (IOException e) {
logger.error("Error creating config file: " + configFile.getAbsolutePath(), ThrowableProperty.of(e));
return;
}
JsonObject root = new JsonObject();
for (ConfigField<?> field : fields.values()) {
setDefault(root, field);
}
saveJson(root);
return;
}
JsonObject root;
try (FileReader reader = new FileReader(configFile)) {
JsonElement parsed = JsonParser.parseReader(reader);
if (parsed == null || !parsed.isJsonObject()) {
root = new JsonObject();
} else {
root = parsed.getAsJsonObject();
}
} catch (Exception e) {
logger.error("Error reading config file: " + configFile.getAbsolutePath(), ThrowableProperty.of(e));
root = new JsonObject();
}
boolean dirty = false;
for (Map.Entry<String, ConfigField<?>> entry : fields.entrySet()) {
String path = entry.getKey();
ConfigField<?> field = entry.getValue();
if (field.forRemoval()) {
if (isSet(root, path)) {
logger.debug("Removing path '" + path + "' from config");
removePath(root, path);
dirty = true;
}
continue;
}
JsonElement elem = getElement(root, path);
if (elem != null && !elem.isJsonNull()) {
try {
Object deserialized = gson.fromJson(elem, (Type) field.type());
if (deserialized != null && field.type().isInstance(deserialized)) {
values.put(path, deserialized);
} else {
// Attempt numeric conversions: gson may deserialize numbers as Double
Object converted = tryConvertNumber(deserialized, field.type());
if (converted != null) {
values.put(path, converted);
} else {
logger.warn("Value for path '" + path + "' is not of type '" + field.type().getSimpleName() + "'");
setDefault(root, field);
dirty = true;
}
}
} catch (JsonSyntaxException | ClassCastException ex) {
logger.warn("Failed to parse value for path '" + path + "': " + ex.getMessage());
setDefault(root, field);
dirty = true;
}
} else {
logger.debug("Path '" + path + "' not found in config");
setDefault(root, field);
dirty = true;
}
}
if (dirty) {
saveJson(root);
}
}
private void setDefault(JsonObject root, ConfigField<?> field) {
logger.debug("Setting default value for path '" + field.path() + "': " + field.defaultValue());
JsonElement elem = gson.toJsonTree(field.defaultValue(), (Type) field.type());
setElement(root, field.path(), elem);
// JSON does not support inline comments; descriptions are not stored.
}
private void saveJson(JsonObject root) {
try (FileWriter writer = new FileWriter(configFile)) {
gson.toJson(root, writer);
} catch (IOException e) {
logger.error("Error saving config file: " + configFile.getAbsolutePath(), ThrowableProperty.of(e));
}
}
/**
* Utility: get JsonElement at dot-separated path, or null if absent
*/
private JsonElement getElement(JsonObject root, String path) {
String[] parts = path.split("\\.");
JsonElement current = root;
for (String p : parts) {
if (!current.isJsonObject()) return null;
JsonObject obj = current.getAsJsonObject();
if (!obj.has(p)) return null;
current = obj.get(p);
}
return current;
}
/**
* Utility: set JsonElement at dot-separated path, creating intermediate objects
*/
private void setElement(JsonObject root, String path, JsonElement value) {
String[] parts = path.split("\\.");
JsonObject current = root;
for (int i = 0; i < parts.length - 1; i++) {
String p = parts[i];
if (!current.has(p) || !current.get(p).isJsonObject()) {
JsonObject child = new JsonObject();
current.add(p, child);
current = child;
} else {
current = current.getAsJsonObject(p);
}
}
current.add(parts[parts.length - 1], value);
}
private boolean isSet(JsonObject root, String path) {
return getElement(root, path) != null;
}
/**
* Remove a path (dot-separated) from the JSON object
*/
private void removePath(JsonObject root, String path) {
String[] parts = path.split("\\.");
JsonObject current = root;
for (int i = 0; i < parts.length - 1; i++) {
String p = parts[i];
if (!current.has(p) || !current.get(p).isJsonObject()) {
return;
}
current = current.getAsJsonObject(p);
}
current.remove(parts[parts.length - 1]);
}
/**
* Try to convert numeric values (e.g., Double) to the requested numeric target type
*/
private Object tryConvertNumber(Object value, Class<?> target) {
if (!(value instanceof Number)) return null;
Number num = (Number) value;
if (target == Integer.class || target == int.class) {
return num.intValue();
} else if (target == Long.class || target == long.class) {
return num.longValue();
} else if (target == Double.class || target == double.class) {
return num.doubleValue();
} else if (target == Float.class || target == float.class) {
return num.floatValue();
} else if (target == Short.class || target == short.class) {
return num.shortValue();
} else if (target == Byte.class || target == byte.class) {
return num.byteValue();
}
return null;
}
}

1
libraries/jdb/VERSION Normal file
View File

@@ -0,0 +1 @@
1.0.4

View File

@@ -1,11 +1,11 @@
plugins { plugins {
id("java") id("java")
id("maven-publish") id("maven-publish")
id("com.github.johnrengelman.shadow") id("com.gradleup.shadow")
} }
group = "de.oliver" group = "de.oliver"
version = findProperty("jdbVersion") as String version = getJDBVersion()
description = "Library for storing JSON data locally" description = "Library for storing JSON data locally"
java { java {
@@ -55,7 +55,7 @@ tasks {
create<MavenPublication>("maven") { create<MavenPublication>("maven") {
groupId = "de.oliver" groupId = "de.oliver"
artifactId = "JDB" artifactId = "JDB"
version = findProperty("jdbVersion") as String version = getJDBVersion()
from(project.components["java"]) from(project.components["java"])
} }
} }
@@ -85,3 +85,7 @@ tasks {
useJUnitPlatform() useJUnitPlatform()
} }
} }
fun getJDBVersion(): String {
return file("VERSION").readText()
}

View File

@@ -9,6 +9,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -16,7 +17,7 @@ import java.util.Map;
* The JDB class provides a simple JSON document-based storage system in a specified directory. * The JDB class provides a simple JSON document-based storage system in a specified directory.
*/ */
public class JDB { public class JDB {
private final static Gson GSON = new GsonBuilder() public final static Gson GSON = new GsonBuilder()
.setPrettyPrinting() .setPrettyPrinting()
.disableHtmlEscaping() .disableHtmlEscaping()
.create(); .create();
@@ -24,6 +25,7 @@ public class JDB {
private static final String FILE_EXTENSION = ".json"; private static final String FILE_EXTENSION = ".json";
private final @NotNull String basePath; private final @NotNull String basePath;
private final @NotNull File baseDirectory; private final @NotNull File baseDirectory;
private final JIndex index;
/** /**
* Constructs a new JDB instance with the specified base path. * Constructs a new JDB instance with the specified base path.
@@ -33,6 +35,8 @@ public class JDB {
public JDB(@NotNull String basePath) { public JDB(@NotNull String basePath) {
this.basePath = basePath; this.basePath = basePath;
this.baseDirectory = new File(basePath); this.baseDirectory = new File(basePath);
this.index = JIndex.load("jdb_index", basePath);
} }
/** /**
@@ -47,6 +51,13 @@ public class JDB {
public <T> T get(@NotNull String path, @NotNull Class<T> clazz) throws IOException { public <T> T get(@NotNull String path, @NotNull Class<T> clazz) throws IOException {
File documentFile = new File(baseDirectory, createFilePath(path)); File documentFile = new File(baseDirectory, createFilePath(path));
if (!documentFile.exists()) { if (!documentFile.exists()) {
// Check index for alternative path
if (index.indexMap().containsKey(path)) {
String indexPath = index.indexMap().get(path);
return get(indexPath, clazz);
}
return null; return null;
} }
BufferedReader bufferedReader = Files.newBufferedReader(documentFile.toPath()); BufferedReader bufferedReader = Files.newBufferedReader(documentFile.toPath());
@@ -95,6 +106,26 @@ public class JDB {
return documents; return documents;
} }
/**
* Counts the number of documents in the specified directory path.
*
* @param path the relative directory path
* @return the number of documents in the directory
*/
public int countDocuments(@NotNull String path) {
File directory = new File(baseDirectory, path);
if (!directory.exists()) {
return 0;
}
File[] files = directory.listFiles();
if (files == null) {
return 0;
}
return files.length;
}
/** /**
* Saves the given value as a document at the specified path. * Saves the given value as a document at the specified path.
* *
@@ -113,12 +144,40 @@ public class JDB {
Files.write(documentFile.toPath(), json.getBytes()); Files.write(documentFile.toPath(), json.getBytes());
} }
/**
* Saves the given value as a document at the specified path and indexes it under additional paths.
*/
public <T> void set(@NotNull String path, @NotNull T value, String... indexPaths) throws IOException {
set(path, value);
for (String indexPath : indexPaths) {
indexDocument(indexPath, path);
}
}
/**
* Indexes a document by mapping the original path to the index path.
*
* @param originalPath the original relative path (excluding .json extension) of the document
* @param indexPath the index relative path (excluding .json extension) to map to the original document
*/
public void indexDocument(@NotNull String originalPath, @NotNull String indexPath) {
index.indexMap().put(originalPath, indexPath);
index.save();
}
/** /**
* Deletes the document(s) at the specified path. * Deletes the document(s) at the specified path.
* *
* @param path the relative path (excluding .json extension) of the document(s) to be deleted * @param path the relative path (excluding .json extension) of the document(s) to be deleted
*/ */
public void delete(@NotNull String path) { public void delete(@NotNull String path) {
for (Map.Entry<String, String> entry : new HashSet<>(index.indexMap().entrySet())) {
if (entry.getKey().equals(path) || entry.getValue().equals(path)) {
index.indexMap().remove(entry.getKey());
index.save();
}
}
File file = new File(baseDirectory, path); File file = new File(baseDirectory, path);
if (file.isDirectory()) { if (file.isDirectory()) {
deleteDirectory(file); deleteDirectory(file);

View File

@@ -0,0 +1,41 @@
package de.oliver.jdb;
import com.google.gson.annotations.SerializedName;
import java.io.File;
import java.nio.file.Files;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public record JIndex(
String name,
@SerializedName("base_path") String basePath,
@SerializedName("index_map") Map<String, String> indexMap // key -> original path
) {
public static JIndex load(String name, String basePath) {
File indexFile = new File(basePath, name + ".json");
if (!indexFile.exists()) {
return new JIndex(name, basePath, new ConcurrentHashMap<>());
}
try (var reader = Files.newBufferedReader(indexFile.toPath())) {
return JDB.GSON.fromJson(reader, JIndex.class);
} catch (Exception e) {
e.printStackTrace();
return new JIndex(name, basePath, new ConcurrentHashMap<>());
}
}
public void save() {
File indexFile = new File(basePath, name + ".json");
String json = JDB.GSON.toJson(this);
try {
Files.write(indexFile.toPath(), json.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -110,6 +110,23 @@ public class JDBTest {
assertTrue(result.isEmpty()); assertTrue(result.isEmpty());
} }
@Test
public void testCountDocuments() throws IOException {
// Prepare
String basePath = "./test_files/";
JDB jdb = new JDB(basePath);
String path = "test_files";
jdb.set(path + "/obj1", "Test message 1");
jdb.set(path + "/obj2", "Test message 2");
jdb.set(path + "/obj3", "Test message 3");
// Act
int count = jdb.countDocuments(path);
// Assert
assertEquals(3, count);
}
@Test @Test
public void testSetNewObject() throws IOException { public void testSetNewObject() throws IOException {
// Prepare // Prepare

View File

@@ -21,6 +21,7 @@ dependencies {
compileOnly("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT") compileOnly("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
implementation(project(":libraries:packets:packets-api")) implementation(project(":libraries:packets:packets-api"))
implementation(project(":libraries:packets:implementations:1_21_11"))
implementation(project(":libraries:packets:implementations:1_21_9")) implementation(project(":libraries:packets:implementations:1_21_9"))
implementation(project(":libraries:packets:implementations:1_21_6")) implementation(project(":libraries:packets:implementations:1_21_6"))
implementation(project(":libraries:packets:implementations:1_21_5")) implementation(project(":libraries:packets:implementations:1_21_5"))

View File

@@ -0,0 +1,23 @@
plugins {
id("java-library")
id("io.papermc.paperweight.userdev")
}
paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.MOJANG_PRODUCTION
dependencies {
paperweight.paperDevBundle("1.21.11-rc2-R0.1-SNAPSHOT")
compileOnly(project(":libraries:packets:packets-api"))
testImplementation(project(":libraries:packets"))
testImplementation(project(":libraries:packets:packets-api"))
testImplementation("org.junit.jupiter:junit-jupiter-api:5.12.2")
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.12.2")
testImplementation("org.junit.platform:junit-platform-console-standalone:1.12.2")
}
tasks {
test {
useJUnitPlatform()
}
}

View File

@@ -0,0 +1,48 @@
package de.oliver.fancysitula.versions.v1_21_11.packets;
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
import de.oliver.fancysitula.api.packets.FS_ClientboundAddEntityPacket;
import de.oliver.fancysitula.api.utils.AngelConverter;
import de.oliver.fancysitula.versions.v1_21_11.utils.VanillaPlayerAdapter;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.phys.Vec3;
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.entity.EntityType;
import java.util.UUID;
public class ClientboundAddEntityPacketImpl extends FS_ClientboundAddEntityPacket {
public ClientboundAddEntityPacketImpl(int entityId, UUID entityUUID, EntityType entityType, double x, double y, double z, float yaw, float pitch, float headYaw, int velocityX, int velocityY, int velocityZ, int data) {
super(entityId, entityUUID, entityType, x, y, z, yaw, pitch, headYaw, velocityX, velocityY, velocityZ, data);
}
@Override
public Object createPacket() {
net.minecraft.world.entity.EntityType<?> vanillaType = BuiltInRegistries.ENTITY_TYPE.getValue(CraftNamespacedKey.toMinecraft(entityType.getKey()));
return new ClientboundAddEntityPacket(
entityId,
entityUUID,
x,
y,
z,
AngelConverter.degreesToVanillaByte(pitch),
AngelConverter.degreesToVanillaByte(yaw),
vanillaType,
data,
new Vec3(velocityX, velocityY, velocityZ),
AngelConverter.degreesToVanillaByte(headYaw)
);
}
@Override
public void sendPacketTo(FS_RealPlayer player) {
ClientboundAddEntityPacket packet = (ClientboundAddEntityPacket) createPacket();
ServerPlayer vanillaPlayer = VanillaPlayerAdapter.asVanilla(player.getBukkitPlayer());
vanillaPlayer.connection.send(packet);
}
}

View File

@@ -0,0 +1,22 @@
package de.oliver.fancysitula.versions.v1_21_11.packets;
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
import de.oliver.fancysitula.api.packets.FS_ClientboundClearDialogPacket;
import de.oliver.fancysitula.versions.v1_21_11.utils.VanillaPlayerAdapter;
import net.minecraft.network.protocol.common.ClientboundClearDialogPacket;
import net.minecraft.server.level.ServerPlayer;
public class ClientboundClearDialogPacketImpl extends FS_ClientboundClearDialogPacket {
@Override
public Object createPacket() {
return ClientboundClearDialogPacket.INSTANCE;
}
@Override
protected void sendPacketTo(FS_RealPlayer player) {
ClientboundClearDialogPacket packet = (ClientboundClearDialogPacket) createPacket();
ServerPlayer vanillaPlayer = VanillaPlayerAdapter.asVanilla(player.getBukkitPlayer());
vanillaPlayer.connection.send(packet);
}
}

View File

@@ -0,0 +1,128 @@
package de.oliver.fancysitula.versions.v1_21_11.packets;
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
import de.oliver.fancysitula.api.packets.FS_ClientboundCreateOrUpdateTeamPacket;
import de.oliver.fancysitula.versions.v1_21_11.utils.VanillaPlayerAdapter;
import io.papermc.paper.adventure.PaperAdventure;
import net.minecraft.ChatFormatting;
import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.scores.PlayerTeam;
import net.minecraft.world.scores.Scoreboard;
import net.minecraft.world.scores.Team;
public class ClientboundCreateOrUpdateTeamPacketImpl extends FS_ClientboundCreateOrUpdateTeamPacket {
private static final Scoreboard SCOREBOARD = new Scoreboard();
public ClientboundCreateOrUpdateTeamPacketImpl(String teamName, CreateTeam createTeam) {
super(teamName, createTeam);
}
public ClientboundCreateOrUpdateTeamPacketImpl(String teamName, RemoveTeam removeTeam) {
super(teamName, removeTeam);
}
public ClientboundCreateOrUpdateTeamPacketImpl(String teamName, UpdateTeam updateTeam) {
super(teamName, updateTeam);
}
public ClientboundCreateOrUpdateTeamPacketImpl(String teamName, AddEntity addEntity) {
super(teamName, addEntity);
}
public ClientboundCreateOrUpdateTeamPacketImpl(String teamName, RemoveEntity removeEntity) {
super(teamName, removeEntity);
}
@Override
public Object createPacket() {
return switch (method) {
case CREATE_TEAM -> createCreateTeamPacket();
case REMOVE_TEAM -> createRemoveTeamPacket();
case UPDATE_TEAM -> createUpdateTeamPacket();
case ADD_ENTITY -> createAddEntityPacket();
case REMOVE_ENTITY -> createRemoveEntityPacket();
};
}
private Object createCreateTeamPacket() {
if (createTeam == null) {
return null;
}
PlayerTeam playerTeam = new PlayerTeam(SCOREBOARD, teamName);
playerTeam.setDisplayName(PaperAdventure.asVanilla(createTeam.getDisplayName()));
playerTeam.setAllowFriendlyFire(createTeam.isAllowFriendlyFire());
playerTeam.setSeeFriendlyInvisibles(createTeam.isCanSeeFriendlyInvisibles());
playerTeam.setNameTagVisibility(Team.Visibility.valueOf(createTeam.getNameTagVisibility().getName()));
playerTeam.setCollisionRule(PlayerTeam.CollisionRule.valueOf(createTeam.getCollisionRule().getName()));
playerTeam.setColor(ChatFormatting.getById(createTeam.getColor().getId()));
playerTeam.setPlayerPrefix(PaperAdventure.asVanilla(createTeam.getPrefix()));
playerTeam.setPlayerSuffix(PaperAdventure.asVanilla(createTeam.getSuffix()));
for (String entity : createTeam.getEntities()) {
playerTeam.getPlayers().add(entity);
}
return ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(playerTeam, true);
}
private Object createRemoveTeamPacket() {
if (removeTeam == null) {
return null;
}
PlayerTeam playerTeam = new PlayerTeam(SCOREBOARD, teamName);
return ClientboundSetPlayerTeamPacket.createRemovePacket(playerTeam);
}
private Object createUpdateTeamPacket() {
if (updateTeam == null) {
return null;
}
PlayerTeam playerTeam = new PlayerTeam(SCOREBOARD, teamName);
playerTeam.setDisplayName(PaperAdventure.asVanilla(updateTeam.getDisplayName()));
playerTeam.setAllowFriendlyFire(updateTeam.isAllowFriendlyFire());
playerTeam.setSeeFriendlyInvisibles(updateTeam.isCanSeeFriendlyInvisibles());
playerTeam.setNameTagVisibility(Team.Visibility.valueOf(updateTeam.getNameTagVisibility().getName()));
playerTeam.setCollisionRule(PlayerTeam.CollisionRule.valueOf(updateTeam.getCollisionRule().getName()));
playerTeam.setColor(ChatFormatting.getById(updateTeam.getColor().getId()));
playerTeam.setPlayerPrefix(PaperAdventure.asVanilla(updateTeam.getPrefix()));
playerTeam.setPlayerSuffix(PaperAdventure.asVanilla(updateTeam.getSuffix()));
return ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(playerTeam, true);
}
private Object createAddEntityPacket() {
if (addEntity == null) {
return null;
}
PlayerTeam playerTeam = new PlayerTeam(SCOREBOARD, teamName);
for (String entity : addEntity.getEntities()) {
playerTeam.getPlayers().add(entity);
}
return ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket(playerTeam, addEntity.getEntities(), ClientboundSetPlayerTeamPacket.Action.ADD);
}
private Object createRemoveEntityPacket() {
if (removeEntity == null) {
return null;
}
PlayerTeam playerTeam = new PlayerTeam(SCOREBOARD, teamName);
for (String entity : removeEntity.getEntities()) {
playerTeam.getPlayers().add(entity);
}
return ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket(playerTeam, removeEntity.getEntities(), ClientboundSetPlayerTeamPacket.Action.REMOVE);
}
@Override
protected void sendPacketTo(FS_RealPlayer player) {
ClientboundSetPlayerTeamPacket packet = (ClientboundSetPlayerTeamPacket) createPacket();
ServerPlayer vanillaPlayer = VanillaPlayerAdapter.asVanilla(player.getBukkitPlayer());
vanillaPlayer.connection.send(packet);
}
}

View File

@@ -0,0 +1,30 @@
package de.oliver.fancysitula.versions.v1_21_11.packets;
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
import de.oliver.fancysitula.api.packets.FS_ClientboundPlayerInfoRemovePacket;
import de.oliver.fancysitula.versions.v1_21_11.utils.VanillaPlayerAdapter;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
import net.minecraft.server.level.ServerPlayer;
import java.util.List;
import java.util.UUID;
public class ClientboundPlayerInfoRemovePacketImpl extends FS_ClientboundPlayerInfoRemovePacket {
public ClientboundPlayerInfoRemovePacketImpl(List<UUID> uuids) {
super(uuids);
}
@Override
public Object createPacket() {
return new ClientboundPlayerInfoRemovePacket(uuids);
}
@Override
public void sendPacketTo(FS_RealPlayer player) {
ClientboundPlayerInfoRemovePacket packet = (ClientboundPlayerInfoRemovePacket) createPacket();
ServerPlayer vanillaPlayer = VanillaPlayerAdapter.asVanilla(player.getBukkitPlayer());
vanillaPlayer.connection.send(packet);
}
}

View File

@@ -0,0 +1,54 @@
package de.oliver.fancysitula.versions.v1_21_11.packets;
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
import de.oliver.fancysitula.api.packets.FS_ClientboundPlayerInfoUpdatePacket;
import de.oliver.fancysitula.versions.v1_21_11.utils.GameProfileImpl;
import de.oliver.fancysitula.versions.v1_21_11.utils.VanillaPlayerAdapter;
import io.papermc.paper.adventure.PaperAdventure;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.GameType;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
public class ClientboundPlayerInfoUpdatePacketImpl extends FS_ClientboundPlayerInfoUpdatePacket {
public ClientboundPlayerInfoUpdatePacketImpl(EnumSet<Action> actions, List<Entry> entries) {
super(actions, entries);
}
@Override
public Object createPacket() {
EnumSet<ClientboundPlayerInfoUpdatePacket.Action> vanillaActions = EnumSet.noneOf(ClientboundPlayerInfoUpdatePacket.Action.class);
for (FS_ClientboundPlayerInfoUpdatePacket.Action action : actions) {
vanillaActions.add(ClientboundPlayerInfoUpdatePacket.Action.valueOf(action.name()));
}
List<ClientboundPlayerInfoUpdatePacket.Entry> entries = new ArrayList<>();
for (Entry entry : this.entries) {
entries.add(new ClientboundPlayerInfoUpdatePacket.Entry(
entry.uuid(),
GameProfileImpl.asVanilla(entry.profile()),
entry.listed(),
entry.latency(),
GameType.byId(entry.gameMode().getId()),
PaperAdventure.asVanilla(entry.displayName()),
true,
-1,
null // TODO: Add ChatSession support
));
}
return new ClientboundPlayerInfoUpdatePacket(vanillaActions, entries);
}
@Override
public void sendPacketTo(FS_RealPlayer player) {
ClientboundPlayerInfoUpdatePacket packet = (ClientboundPlayerInfoUpdatePacket) createPacket();
ServerPlayer vanillaPlayer = VanillaPlayerAdapter.asVanilla(player.getBukkitPlayer());
vanillaPlayer.connection.send(packet);
}
}

View File

@@ -0,0 +1,37 @@
package de.oliver.fancysitula.versions.v1_21_11.packets;
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
import de.oliver.fancysitula.api.packets.FS_ClientboundRemoveEntitiesPacket;
import de.oliver.fancysitula.versions.v1_21_11.utils.VanillaPlayerAdapter;
import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket;
import net.minecraft.server.level.ServerPlayer;
import java.util.List;
public class ClientboundRemoveEntitiesPacketImpl extends FS_ClientboundRemoveEntitiesPacket {
/**
* @param entityIds IDs of the entities to remove
*/
public ClientboundRemoveEntitiesPacketImpl(List<Integer> entityIds) {
super(entityIds);
}
@Override
public Object createPacket() {
int[] ids = new int[this.entityIds.size()];
for (int i = 0; i < this.entityIds.size(); i++) {
ids[i] = this.entityIds.get(i);
}
return new ClientboundRemoveEntitiesPacket(ids);
}
@Override
public void sendPacketTo(FS_RealPlayer player) {
ClientboundRemoveEntitiesPacket packet = (ClientboundRemoveEntitiesPacket) createPacket();
ServerPlayer vanillaPlayer = VanillaPlayerAdapter.asVanilla(player.getBukkitPlayer());
vanillaPlayer.connection.send(packet);
}
}

View File

@@ -0,0 +1,38 @@
package de.oliver.fancysitula.versions.v1_21_11.packets;
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
import de.oliver.fancysitula.api.packets.FS_ClientboundRotateHeadPacket;
import de.oliver.fancysitula.api.utils.AngelConverter;
import de.oliver.fancysitula.api.utils.reflections.ReflectionUtils;
import de.oliver.fancysitula.versions.v1_21_11.utils.VanillaPlayerAdapter;
import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket;
import net.minecraft.server.level.ServerPlayer;
public class ClientboundRotateHeadPacketImpl extends FS_ClientboundRotateHeadPacket {
public ClientboundRotateHeadPacketImpl(int entityId, float headYaw) {
super(entityId, headYaw);
}
@Override
public Object createPacket() {
ClientboundRotateHeadPacket packet = null;
try {
packet = ReflectionUtils.createUnsafeInstance(ClientboundRotateHeadPacket.class);
ReflectionUtils.setFinalField(packet, "entityId", entityId);
ReflectionUtils.setFinalField(packet, "yHeadRot", AngelConverter.degreesToVanillaByte(headYaw));
} catch (Exception e) {
e.printStackTrace();
}
return packet;
}
@Override
public void sendPacketTo(FS_RealPlayer player) {
ClientboundRotateHeadPacket packet = (ClientboundRotateHeadPacket) createPacket();
ServerPlayer vanillaPlayer = VanillaPlayerAdapter.asVanilla(player.getBukkitPlayer());
vanillaPlayer.connection.send(packet);
}
}

View File

@@ -0,0 +1,67 @@
package de.oliver.fancysitula.versions.v1_21_11.packets;
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
import de.oliver.fancysitula.api.utils.reflections.ReflectionUtils;
import de.oliver.fancysitula.versions.v1_21_11.utils.VanillaPlayerAdapter;
import io.papermc.paper.adventure.PaperAdventure;
import net.kyori.adventure.text.Component;
import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.block.BlockState;
import org.bukkit.craftbukkit.block.CraftBlockState;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
public class ClientboundSetEntityDataPacketImpl extends FS_ClientboundSetEntityDataPacket {
public ClientboundSetEntityDataPacketImpl(int entityId, List<EntityData> entityData) {
super(entityId, entityData);
}
@Override
public Object createPacket() {
List<SynchedEntityData.DataValue<?>> dataValues = new ArrayList<>();
for (EntityData data : entityData) {
try {
Class<?> entityClass = Class.forName(data.getAccessor().entityClassName());
net.minecraft.network.syncher.EntityDataAccessor<Object> accessor = ReflectionUtils.getStaticField(entityClass, data.getAccessor().accessorFieldName());
Object vanillaValue = data.getValue();
if (data.getValue() == null) {
continue;
}
if (data.getValue() instanceof Component c) {
vanillaValue = PaperAdventure.asVanilla(c);
}
if (data.getValue() instanceof ItemStack i) {
vanillaValue = net.minecraft.world.item.ItemStack.fromBukkitCopy(i);
}
if (data.getValue() instanceof BlockState b) {
vanillaValue = ((CraftBlockState) b).getHandle();
}
dataValues.add(SynchedEntityData.DataValue.create(accessor, vanillaValue));
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
return new ClientboundSetEntityDataPacket(entityId, dataValues);
}
@Override
public void sendPacketTo(FS_RealPlayer player) {
ClientboundSetEntityDataPacket packet = (ClientboundSetEntityDataPacket) createPacket();
ServerPlayer vanillaPlayer = VanillaPlayerAdapter.asVanilla(player.getBukkitPlayer());
vanillaPlayer.connection.send(packet);
}
}

View File

@@ -0,0 +1,45 @@
package de.oliver.fancysitula.versions.v1_21_11.packets;
import com.mojang.datafixers.util.Pair;
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEquipmentPacket;
import de.oliver.fancysitula.api.utils.FS_EquipmentSlot;
import de.oliver.fancysitula.versions.v1_21_11.utils.VanillaPlayerAdapter;
import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.EquipmentSlot;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class ClientboundSetEquipmentPacketImpl extends FS_ClientboundSetEquipmentPacket {
public ClientboundSetEquipmentPacketImpl(int entityId, Map<FS_EquipmentSlot, ItemStack> equipment) {
super(entityId, equipment);
}
@Override
public Object createPacket() {
List<Pair<net.minecraft.world.entity.EquipmentSlot, net.minecraft.world.item.ItemStack>> slots = new ArrayList<>();
for (Map.Entry<FS_EquipmentSlot, ItemStack> entry : equipment.entrySet()) {
EquipmentSlot equipmentSlot = net.minecraft.world.entity.EquipmentSlot.byName(entry.getKey().name().toLowerCase());
net.minecraft.world.item.ItemStack itemStack = CraftItemStack.asNMSCopy(entry.getValue());
slots.add(Pair.of(equipmentSlot, itemStack));
}
return new ClientboundSetEquipmentPacket(entityId, slots);
}
@Override
public void sendPacketTo(FS_RealPlayer player) {
ClientboundSetEquipmentPacket packet = (ClientboundSetEquipmentPacket) createPacket();
ServerPlayer vanillaPlayer = VanillaPlayerAdapter.asVanilla(player.getBukkitPlayer());
vanillaPlayer.connection.send(packet);
}
}

View File

@@ -0,0 +1,45 @@
package de.oliver.fancysitula.versions.v1_21_11.packets;
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
import de.oliver.fancysitula.api.packets.FS_ClientboundSetPassengersPacket;
import de.oliver.fancysitula.api.utils.reflections.ReflectionUtils;
import de.oliver.fancysitula.versions.v1_21_11.utils.VanillaPlayerAdapter;
import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket;
import net.minecraft.server.level.ServerPlayer;
import java.util.List;
public class ClientboundSetPassengersPacketImpl extends FS_ClientboundSetPassengersPacket {
public ClientboundSetPassengersPacketImpl(int entityId, List<Integer> passengers) {
super(entityId, passengers);
}
@Override
public Object createPacket() {
int[] passengers = new int[this.passengers.size()];
for (int i = 0; i < this.passengers.size(); i++) {
passengers[i] = this.passengers.get(i);
}
try {
ClientboundSetPassengersPacket packet = ReflectionUtils.createUnsafeInstance(ClientboundSetPassengersPacket.class);
ReflectionUtils.setFinalField(packet, "vehicle", entityId);
ReflectionUtils.setFinalField(packet, "passengers", passengers);
return packet;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public void sendPacketTo(FS_RealPlayer player) {
ClientboundSetPassengersPacket packet = (ClientboundSetPassengersPacket) createPacket();
ServerPlayer vanillaPlayer = VanillaPlayerAdapter.asVanilla(player.getBukkitPlayer());
vanillaPlayer.connection.send(packet);
}
}

View File

@@ -0,0 +1,276 @@
package de.oliver.fancysitula.versions.v1_21_11.packets;
import de.oliver.fancysitula.api.dialogs.FS_CommonDialogData;
import de.oliver.fancysitula.api.dialogs.FS_Dialog;
import de.oliver.fancysitula.api.dialogs.FS_DialogAction;
import de.oliver.fancysitula.api.dialogs.actions.FS_CommonButtonData;
import de.oliver.fancysitula.api.dialogs.actions.FS_DialogActionButton;
import de.oliver.fancysitula.api.dialogs.actions.FS_DialogCustomAction;
import de.oliver.fancysitula.api.dialogs.body.FS_DialogBody;
import de.oliver.fancysitula.api.dialogs.body.FS_DialogItemBody;
import de.oliver.fancysitula.api.dialogs.body.FS_DialogTextBody;
import de.oliver.fancysitula.api.dialogs.inputs.*;
import de.oliver.fancysitula.api.dialogs.types.FS_ConfirmationDialog;
import de.oliver.fancysitula.api.dialogs.types.FS_DialogListDialog;
import de.oliver.fancysitula.api.dialogs.types.FS_MultiActionDialog;
import de.oliver.fancysitula.api.dialogs.types.FS_NoticeDialog;
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
import de.oliver.fancysitula.api.packets.FS_ClientboundShowDialogPacket;
import de.oliver.fancysitula.versions.v1_21_11.utils.VanillaPlayerAdapter;
import io.papermc.paper.adventure.PaperAdventure;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.common.ClientboundShowDialogPacket;
import net.minecraft.resources.Identifier;
import net.minecraft.server.dialog.*;
import net.minecraft.server.dialog.action.Action;
import net.minecraft.server.dialog.action.CustomAll;
import net.minecraft.server.dialog.body.DialogBody;
import net.minecraft.server.dialog.body.ItemBody;
import net.minecraft.server.dialog.body.PlainMessage;
import net.minecraft.server.dialog.input.*;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class ClientboundShowDialogPacketImpl extends FS_ClientboundShowDialogPacket {
public ClientboundShowDialogPacketImpl(FS_Dialog dialog) {
super(dialog);
}
@Override
public Object createPacket() {
Holder<Dialog> holder = Holder.direct(toNms(dialog));
return new ClientboundShowDialogPacket(holder);
}
@Override
protected void sendPacketTo(FS_RealPlayer player) {
ClientboundShowDialogPacket packet = (ClientboundShowDialogPacket) createPacket();
ServerPlayer vanillaPlayer = VanillaPlayerAdapter.asVanilla(player.getBukkitPlayer());
vanillaPlayer.connection.send(packet);
}
private Dialog toNms(FS_Dialog dialog) {
if (dialog instanceof FS_NoticeDialog notice) {
return noticeToNms(notice);
} else if (dialog instanceof FS_ConfirmationDialog confirmation) {
return confirmationToNms(confirmation);
} else if (dialog instanceof FS_DialogListDialog dialogList) {
return dialogListToNms(dialogList);
} else if (dialog instanceof FS_MultiActionDialog multiActionDialog) {
return multiActionDialogToNms(multiActionDialog);
}
return null;
}
private Dialog noticeToNms(FS_NoticeDialog notice) {
CommonDialogData common = commonToNms(notice.getDialogData());
ActionButton actionButton = actionButtonToNms(notice.getActionButton());
return new NoticeDialog(common, actionButton);
}
private Dialog confirmationToNms(FS_ConfirmationDialog notice) {
CommonDialogData common = commonToNms(notice.getDialogData());
ActionButton yes = actionButtonToNms(notice.getYesButton());
ActionButton no = actionButtonToNms(notice.getNoButton());
return new ConfirmationDialog(common, yes, no);
}
private Dialog dialogListToNms(FS_DialogListDialog dialogList) {
CommonDialogData common = commonToNms(dialogList.getDialogData());
List<Holder<Dialog>> dialogs = new ArrayList<>();
for (FS_Dialog dialog : dialogList.getDialogs()) {
dialogs.add(Holder.direct(toNms(dialog)));
}
HolderSet<Dialog> dialogSet = HolderSet.direct(dialogs);
Optional<ActionButton> exitButton = dialogList.getExitButton() != null ?
Optional.of(actionButtonToNms(dialogList.getExitButton())) :
Optional.empty();
return new DialogListDialog(common, dialogSet, exitButton, dialogList.getColumns(), dialogList.getButtonWidth());
}
private Dialog multiActionDialogToNms(FS_MultiActionDialog multiActionDialog) {
CommonDialogData common = commonToNms(multiActionDialog.getDialogData());
List<ActionButton> actionButtons = new ArrayList<>();
for (FS_DialogActionButton actionButton : multiActionDialog.getActions()) {
actionButtons.add(actionButtonToNms(actionButton));
}
Optional<ActionButton> exitAction = multiActionDialog.getExitAction() != null ?
Optional.of(actionButtonToNms(multiActionDialog.getExitAction())) :
Optional.empty();
return new MultiActionDialog(common, actionButtons, exitAction, multiActionDialog.getColumns());
}
private CommonDialogData commonToNms(FS_CommonDialogData dialogData) {
Component title = PaperAdventure.asVanilla(MiniMessage.miniMessage().deserialize(dialogData.getTitle()));
Optional<Component> externalTitle = dialogData.getExternalTitle() != null ?
Optional.of(PaperAdventure.asVanilla(MiniMessage.miniMessage().deserialize(dialogData.getExternalTitle()))) :
Optional.empty();
return new CommonDialogData(
title,
externalTitle,
dialogData.isCanCloseWithEscape(),
dialogData.isPause(),
actionToNms(dialogData.getAfterAction()),
bodyToNms(dialogData.getBody()),
inputsToNms(dialogData.getInputs())
);
}
private DialogAction actionToNms(FS_DialogAction dialogAction) {
return switch (dialogAction) {
case CLOSE -> DialogAction.CLOSE;
case NONE -> DialogAction.NONE;
case WAIT_FOR_RESPONSE -> DialogAction.WAIT_FOR_RESPONSE;
};
}
private List<DialogBody> bodyToNms(List<FS_DialogBody> bodies) {
List<DialogBody> nmsBodies = new ArrayList<>();
for (FS_DialogBody body : bodies) {
if (body instanceof FS_DialogTextBody textBody) {
nmsBodies.add(new PlainMessage(
PaperAdventure.asVanilla(MiniMessage.miniMessage().deserialize(textBody.getText())),
textBody.getWidth()
));
} else if (body instanceof FS_DialogItemBody itemBody) {
Optional<PlainMessage> description = itemBody.getDescription() != null ?
Optional.of(new PlainMessage(
PaperAdventure.asVanilla(MiniMessage.miniMessage().deserialize(itemBody.getDescription().getText())),
itemBody.getDescription().getWidth()
)) :
Optional.empty();
nmsBodies.add(new ItemBody(
CraftItemStack.asNMSCopy(itemBody.getItem()),
description,
itemBody.isShowDecorations(),
itemBody.isShowTooltip(),
itemBody.getWidth(),
itemBody.getHeight()
));
}
}
return nmsBodies;
}
private List<Input> inputsToNms(List<FS_DialogInput> inputs) {
List<Input> nmsInputs = new ArrayList<>();
for (FS_DialogInput input : inputs) {
String key = input.getKey();
InputControl control = null;
if (input.getControl() instanceof FS_DialogBooleanInput booleanInput) {
control = new BooleanInput(
PaperAdventure.asVanilla(MiniMessage.miniMessage().deserialize(booleanInput.getLabel())),
booleanInput.isInitial(),
booleanInput.getOnTrue(),
booleanInput.getOnFalse()
);
} else if (input.getControl() instanceof FS_DialogNumberRangeInput numberRangeInput) {
control = new NumberRangeInput(
numberRangeInput.getWidth(),
PaperAdventure.asVanilla(MiniMessage.miniMessage().deserialize(numberRangeInput.getLabel())),
numberRangeInput.getLabelFormat(),
new NumberRangeInput.RangeInfo(
numberRangeInput.getStart(),
numberRangeInput.getEnd(),
numberRangeInput.getInitial() != null ? Optional.of(numberRangeInput.getInitial()) : Optional.empty(),
numberRangeInput.getStep() != null ? Optional.of(numberRangeInput.getStep()) : Optional.empty()
)
);
} else if (input.getControl() instanceof FS_DialogSingleOptionInput singleOptionInput) {
List<SingleOptionInput.Entry> nmsEntries = new ArrayList<>();
for (FS_DialogSingleOptionInput.Entry entry : singleOptionInput.getEntries()) {
nmsEntries.add(new SingleOptionInput.Entry(
entry.getId(),
entry.getDisplay() != null ? Optional.of(PaperAdventure.asVanilla(MiniMessage.miniMessage().deserialize(entry.getDisplay()))) : Optional.empty(),
entry.isInitial()
));
}
control = new SingleOptionInput(
singleOptionInput.getWidth(),
nmsEntries,
PaperAdventure.asVanilla(MiniMessage.miniMessage().deserialize(singleOptionInput.getLabel())),
singleOptionInput.isLabelVisible()
);
} else if (input.getControl() instanceof FS_DialogTextInput textInput) {
control = new TextInput(
textInput.getWidth(),
PaperAdventure.asVanilla(MiniMessage.miniMessage().deserialize(textInput.getLabel())),
textInput.isLabelVisible(),
textInput.getInitial(),
textInput.getMaxLength(),
Optional.empty()
);
}
nmsInputs.add(new Input(key, control));
}
return nmsInputs;
}
private ActionButton actionButtonToNms(FS_DialogActionButton actionButton) {
CommonButtonData buttonData = commonButtonDataToNms(actionButton.getButtonData());
Action action = null;
if (actionButton.getAction() instanceof FS_DialogCustomAction customAction) {
Key idKey = Key.key("fancysitula", customAction.getId());
Identifier idLocation = PaperAdventure.asVanilla(idKey);
Optional<CompoundTag> additions;
if (customAction.getAdditions() != null) {
CompoundTag tag = new CompoundTag();
customAction.getAdditions().forEach(tag::putString);
additions = Optional.of(tag);
} else {
additions = Optional.empty();
}
action = new CustomAll(idLocation, additions);
}
Optional<Action> optionalAction = action != null ?
Optional.of(action) :
Optional.empty();
return new ActionButton(buttonData, optionalAction);
}
private CommonButtonData commonButtonDataToNms(FS_CommonButtonData commonButtonData) {
Component label = PaperAdventure.asVanilla(MiniMessage.miniMessage().deserialize(commonButtonData.getLabel()));
Optional<Component> tooltip = commonButtonData.getTooltip() != null ?
Optional.of(PaperAdventure.asVanilla(MiniMessage.miniMessage().deserialize(commonButtonData.getTooltip()))) :
Optional.empty();
int width = commonButtonData.getWidth();
return new CommonButtonData(label, tooltip, width);
}
}

View File

@@ -0,0 +1,43 @@
package de.oliver.fancysitula.versions.v1_21_11.packets;
import de.oliver.fancysitula.api.entities.FS_RealPlayer;
import de.oliver.fancysitula.api.packets.FS_ClientboundTeleportEntityPacket;
import de.oliver.fancysitula.versions.v1_21_11.utils.VanillaPlayerAdapter;
import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.PositionMoveRotation;
import net.minecraft.world.phys.Vec3;
import java.util.Set;
public class ClientboundTeleportEntityPacketImpl extends FS_ClientboundTeleportEntityPacket {
public ClientboundTeleportEntityPacketImpl(int entityId, double x, double y, double z, float yaw, float pitch, boolean onGround) {
super(entityId, x, y, z, yaw, pitch, onGround);
}
@Override
public Object createPacket() {
ClientboundTeleportEntityPacket packet = new ClientboundTeleportEntityPacket(
entityId,
new PositionMoveRotation(
new Vec3(x, y, z),
Vec3.ZERO,
yaw,
pitch
),
Set.of(),
onGround
);
return packet;
}
@Override
public void sendPacketTo(FS_RealPlayer player) {
ClientboundTeleportEntityPacket packet = (ClientboundTeleportEntityPacket) createPacket();
ServerPlayer vanillaPlayer = VanillaPlayerAdapter.asVanilla(player.getBukkitPlayer());
vanillaPlayer.connection.send(packet);
}
}

View File

@@ -0,0 +1,33 @@
package de.oliver.fancysitula.versions.v1_21_11.utils;
import com.mojang.authlib.GameProfile;
import de.oliver.fancysitula.api.utils.FS_GameProfile;
import java.util.Map;
public class GameProfileImpl {
public static GameProfile asVanilla(FS_GameProfile gameProfile) {
GameProfile gf = new GameProfile(gameProfile.getUUID(), gameProfile.getName());
for (Map.Entry<String, FS_GameProfile.Property> entry : gameProfile.getProperties().entrySet()) {
FS_GameProfile.Property property = entry.getValue();
gf.properties().put(entry.getKey(), new com.mojang.authlib.properties.Property(property.name(), property.value(), property.signature()));
}
return gf;
}
public static FS_GameProfile fromVanilla(GameProfile gameProfile) {
FS_GameProfile fsGameProfile = new FS_GameProfile(gameProfile.id(), gameProfile.name());
for (Map.Entry<String, com.mojang.authlib.properties.Property> entry : gameProfile.properties().entries()) {
com.mojang.authlib.properties.Property property = entry.getValue();
fsGameProfile.getProperties().put(entry.getKey(), new FS_GameProfile.Property(property.name(), property.value(), property.signature()));
}
return fsGameProfile;
}
}

View File

@@ -0,0 +1,110 @@
package de.oliver.fancysitula.versions.v1_21_11.utils;
import de.oliver.fancysitula.api.packets.FS_ServerboundCustomClickActionPacket;
import de.oliver.fancysitula.api.packets.FS_ServerboundPacket;
import de.oliver.fancysitula.api.utils.FS_PacketListener;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.papermc.paper.adventure.PaperAdventure;
import net.minecraft.nbt.StringTag;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.common.ServerboundCustomClickActionPacket;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PacketListenerImpl extends FS_PacketListener {
private static final String PIPELINE_NAME = "fancysitula-packet-injector";
public PacketListenerImpl(FS_ServerboundPacket.Type packet) {
super(packet);
}
@Override
public void inject(Player player) {
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
Channel channel = serverPlayer.connection.connection.channel;
if (channel.pipeline().get(PIPELINE_NAME) != null) {
return;
}
channel.pipeline().addAfter("decoder", PIPELINE_NAME, new MessageToMessageDecoder<Packet<?>>() {
@Override
protected void decode(ChannelHandlerContext ctx, Packet<?> msg, List<Object> out) {
out.add(msg);
FS_ServerboundPacket.Type packetType = getPacketType(msg);
if (packetType == null) {
return; // Unsupported packet type
}
if (packet == FS_ServerboundPacket.Type.ALL) {
FS_ServerboundPacket fsPacket = convert(packetType, msg);
PacketReceivedEvent packetReceivedEvent = new PacketReceivedEvent(fsPacket, player);
listeners.forEach(listener -> listener.accept(packetReceivedEvent));
return;
}
if (packet == packetType) {
FS_ServerboundPacket fsPacket = convert(packetType, msg);
PacketReceivedEvent packetReceivedEvent = new PacketReceivedEvent(fsPacket, player);
listeners.forEach(listener -> listener.accept(packetReceivedEvent));
}
}
});
}
private FS_ServerboundPacket.Type getPacketType(Packet<?> packet) {
String className = packet.getClass().getSimpleName();
for (FS_ServerboundPacket.Type type : FS_ServerboundPacket.Type.values()) {
if (type.getPacketClassName().equalsIgnoreCase(className)) {
return type;
}
}
return null;
}
private FS_ServerboundPacket convert(FS_ServerboundPacket.Type type, Packet<?> packet) {
switch (type) {
case CUSTOM_CLICK_ACTION -> {
ServerboundCustomClickActionPacket customClickActionPacket = (ServerboundCustomClickActionPacket) packet;
Map<String, String> payload = new HashMap<>();
if (customClickActionPacket.payload().isPresent() && customClickActionPacket.payload().get().asCompound().isPresent()) {
customClickActionPacket.payload().get().asCompound().get().forEach((k, v) -> {
if (v.getType().getName().equals(StringTag.TYPE.getName())) {
if (v.asString().isPresent()) {
payload.put(k, v.asString().get());
}
} else if (v.getType().getName().equals(net.minecraft.nbt.ByteTag.TYPE.getName())) {
if (v.asBoolean().isPresent()) {
payload.put(k, String.valueOf(v.asBoolean().get()));
} else if (v.asByte().isPresent()) {
payload.put(k, String.valueOf(v.asByte().get()));
}
} else {
payload.put(k, v.toString());
}
});
}
return new FS_ServerboundCustomClickActionPacket(
type,
PaperAdventure.asAdventure(customClickActionPacket.id()),
payload
);
}
// Add more cases for other packet types as needed
default -> throw new IllegalArgumentException("Unsupported packet type: " + type);
}
}
}

View File

@@ -0,0 +1,12 @@
package de.oliver.fancysitula.versions.v1_21_11.utils;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
public class VanillaPlayerAdapter {
public static ServerPlayer asVanilla(Player p) {
return ((CraftPlayer) p).getHandle();
}
}

View File

@@ -0,0 +1,65 @@
package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.api.utils.AngelConverter;
import de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundAddEntityPacketImpl;
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
import org.bukkit.entity.EntityType;
import java.util.UUID;
class ClientboundAddEntityPacketImplTest {
//TODO: Fix this test (registry problems)
// @Test
void createPacket() {
int entityId = 10000;
UUID entityUUID = UUID.randomUUID();
EntityType entityType = EntityType.PIG;
double x = 5;
double y = 57;
double z = 203;
float yaw = 142;
float pitch = 247;
float headYaw = 90;
int velocityX = 0;
int velocityY = 0;
int velocityZ = 0;
int data = 0;
ClientboundAddEntityPacketImpl packet = new ClientboundAddEntityPacketImpl(
entityId,
entityUUID,
entityType,
x,
y,
z,
yaw,
pitch,
headYaw,
velocityX,
velocityY,
velocityZ,
data
);
ClientboundAddEntityPacket createdPacket = (ClientboundAddEntityPacket) packet.createPacket();
assert createdPacket.getId() == entityId;
assert createdPacket.getUUID().equals(entityUUID);
assert createdPacket.getType().getDescriptionId().equals(entityType.getKey().getKey());
assert createdPacket.getX() == x;
assert createdPacket.getY() == y;
assert createdPacket.getZ() == z;
assert createdPacket.getYRot() == AngelConverter.degreesToVanillaByte(yaw);
assert createdPacket.getXRot() == AngelConverter.degreesToVanillaByte(pitch);
assert createdPacket.getYHeadRot() == AngelConverter.degreesToVanillaByte(headYaw);
assert createdPacket.getMovement().x == velocityX;
assert createdPacket.getMovement().y == velocityY;
assert createdPacket.getMovement().z == velocityZ;
assert createdPacket.getData() == data;
}
}

View File

@@ -0,0 +1,15 @@
package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundClearDialogPacketImpl;
import org.junit.jupiter.api.Test;
public class ClientboundClearDialogPacketImplTest {
@Test
void createPacket() {
ClientboundClearDialogPacketImpl packet = new ClientboundClearDialogPacketImpl();
assert packet.createPacket() != null : "Packet creation failed";
// assert packet.equals(ClientboundClearDialogPacket.INSTANCE);
}
}

View File

@@ -0,0 +1,23 @@
package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundPlayerInfoRemovePacketImpl;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.UUID;
class ClientboundPlayerInfoRemovePacketImplTest {
@Test
void createPacket() {
List<UUID> uuids = List.of(UUID.randomUUID(), UUID.randomUUID());
ClientboundPlayerInfoRemovePacketImpl packet = new ClientboundPlayerInfoRemovePacketImpl(uuids);
ClientboundPlayerInfoRemovePacket vanillaPacket = (ClientboundPlayerInfoRemovePacket) packet.createPacket();
for (UUID uuid : uuids) {
assert vanillaPacket.profileIds().contains(uuid);
}
}
}

View File

@@ -0,0 +1,62 @@
package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.api.packets.FS_ClientboundPlayerInfoUpdatePacket;
import de.oliver.fancysitula.api.utils.FS_GameProfile;
import de.oliver.fancysitula.api.utils.FS_GameType;
import de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundPlayerInfoUpdatePacketImpl;
import net.kyori.adventure.text.Component;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.UUID;
class ClientboundPlayerInfoUpdatePacketImplTest {
@Test
void createPacket() {
// Setup packet
EnumSet<FS_ClientboundPlayerInfoUpdatePacket.Action> actions = EnumSet.noneOf(FS_ClientboundPlayerInfoUpdatePacket.Action.class);
actions.add(FS_ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER);
actions.add(FS_ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
actions.add(FS_ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED);
FS_GameProfile gameProfile = new FS_GameProfile(UUID.randomUUID(), "Test name");
boolean listed = true;
int latency = 42;
FS_GameType gameMode = FS_GameType.SURVIVAL;
Component displayName = Component.text("Test displayname");
List<FS_ClientboundPlayerInfoUpdatePacket.Entry> entries = new ArrayList<>();
entries.add(new FS_ClientboundPlayerInfoUpdatePacket.Entry(
gameProfile.getUUID(),
gameProfile,
listed,
latency,
gameMode,
displayName
));
ClientboundPlayerInfoUpdatePacketImpl packet = new ClientboundPlayerInfoUpdatePacketImpl(actions, entries);
ClientboundPlayerInfoUpdatePacket createdPacket = (ClientboundPlayerInfoUpdatePacket) packet.createPacket();
assert createdPacket.entries().size() == 1;
assert createdPacket.actions().size() == 3;
// check entry
ClientboundPlayerInfoUpdatePacket.Entry entry = createdPacket.entries().getFirst();
assert entry.profile().id().equals(gameProfile.getUUID());
assert entry.profile().name().equals(gameProfile.getName());
assert entry.listed() == listed;
assert entry.latency() == latency;
assert entry.gameMode().getId() == gameMode.getId();
// check actions
assert createdPacket.actions().contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER);
assert createdPacket.actions().contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME);
assert createdPacket.actions().contains(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED);
}
}

View File

@@ -0,0 +1,21 @@
package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundRemoveEntitiesPacketImpl;
import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket;
import org.junit.jupiter.api.Test;
import java.util.List;
class ClientboundRemoveEntitiesPacketImplTest {
@Test
void createPacket() {
List<Integer> entityIds = List.of(95, 120, 154, 187);
ClientboundRemoveEntitiesPacketImpl packet = new ClientboundRemoveEntitiesPacketImpl(entityIds);
ClientboundRemoveEntitiesPacket createdPacket = (ClientboundRemoveEntitiesPacket) packet.createPacket();
assert createdPacket.getEntityIds().size() == entityIds.size();
assert createdPacket.getEntityIds().containsAll(entityIds);
}
}

View File

@@ -0,0 +1,21 @@
package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.api.utils.reflections.ReflectionUtils;
import de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundRotateHeadPacketImpl;
import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket;
import org.junit.jupiter.api.Test;
class ClientboundRotateHeadPacketImplTest {
@Test
void createPacket() throws Exception {
int entityId = 184;
float headYaw = 45;
ClientboundRotateHeadPacketImpl packet = new ClientboundRotateHeadPacketImpl(entityId, (byte) headYaw);
ClientboundRotateHeadPacket createdPacket = (ClientboundRotateHeadPacket) packet.createPacket();
assert ReflectionUtils.getField(createdPacket, "entityId").equals(entityId);
assert createdPacket.getYHeadRot() == headYaw;
}
}

View File

@@ -0,0 +1,29 @@
package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
import de.oliver.fancysitula.api.utils.entityData.FS_TextDisplayData;
import de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundSetEntityDataPacketImpl;
import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket;
import java.util.List;
class ClientboundSetEntityDataPacketImplTest {
//TODO: Fix this test (using registry)
// @Test
void createPacket() {
int entityId = 712;
List<FS_ClientboundSetEntityDataPacket.EntityData> entityData = List.of(
new FS_ClientboundSetEntityDataPacket.EntityData(
FS_TextDisplayData.TEXT,
"Hello, World!"
)
);
ClientboundSetEntityDataPacketImpl packet = new ClientboundSetEntityDataPacketImpl(entityId, entityData);
ClientboundSetEntityDataPacket createdPacket = (ClientboundSetEntityDataPacket) packet.createPacket();
assert createdPacket.id() == entityId;
assert createdPacket.packedItems().size() == 1;
}
}

View File

@@ -0,0 +1,29 @@
package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.api.utils.FS_EquipmentSlot;
import de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundSetEquipmentPacketImpl;
import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import java.util.Map;
class ClientboundSetEquipmentPacketImplTest {
//TODO: Fix this test (registry problems)
// @Test
void createPacket() {
// Setup packet
Map<FS_EquipmentSlot, ItemStack> equipment = Map.of(
FS_EquipmentSlot.MAINHAND, new ItemStack(Material.DIAMOND_SWORD),
FS_EquipmentSlot.OFFHAND, new ItemStack(Material.SHIELD),
FS_EquipmentSlot.HEAD, new ItemStack(Material.DIAMOND_HELMET)
);
ClientboundSetEquipmentPacketImpl packet = new ClientboundSetEquipmentPacketImpl(42, equipment);
ClientboundSetEquipmentPacket createdPacket = (ClientboundSetEquipmentPacket) packet.createPacket();
assert createdPacket.getEntity() == 42;
assert createdPacket.getSlots().size() == 3;
}
}

View File

@@ -0,0 +1,29 @@
package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundSetPassengersPacketImpl;
import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
public class ClientboundSetPassengersPacketImplTest {
@Test
void createPacket() {
// Setup packet
int vehicleID = 712;
List<Integer> passengers = new ArrayList<>();
passengers.add(571);
passengers.add(572);
ClientboundSetPassengersPacketImpl packet = new ClientboundSetPassengersPacketImpl(vehicleID, passengers);
ClientboundSetPassengersPacket createdPacket = (ClientboundSetPassengersPacket) packet.createPacket();
// Check packet
assert createdPacket.getVehicle() == vehicleID;
assert createdPacket.getPassengers().length == 2;
assert createdPacket.getPassengers()[0] == 571;
assert createdPacket.getPassengers()[1] == 572;
}
}

View File

@@ -0,0 +1,31 @@
package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundTeleportEntityPacketImpl;
import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket;
import org.junit.jupiter.api.Test;
class ClientboundTeleportEntityPacketImplTest {
@Test
void createPacket() {
int entityId = 4313;
double x = 15.0;
double y = 57.0;
double z = -27.0;
float yaw = 90.0f;
float pitch = 45.0f;
boolean onGround = true;
ClientboundTeleportEntityPacketImpl packet = new ClientboundTeleportEntityPacketImpl(entityId, x, y, z, yaw, pitch, onGround);
ClientboundTeleportEntityPacket createdPacket = (ClientboundTeleportEntityPacket) packet.createPacket();
assert createdPacket != null;
assert createdPacket.id() == entityId;
assert createdPacket.change().position().x == x;
assert createdPacket.change().position().y == y;
assert createdPacket.change().position().z == z;
assert createdPacket.change().xRot() == pitch;
assert createdPacket.change().yRot() == yaw;
assert createdPacket.onGround() == onGround;
}
}

View File

@@ -1,4 +1,4 @@
package de.oliver.fancysitula.versions.v1_21_6.packets; package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.api.utils.AngelConverter; import de.oliver.fancysitula.api.utils.AngelConverter;
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
@@ -56,9 +56,9 @@ class ClientboundAddEntityPacketImplTest {
assert createdPacket.getYRot() == AngelConverter.degreesToVanillaByte(yaw); assert createdPacket.getYRot() == AngelConverter.degreesToVanillaByte(yaw);
assert createdPacket.getXRot() == AngelConverter.degreesToVanillaByte(pitch); assert createdPacket.getXRot() == AngelConverter.degreesToVanillaByte(pitch);
assert createdPacket.getYHeadRot() == AngelConverter.degreesToVanillaByte(headYaw); assert createdPacket.getYHeadRot() == AngelConverter.degreesToVanillaByte(headYaw);
assert createdPacket.getXa() == velocityX; assert createdPacket.getMovement().x == velocityX;
assert createdPacket.getYa() == velocityY; assert createdPacket.getMovement().y == velocityY;
assert createdPacket.getZa() == velocityZ; assert createdPacket.getMovement().z == velocityZ;
assert createdPacket.getData() == data; assert createdPacket.getData() == data;
} }
} }

View File

@@ -1,4 +1,4 @@
package de.oliver.fancysitula.versions.v1_21_6.packets; package de.oliver.fancysitula.versions.v1_21_9.packets;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

View File

@@ -1,4 +1,4 @@
package de.oliver.fancysitula.versions.v1_21_6.packets; package de.oliver.fancysitula.versions.v1_21_9.packets;
import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

View File

@@ -1,4 +1,4 @@
package de.oliver.fancysitula.versions.v1_21_6.packets; package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.api.packets.FS_ClientboundPlayerInfoUpdatePacket; import de.oliver.fancysitula.api.packets.FS_ClientboundPlayerInfoUpdatePacket;
import de.oliver.fancysitula.api.utils.FS_GameProfile; import de.oliver.fancysitula.api.utils.FS_GameProfile;
@@ -47,8 +47,8 @@ class ClientboundPlayerInfoUpdatePacketImplTest {
// check entry // check entry
ClientboundPlayerInfoUpdatePacket.Entry entry = createdPacket.entries().getFirst(); ClientboundPlayerInfoUpdatePacket.Entry entry = createdPacket.entries().getFirst();
assert entry.profile().getId().equals(gameProfile.getUUID()); assert entry.profile().id().equals(gameProfile.getUUID());
assert entry.profile().getName().equals(gameProfile.getName()); assert entry.profile().name().equals(gameProfile.getName());
assert entry.listed() == listed; assert entry.listed() == listed;
assert entry.latency() == latency; assert entry.latency() == latency;
assert entry.gameMode().getId() == gameMode.getId(); assert entry.gameMode().getId() == gameMode.getId();

View File

@@ -1,4 +1,4 @@
package de.oliver.fancysitula.versions.v1_21_6.packets; package de.oliver.fancysitula.versions.v1_21_9.packets;
import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

View File

@@ -1,4 +1,4 @@
package de.oliver.fancysitula.versions.v1_21_6.packets; package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.api.utils.reflections.ReflectionUtils; import de.oliver.fancysitula.api.utils.reflections.ReflectionUtils;
import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket; import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket;

View File

@@ -1,4 +1,4 @@
package de.oliver.fancysitula.versions.v1_21_6.packets; package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket; import de.oliver.fancysitula.api.packets.FS_ClientboundSetEntityDataPacket;
import de.oliver.fancysitula.api.utils.entityData.FS_TextDisplayData; import de.oliver.fancysitula.api.utils.entityData.FS_TextDisplayData;

View File

@@ -1,4 +1,4 @@
package de.oliver.fancysitula.versions.v1_21_6.packets; package de.oliver.fancysitula.versions.v1_21_9.packets;
import de.oliver.fancysitula.api.utils.FS_EquipmentSlot; import de.oliver.fancysitula.api.utils.FS_EquipmentSlot;
import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket; import net.minecraft.network.protocol.game.ClientboundSetEquipmentPacket;

View File

@@ -1,4 +1,4 @@
package de.oliver.fancysitula.versions.v1_21_6.packets; package de.oliver.fancysitula.versions.v1_21_9.packets;
import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket; import net.minecraft.network.protocol.game.ClientboundSetPassengersPacket;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

View File

@@ -1,4 +1,4 @@
package de.oliver.fancysitula.versions.v1_21_6.packets; package de.oliver.fancysitula.versions.v1_21_9.packets;
import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket; import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;

View File

@@ -7,6 +7,7 @@ import java.util.List;
public enum ServerVersion { public enum ServerVersion {
v1_21_11("1.21.11 Release Candidate 2", 774),
v1_21_10("1.21.10", 773), v1_21_10("1.21.10", 773),
v1_21_9("1.21.9", 773), v1_21_9("1.21.9", 773),
v1_21_8("1.21.8", 772), v1_21_8("1.21.8", 772),

View File

@@ -28,6 +28,9 @@ public class PacketFactory {
List<FS_ClientboundPlayerInfoUpdatePacket.Entry> entries List<FS_ClientboundPlayerInfoUpdatePacket.Entry> entries
) { ) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundPlayerInfoUpdatePacketImpl(actions, entries);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundPlayerInfoUpdatePacketImpl(actions, entries); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundPlayerInfoUpdatePacketImpl(actions, entries);
} }
@@ -73,6 +76,9 @@ public class PacketFactory {
int velocityZ, int velocityZ,
int data) { int data) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundAddEntityPacketImpl(entityId, entityUUID, entityType, x, y, z, yaw, pitch, headYaw, velocityX, velocityY, velocityZ, data);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundAddEntityPacketImpl(entityId, entityUUID, entityType, x, y, z, yaw, pitch, headYaw, velocityX, velocityY, velocityZ, data); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundAddEntityPacketImpl(entityId, entityUUID, entityType, x, y, z, yaw, pitch, headYaw, velocityX, velocityY, velocityZ, data);
} }
@@ -105,6 +111,9 @@ public class PacketFactory {
List<UUID> uuids List<UUID> uuids
) { ) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundPlayerInfoRemovePacketImpl(uuids);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundPlayerInfoRemovePacketImpl(uuids); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundPlayerInfoRemovePacketImpl(uuids);
} }
@@ -137,6 +146,9 @@ public class PacketFactory {
List<Integer> entityIds List<Integer> entityIds
) { ) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundRemoveEntitiesPacketImpl(entityIds);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundRemoveEntitiesPacketImpl(entityIds); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundRemoveEntitiesPacketImpl(entityIds);
} }
@@ -181,6 +193,9 @@ public class PacketFactory {
boolean onGround boolean onGround
) { ) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundTeleportEntityPacketImpl(entityId, x, y, z, yaw, pitch, onGround);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundTeleportEntityPacketImpl(entityId, x, y, z, yaw, pitch, onGround); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundTeleportEntityPacketImpl(entityId, x, y, z, yaw, pitch, onGround);
} }
@@ -215,6 +230,9 @@ public class PacketFactory {
float headYaw float headYaw
) { ) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundRotateHeadPacketImpl(entityId, headYaw);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundRotateHeadPacketImpl(entityId, headYaw); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundRotateHeadPacketImpl(entityId, headYaw);
} }
@@ -249,6 +267,9 @@ public class PacketFactory {
List<FS_ClientboundSetEntityDataPacket.EntityData> entityData List<FS_ClientboundSetEntityDataPacket.EntityData> entityData
) { ) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundSetEntityDataPacketImpl(entityId, entityData);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundSetEntityDataPacketImpl(entityId, entityData); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundSetEntityDataPacketImpl(entityId, entityData);
} }
@@ -283,6 +304,9 @@ public class PacketFactory {
Map<FS_EquipmentSlot, ItemStack> equipment Map<FS_EquipmentSlot, ItemStack> equipment
) { ) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundSetEquipmentPacketImpl(entityId, equipment);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundSetEquipmentPacketImpl(entityId, equipment); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundSetEquipmentPacketImpl(entityId, equipment);
} }
@@ -317,6 +341,9 @@ public class PacketFactory {
List<Integer> passengers List<Integer> passengers
) { ) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundSetPassengersPacketImpl(entityId, passengers);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundSetPassengersPacketImpl(entityId, passengers); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundSetPassengersPacketImpl(entityId, passengers);
} }
@@ -354,6 +381,9 @@ public class PacketFactory {
FS_ClientboundCreateOrUpdateTeamPacket.CreateTeam createTeam FS_ClientboundCreateOrUpdateTeamPacket.CreateTeam createTeam
) { ) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, createTeam);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, createTeam); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, createTeam);
} }
@@ -390,6 +420,9 @@ public class PacketFactory {
FS_ClientboundCreateOrUpdateTeamPacket.RemoveTeam removeTeam FS_ClientboundCreateOrUpdateTeamPacket.RemoveTeam removeTeam
) { ) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, removeTeam);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, removeTeam); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, removeTeam);
} }
@@ -426,6 +459,9 @@ public class PacketFactory {
FS_ClientboundCreateOrUpdateTeamPacket.UpdateTeam updateTeam FS_ClientboundCreateOrUpdateTeamPacket.UpdateTeam updateTeam
) { ) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, updateTeam);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, updateTeam); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, updateTeam);
} }
@@ -462,6 +498,9 @@ public class PacketFactory {
FS_ClientboundCreateOrUpdateTeamPacket.AddEntity addEntity FS_ClientboundCreateOrUpdateTeamPacket.AddEntity addEntity
) { ) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, addEntity);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, addEntity); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, addEntity);
} }
@@ -498,6 +537,9 @@ public class PacketFactory {
FS_ClientboundCreateOrUpdateTeamPacket.RemoveEntity removeEntity FS_ClientboundCreateOrUpdateTeamPacket.RemoveEntity removeEntity
) { ) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, removeEntity);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, removeEntity); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundCreateOrUpdateTeamPacketImpl(teamName, removeEntity);
} }
@@ -531,6 +573,9 @@ public class PacketFactory {
FS_Dialog dialog FS_Dialog dialog
) { ) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundShowDialogPacketImpl(dialog);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundShowDialogPacketImpl(dialog); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundShowDialogPacketImpl(dialog);
} }
@@ -549,6 +594,9 @@ public class PacketFactory {
*/ */
public FS_ClientboundClearDialogPacket createClearDialogPacket() { public FS_ClientboundClearDialogPacket createClearDialogPacket() {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.packets.ClientboundClearDialogPacketImpl();
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundClearDialogPacketImpl(); return new de.oliver.fancysitula.versions.v1_21_9.packets.ClientboundClearDialogPacketImpl();
} }

View File

@@ -8,6 +8,9 @@ public class PacketListenerFactory {
public FS_PacketListener createPacketListener(FS_ServerboundPacket.Type packet) { public FS_PacketListener createPacketListener(FS_ServerboundPacket.Type packet) {
switch (ServerVersion.getCurrentVersion()) { switch (ServerVersion.getCurrentVersion()) {
case v1_21_11 -> {
return new de.oliver.fancysitula.versions.v1_21_11.utils.PacketListenerImpl(packet);
}
case v1_21_9, v1_21_10 -> { case v1_21_9, v1_21_10 -> {
return new de.oliver.fancysitula.versions.v1_21_9.utils.PacketListenerImpl(packet); return new de.oliver.fancysitula.versions.v1_21_9.utils.PacketListenerImpl(packet);
} }

Some files were not shown because too many files have changed in this diff Show More