diff --git a/.github/workflows/build-remote.yml b/.github/workflows/build-remote.yml
new file mode 100644
index 000000000..7cb89cc61
--- /dev/null
+++ b/.github/workflows/build-remote.yml
@@ -0,0 +1,47 @@
+name: Build Remote
+
+on:
+ workflow_call:
+ inputs:
+ repository:
+ required: true
+ description: 'The repo of the remote'
+ type: string
+ ref:
+ required: true
+ description: 'The ref of the remote'
+ type: string
+
+permissions: {}
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Set Build Number
+ run: |
+ echo "BUILD_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
+
+ - name: Setup Gradle
+ uses: GeyserMC/actions/setup-gradle-composite@master
+ with:
+ checkout_repository: ${{ inputs.repository }}
+ checkout_ref: ${{ inputs.ref }}
+ setup-java_java-version: 21
+ setup-gradle_cache-read-only: true
+
+ - name: Build Geyser
+ run: ./gradlew build
+
+ - name: Archive Artifacts
+ uses: GeyserMC/actions/upload-multi-artifact@master
+ if: success()
+ with:
+ artifacts: |
+ bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
+ bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
+ bootstrap/standalone/build/libs/Geyser-Standalone.jar
+ bootstrap/spigot/build/libs/Geyser-Spigot.jar
+ bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
+ bootstrap/velocity/build/libs/Geyser-Velocity.jar
+ bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
\ No newline at end of file
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 6c5c15248..ccc4dd79c 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -3,10 +3,14 @@ name: Build
on:
workflow_dispatch:
push:
+ branches-ignore:
+ - 'gh-readonly-queue/**'
paths-ignore:
- '.github/ISSUE_TEMPLATE/*.yml'
- - '.github/actions/pullrequest.yml'
- - '.idea/copyright/*.xml'
+ - '.github/workflows/build-remote.yml'
+ - '.github/workflows/preview.yml'
+ - '.github/workflows/pull-request.yml'
+ - '.idea/copyright/*.xml'
- '.gitignore'
- 'CONTRIBUTING.md'
- 'LICENSE'
@@ -18,112 +22,99 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - name: Checkout repository and submodules
- # See https://github.com/actions/checkout/commits
- uses: actions/checkout@72f2cec99f417b1a1c5e2e88945068983b7965f9
+ - name: Get Release Info
+ id: release-info
+ uses: GeyserMC/actions/previous-release@master
with:
- submodules: recursive
+ data: ${{ vars.RELEASEACTION_PREVRELEASE }}
- - name: Validate Gradle Wrapper
- # See https://github.com/gradle/wrapper-validation-action/commits
- uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4
+ - name: Setup Gradle
+ uses: GeyserMC/actions/setup-gradle-composite@master
+ with:
+ setup-java_java-version: 21
- # See https://github.com/actions/setup-java/commits
- - uses: actions/setup-java@4075bfc1b51bf22876335ae1cd589602d60d8758
- with:
- java-version: 17
- distribution: temurin
+ - name: Build Geyser
+ run: ./gradlew build
+ env:
+ BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }}
- - name: Build
- # See https://github.com/gradle/gradle-build-action/commits
- uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
- with:
- arguments: build
- gradle-home-cache-cleanup: true
-
- - name: Archive artifacts (Geyser Fabric)
- # See https://github.com/actions/upload-artifact/commits
- uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
+ - name: Archive Artifacts
+ uses: GeyserMC/actions/upload-multi-artifact@master
if: success()
with:
- name: Geyser Fabric
- path: bootstrap/fabric/build/libs/Geyser-Fabric.jar
- if-no-files-found: error
- - name: Archive artifacts (Geyser Standalone)
- uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
- if: success()
- with:
- name: Geyser Standalone
- path: bootstrap/standalone/build/libs/Geyser-Standalone.jar
- if-no-files-found: error
- - name: Archive artifacts (Geyser Spigot)
- uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
- if: success()
- with:
- name: Geyser Spigot
- path: bootstrap/spigot/build/libs/Geyser-Spigot.jar
- if-no-files-found: error
- - name: Archive artifacts (Geyser BungeeCord)
- uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
- if: success()
- with:
- name: Geyser BungeeCord
- path: bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
- if-no-files-found: error
- - name: Archive artifacts (Geyser Velocity)
- uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
- if: success()
- with:
- name: Geyser Velocity
- path: bootstrap/velocity/build/libs/Geyser-Velocity.jar
- if-no-files-found: error
+ artifacts: |
+ bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
+ bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
+ bootstrap/standalone/build/libs/Geyser-Standalone.jar
+ bootstrap/spigot/build/libs/Geyser-Spigot.jar
+ bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
+ bootstrap/velocity/build/libs/Geyser-Velocity.jar
+ bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
- name: Publish to Maven Repository
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
- uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
+ run: ./gradlew publish
env:
+ BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }}
ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }}
ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }}
+
+ - name: Get Version
+ if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
+ id: get-version
+ run: |
+ version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2)
+ echo "VERSION=${version}" >> $GITHUB_OUTPUT
+
+ - name: Get Release Metadata
+ if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
+ uses: GeyserMC/actions/release@master
+ id: metadata
with:
- arguments: publish
+ appID: ${{ secrets.RELEASE_APP_ID }}
+ appPrivateKey: ${{ secrets.RELEASE_APP_PK }}
+ files: |
+ bungeecord:bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
+ fabric:bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
+ neoforge:bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
+ spigot:bootstrap/spigot/build/libs/Geyser-Spigot.jar
+ standalone:bootstrap/standalone/build/libs/Geyser-Standalone.jar
+ velocity:bootstrap/velocity/build/libs/Geyser-Velocity.jar
+ viaproxy:bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
+ releaseEnabled: false
+ saveMetadata: true
+ releaseProject: 'geyser'
+ releaseVersion: ${{ steps.get-version.outputs.VERSION }}
- name: Publish to Downloads API
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
- shell: bash
- env:
- DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }}
- DOWNLOADS_PRIVATE_KEY: ${{ secrets.DOWNLOADS_PRIVATE_KEY }}
- DOWNLOADS_SERVER_IP: ${{ secrets.DOWNLOADS_SERVER_IP }}
- run: |
- # Save the private key to a file
- echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa
- chmod 600 id_ecdsa
- # Set the project
- project=geyser
- # Get the version from gradle.properties
- version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2)
- # Create the build folder
- ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$project/$GITHUB_RUN_NUMBER/"
- # Copy over artifacts
- rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" bootstrap/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/
- # Run the build script
- # Push the metadata
- echo "{\"project\": \"$project\", \"version\": \"$version\", \"id\": $GITHUB_RUN_NUMBER, \"commit\": \"$GITHUB_SHA\"}" > metadata.json
- rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/
+ uses: GeyserMC/actions/upload-release@master
+ with:
+ username: ${{ vars.DOWNLOADS_USERNAME }}
+ privateKey: ${{ secrets.DOWNLOADS_PRIVATE_KEY }}
+ host: ${{ secrets.DOWNLOADS_SERVER_IP }}
+ files: |
+ bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
+ bootstrap/mod/fabric/build/libs/Geyser-Fabric.jar
+ bootstrap/mod/neoforge/build/libs/Geyser-NeoForge.jar
+ bootstrap/spigot/build/libs/Geyser-Spigot.jar
+ bootstrap/standalone/build/libs/Geyser-Standalone.jar
+ bootstrap/velocity/build/libs/Geyser-Velocity.jar
+ bootstrap/viaproxy/build/libs/Geyser-ViaProxy.jar
+ changelog: ${{ steps.metadata.outputs.body }}
- name: Publish to Modrinth
- uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }}
env:
+ BUILD_NUMBER: ${{ steps.release-info.outputs.curentRelease }}
MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }}
- with:
- arguments: fabric:modrinth
- gradle-home-cache-cleanup: true
-
+ run: ./gradlew modrinth
+
- name: Notify Discord
if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }}
- # See https://github.com/Tim203/actions-git-discord-webhook/commits
- uses: Tim203/actions-git-discord-webhook@70f38ded3aca51635ec978ab4e1a58cd4cd0c2ff
+ uses: GeyserMC/actions/notify-discord@master
with:
- webhook_url: ${{ secrets.DISCORD_WEBHOOK }}
+ discordWebhook: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ job.status }}
+ body: ${{ steps.metadata.outputs.body }}
+ includeDownloads: ${{ github.ref_name == 'master' }}
diff --git a/.github/workflows/dispatch-preview.yml b/.github/workflows/dispatch-preview.yml
new file mode 100644
index 000000000..83df08e37
--- /dev/null
+++ b/.github/workflows/dispatch-preview.yml
@@ -0,0 +1,33 @@
+name: Dispatch Preview
+
+on:
+ workflow_dispatch:
+ inputs:
+ runId:
+ required: true
+ description: 'ID of the action to pull artifacts from'
+ build:
+ required: true
+ description: 'Build number for the release'
+ version:
+ required: true
+ description: 'Version under which to upload to the Downloads API'
+
+jobs:
+ dispatch-preview:
+ # Allow access to secrets if we are uploading a preview
+ secrets: inherit
+ uses: GeyserMC/actions/.github/workflows/upload-preview.yml@master
+ with:
+ build: ${{ inputs.build }}
+ version: ${{ inputs.version }}
+ files: |
+ bungeecord:Geyser-BungeeCord.jar
+ fabric:Geyser-Fabric.jar
+ neoforge:Geyser-NeoForge.jar
+ spigot:Geyser-Spigot.jar
+ standalone:Geyser-Standalone.jar
+ velocity:Geyser-Velocity.jar
+ viaproxy:Geyser-ViaProxy.jar
+ project: geyserpreview
+ runId: ${{ inputs.runId }}
\ No newline at end of file
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
new file mode 100644
index 000000000..6167bb18e
--- /dev/null
+++ b/.github/workflows/pull-request.yml
@@ -0,0 +1,34 @@
+name: Process Pull Request
+
+on:
+ pull_request_target:
+
+jobs:
+ build:
+ # Forbid access to secrets nor GH Token perms while building the PR
+ permissions: {}
+ secrets: {}
+ uses: GeyserMC/Geyser/.github/workflows/build-remote.yml@master
+ with:
+ repository: ${{ github.event.pull_request.head.repo.full_name }}
+ ref: ${{ github.event.pull_request.head.sha }}
+ preview:
+ needs: [build]
+ if: >-
+ contains(github.event.pull_request.labels.*.name, 'PR: Needs Testing')
+ # Allow access to secrets if we are uploading a preview
+ secrets: inherit
+ uses: GeyserMC/actions/.github/workflows/upload-preview.yml@master
+ with:
+ build: ${{ github.run_number }}
+ version: pr.${{ github.event.pull_request.number }}
+ files: |
+ bungeecord:Geyser-BungeeCord.jar
+ fabric:Geyser-Fabric.jar
+ neoforge:Geyser-NeoForge.jar
+ spigot:Geyser-Spigot.jar
+ standalone:Geyser-Standalone.jar
+ velocity:Geyser-Velocity.jar
+ viaproxy:Geyser-ViaProxy.jar
+ project: geyserpreview
+ runId: ${{ github.run_id }}
\ No newline at end of file
diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml
deleted file mode 100644
index 797d68767..000000000
--- a/.github/workflows/pullrequest.yml
+++ /dev/null
@@ -1,89 +0,0 @@
-name: Build Pull Request
-
-on:
- pull_request:
-
-jobs:
- build:
- runs-on: ubuntu-latest
- steps:
- - name: Set up JDK 17
- # See https://github.com/actions/setup-java/commits
- uses: actions/setup-java@4075bfc1b51bf22876335ae1cd589602d60d8758
- with:
- java-version: 17
- distribution: temurin
-
- - name: Check if the author has forked the API repo
- # See https://github.com/Kas-tle/find-forks-action/commits
- uses: Kas-tle/find-forks-action@1b5447d1e3c7a8ed79583dd817cc5399686eed3a
- id: find_forks
- with:
- owner: GeyserMC
- repo: api
- token: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Use author's API repo if it exists
- if: ${{ steps.find_forks.outputs.target_branch_found == 'true' }}
- env:
- API_FORK_URL: ${{ steps.find_forks.outputs.user_fork_url }}
- API_FORK_BRANCH: ${{ github.event.pull_request.head.ref }}
- run: |
- git clone "${API_FORK_URL}" --single-branch --branch "${API_FORK_BRANCH}" api
- cd api
- ./gradlew publishToMavenLocal
-
- - name: Checkout repository and submodules
- # See https://github.com/actions/checkout/commits
- uses: actions/checkout@72f2cec99f417b1a1c5e2e88945068983b7965f9
- with:
- submodules: recursive
- path: geyser
-
- - name: Validate Gradle Wrapper
- # See https://github.com/gradle/wrapper-validation-action/commits
- uses: gradle/wrapper-validation-action@56b90f209b02bf6d1deae490e9ef18b21a389cd4
-
- - name: Build Geyser
- # See https://github.com/gradle/gradle-build-action/commits
- uses: gradle/gradle-build-action@3bfe3a46584a206fb8361cdedd0647b0c4204232
- with:
- arguments: build
- build-root-directory: geyser
-
- - name: Archive artifacts (Geyser Fabric)
- # See https://github.com/actions/upload-artifact/commits
- uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
- if: success()
- with:
- name: Geyser Fabric
- path: geyser/bootstrap/fabric/build/libs/Geyser-Fabric.jar
- if-no-files-found: error
- - name: Archive artifacts (Geyser Standalone)
- uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
- if: success()
- with:
- name: Geyser Standalone
- path: geyser/bootstrap/standalone/build/libs/Geyser-Standalone.jar
- if-no-files-found: error
- - name: Archive artifacts (Geyser Spigot)
- uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
- if: success()
- with:
- name: Geyser Spigot
- path: geyser/bootstrap/spigot/build/libs/Geyser-Spigot.jar
- if-no-files-found: error
- - name: Archive artifacts (Geyser BungeeCord)
- uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
- if: success()
- with:
- name: Geyser BungeeCord
- path: geyser/bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar
- if-no-files-found: error
- - name: Archive artifacts (Geyser Velocity)
- uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32
- if: success()
- with:
- name: Geyser Velocity
- path: geyser/bootstrap/velocity/build/libs/Geyser-Velocity.jar
- if-no-files-found: error
diff --git a/.idea/copyright/Geyser.xml b/.idea/copyright/Geyser.xml
index c6b553aaf..758c31cbd 100644
--- a/.idea/copyright/Geyser.xml
+++ b/.idea/copyright/Geyser.xml
@@ -1,6 +1,7 @@
-
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index d58e2eb58..c45af73ed 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](https://discord.gg/geysermc)
-[![Crowdin](https://badges.crowdin.net/geyser/localized.svg)](https://translate.geysermc.org/)
+[![Crowdin](https://badges.crowdin.net/e/51361b7f8a01644a238d0fe8f3bddc62/localized.svg)](https://translate.geysermc.org/)
Geyser is a bridge between Minecraft: Bedrock Edition and Minecraft: Java Edition, closing the gap from those wanting to play true cross-platform.
@@ -14,7 +14,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t
Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here!
-### Currently supporting Minecraft Bedrock 1.20.40 - 1.20.61 and Minecraft Java 1.20.4
+### Currently supporting Minecraft Bedrock 1.20.80 - 1.21.0 and Minecraft Java 1.21
## Setting Up
Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser.
@@ -32,7 +32,6 @@ Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Ge
## What's Left to be Added/Fixed
- Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you)
- Some Entity Flags
-- Structure block UI
## What can't be fixed
There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://wiki.geysermc.org/geyser/current-limitations/) page.
diff --git a/api/src/main/java/org/geysermc/geyser/api/bedrock/camera/CameraData.java b/api/src/main/java/org/geysermc/geyser/api/bedrock/camera/CameraData.java
index 2f715fa1e..f208879d1 100644
--- a/api/src/main/java/org/geysermc/geyser/api/bedrock/camera/CameraData.java
+++ b/api/src/main/java/org/geysermc/geyser/api/bedrock/camera/CameraData.java
@@ -145,4 +145,36 @@ public interface CameraData {
* @return whether the camera is currently locked
*/
boolean isCameraLocked();
-}
\ No newline at end of file
+
+ /**
+ * Hides a {@link GuiElement} on the client's side.
+ *
+ * @param element the {@link GuiElement} to hide
+ */
+ void hideElement(@NonNull GuiElement... element);
+
+ /**
+ * Resets a {@link GuiElement} on the client's side.
+ * This makes the client decide on its own - e.g. based on client settings -
+ * whether to show or hide the gui element.
+ *
+ * If no elements are specified, this will reset all currently hidden elements
+ *
+ * @param element the {@link GuiElement} to reset
+ */
+ void resetElement(@NonNull GuiElement @Nullable... element);
+
+ /**
+ * Determines whether a {@link GuiElement} is currently hidden.
+ *
+ * @param element the {@link GuiElement} to check
+ */
+ boolean isHudElementHidden(@NonNull GuiElement element);
+
+ /**
+ * Returns the currently hidden {@link GuiElement}s.
+ *
+ * @return an unmodifiable view of all currently hidden {@link GuiElement}s
+ */
+ @NonNull Set hiddenElements();
+}
diff --git a/api/src/main/java/org/geysermc/geyser/api/bedrock/camera/GuiElement.java b/api/src/main/java/org/geysermc/geyser/api/bedrock/camera/GuiElement.java
new file mode 100644
index 000000000..4d3653648
--- /dev/null
+++ b/api/src/main/java/org/geysermc/geyser/api/bedrock/camera/GuiElement.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.api.bedrock.camera;
+
+/**
+ * Represent GUI elements on the players HUD display.
+ * These can be hidden using {@link CameraData#hideElement(GuiElement...)},
+ * and one can reset their visibility using {@link CameraData#resetElement(GuiElement...)}.
+ */
+public class GuiElement {
+ public static final GuiElement PAPER_DOLL = new GuiElement(0);
+ public static final GuiElement ARMOR = new GuiElement(1);
+ public static final GuiElement TOOL_TIPS = new GuiElement(2);
+ public static final GuiElement TOUCH_CONTROLS = new GuiElement(3);
+ public static final GuiElement CROSSHAIR = new GuiElement(4);
+ public static final GuiElement HOTBAR = new GuiElement(5);
+ public static final GuiElement HEALTH = new GuiElement(6);
+ public static final GuiElement PROGRESS_BAR = new GuiElement(7);
+ public static final GuiElement FOOD_BAR = new GuiElement(8);
+ public static final GuiElement AIR_BUBBLES_BAR = new GuiElement(9);
+ public static final GuiElement VEHICLE_HEALTH = new GuiElement(10);
+ public static final GuiElement EFFECTS_BAR = new GuiElement(11);
+ public static final GuiElement ITEM_TEXT_POPUP = new GuiElement(12);
+
+ private GuiElement(int id) {
+ this.id = id;
+ }
+
+ private final int id;
+
+ /**
+ * Internal use only; don't depend on these values being consistent.
+ */
+ public int id() {
+ return this.id;
+ }
+}
diff --git a/api/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockData.java b/api/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockData.java
index 9f142faab..2605cda21 100644
--- a/api/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockData.java
+++ b/api/src/main/java/org/geysermc/geyser/api/block/custom/CustomBlockData.java
@@ -61,16 +61,16 @@ public interface CustomBlockData {
boolean includedInCreativeInventory();
/**
- * Gets the item's creative category, or tab id.
+ * Gets the block's creative category, or tab id.
*
- * @return the item's creative category
+ * @return the block's creative category
*/
@Nullable CreativeCategory creativeCategory();
/**
- * Gets the item's creative group.
+ * Gets the block's creative group.
*
- * @return the item's creative group
+ * @return the block's creative group
*/
@Nullable String creativeGroup();
diff --git a/api/src/main/java/org/geysermc/geyser/api/block/custom/component/CustomBlockComponents.java b/api/src/main/java/org/geysermc/geyser/api/block/custom/component/CustomBlockComponents.java
index 63788df8e..06608f787 100644
--- a/api/src/main/java/org/geysermc/geyser/api/block/custom/component/CustomBlockComponents.java
+++ b/api/src/main/java/org/geysermc/geyser/api/block/custom/component/CustomBlockComponents.java
@@ -129,8 +129,11 @@ public interface CustomBlockComponents {
* Gets the unit cube component
* Equivalent to "minecraft:unit_cube"
*
+ * @deprecated Use {@link #geometry()} and compare with `minecraft:geometry.full_block` instead.
+ *
* @return The rotation.
*/
+ @Deprecated
boolean unitCube();
/**
@@ -181,6 +184,10 @@ public interface CustomBlockComponents {
Builder transformation(TransformationComponent transformation);
+ /**
+ * @deprecated Use {@link #geometry(GeometryComponent)} with `minecraft:geometry.full_block` instead.
+ */
+ @Deprecated
Builder unitCube(boolean unitCube);
Builder placeAir(boolean placeAir);
diff --git a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoginEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoginEvent.java
index c3c8198c1..86a5ec6f8 100644
--- a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoginEvent.java
+++ b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionLoginEvent.java
@@ -32,18 +32,27 @@ import org.geysermc.geyser.api.connection.GeyserConnection;
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
import org.geysermc.geyser.api.network.RemoteServer;
+import java.util.Map;
+import java.util.Objects;
+
/**
- * Called when a session has logged in, and is about to connect to a remote java server.
+ * Called when a session has logged in, and is about to connect to a remote Java server.
* This event is cancellable, and can be used to prevent the player from connecting to the remote server.
*/
public final class SessionLoginEvent extends ConnectionEvent implements Cancellable {
private RemoteServer remoteServer;
private boolean cancelled;
private String disconnectReason;
+ private Map cookies;
+ private boolean transferring;
- public SessionLoginEvent(@NonNull GeyserConnection connection, @NonNull RemoteServer remoteServer) {
+ public SessionLoginEvent(@NonNull GeyserConnection connection,
+ @NonNull RemoteServer remoteServer,
+ @NonNull Map cookies) {
super(connection);
this.remoteServer = remoteServer;
+ this.cookies = cookies;
+ this.transferring = false;
}
/**
@@ -90,9 +99,9 @@ public final class SessionLoginEvent extends ConnectionEvent implements Cancella
}
/**
- * Gets the {@link RemoteServer} the section will attempt to connect to.
+ * Gets the {@link RemoteServer} the session will attempt to connect to.
*
- * @return the {@link RemoteServer} the section will attempt to connect to.
+ * @return the {@link RemoteServer} the session will attempt to connect to.
*/
public @NonNull RemoteServer remoteServer() {
return this.remoteServer;
@@ -106,4 +115,36 @@ public final class SessionLoginEvent extends ConnectionEvent implements Cancella
public void remoteServer(@NonNull RemoteServer remoteServer) {
this.remoteServer = remoteServer;
}
+
+ /**
+ * Sets a map of cookies from a possible previous session. The Java server can send and request these
+ * to store information on the client across server transfers.
+ */
+ public void cookies(@NonNull Map cookies) {
+ Objects.requireNonNull(cookies);
+ this.cookies = cookies;
+ }
+
+ /**
+ * Gets a map of the sessions cookies, if set.
+ * @return the connections cookies
+ */
+ public @NonNull Map cookies() {
+ return cookies;
+ }
+
+ /**
+ * Determines the connection intent of the connection
+ */
+ public void transferring(boolean transferring) {
+ this.transferring = transferring;
+ }
+
+ /**
+ * Gets whether this login attempt to the Java server
+ * has the transfer intent
+ */
+ public boolean transferring() {
+ return this.transferring;
+ }
}
diff --git a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionSkinApplyEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionSkinApplyEvent.java
new file mode 100644
index 000000000..f22241e41
--- /dev/null
+++ b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/SessionSkinApplyEvent.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.api.event.bedrock;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.geysermc.geyser.api.connection.GeyserConnection;
+import org.geysermc.geyser.api.event.connection.ConnectionEvent;
+import org.geysermc.geyser.api.skin.Cape;
+import org.geysermc.geyser.api.skin.Skin;
+import org.geysermc.geyser.api.skin.SkinData;
+import org.geysermc.geyser.api.skin.SkinGeometry;
+
+import java.util.UUID;
+
+/**
+ * Called when a skin is applied to a player.
+ *
+ * Won't be called when a fake player is spawned for a player skull.
+ */
+public abstract class SessionSkinApplyEvent extends ConnectionEvent {
+
+ private final String username;
+ private final UUID uuid;
+ private final boolean slim;
+ private final boolean bedrock;
+ private final SkinData originalSkinData;
+
+ public SessionSkinApplyEvent(@NonNull GeyserConnection connection, String username, UUID uuid, boolean slim, boolean bedrock, SkinData skinData) {
+ super(connection);
+ this.username = username;
+ this.uuid = uuid;
+ this.slim = slim;
+ this.bedrock = bedrock;
+ this.originalSkinData = skinData;
+ }
+
+ /**
+ * The username of the player.
+ *
+ * @return the username of the player
+ */
+ public @NonNull String username() {
+ return username;
+ }
+
+ /**
+ * The UUID of the player.
+ *
+ * @return the UUID of the player
+ */
+ public @NonNull UUID uuid() {
+ return uuid;
+ }
+
+ /**
+ * If the player is using a slim model.
+ *
+ * @return if the player is using a slim model
+ */
+ public boolean slim() {
+ return slim;
+ }
+
+ /**
+ * If the player is a Bedrock player.
+ *
+ * @return if the player is a Bedrock player
+ */
+ public boolean bedrock() {
+ return bedrock;
+ }
+
+ /**
+ * The original skin data of the player.
+ *
+ * @return the original skin data of the player
+ */
+ public @NonNull SkinData originalSkin() {
+ return originalSkinData;
+ }
+
+ /**
+ * The skin data of the player.
+ *
+ * @return the current skin data of the player
+ */
+ public abstract @NonNull SkinData skinData();
+
+ /**
+ * Change the skin of the player.
+ *
+ * @param newSkin the new skin
+ */
+ public abstract void skin(@NonNull Skin newSkin);
+
+ /**
+ * Change the cape of the player.
+ *
+ * @param newCape the new cape
+ */
+ public abstract void cape(@NonNull Cape newCape);
+
+ /**
+ * Change the geometry of the player.
+ *
+ * @param newGeometry the new geometry
+ */
+ public abstract void geometry(@NonNull SkinGeometry newGeometry);
+
+ /**
+ * Change the geometry of the player.
+ *
+ * Constructs a generic {@link SkinGeometry} object with the given data.
+ *
+ * @param geometryName the name of the geometry
+ * @param geometryData the data of the geometry
+ */
+ public void geometry(@NonNull String geometryName, @NonNull String geometryData) {
+ geometry(new SkinGeometry("{\"geometry\" :{\"default\" :\"" + geometryName + "\"}}", geometryData));
+ }
+}
diff --git a/api/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionRequestEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionRequestEvent.java
new file mode 100644
index 000000000..b36ee8bfb
--- /dev/null
+++ b/api/src/main/java/org/geysermc/geyser/api/event/connection/ConnectionRequestEvent.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.api.event.connection;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.geysermc.event.Cancellable;
+import org.geysermc.event.Event;
+
+import java.net.InetSocketAddress;
+
+/**
+ * Called whenever a client attempts to connect to the server, before the connection is accepted.
+ */
+public final class ConnectionRequestEvent implements Event, Cancellable {
+
+ private boolean cancelled;
+ private final InetSocketAddress ip;
+ private final InetSocketAddress proxyIp;
+
+ public ConnectionRequestEvent(@NonNull InetSocketAddress ip, @Nullable InetSocketAddress proxyIp) {
+ this.ip = ip;
+ this.proxyIp = proxyIp;
+ }
+
+ /**
+ * The IP address of the client attempting to connect
+ *
+ * @return the IP address of the client attempting to connect
+ * @deprecated Use {@link #inetSocketAddress()} instead
+ */
+ @NonNull @Deprecated(forRemoval = true)
+ public InetSocketAddress getInetSocketAddress() {
+ return ip;
+ }
+
+ /**
+ * The IP address of the proxy handling the connection. It will return null if there is no proxy.
+ *
+ * @return the IP address of the proxy handling the connection
+ * @deprecated Use {@link #proxyIp()} instead
+ */
+ @Nullable @Deprecated(forRemoval = true)
+ public InetSocketAddress getProxyIp() {
+ return proxyIp;
+ }
+
+ /**
+ * The IP address of the client attempting to connect
+ *
+ * @return the IP address of the client attempting to connect
+ */
+ @NonNull
+ public InetSocketAddress inetSocketAddress() {
+ return ip;
+ }
+
+ /**
+ * The IP address of the proxy handling the connection. It will return null if there is no proxy.
+ *
+ * @return the IP address of the proxy handling the connection
+ */
+ @Nullable
+ public InetSocketAddress proxyIp() {
+ return proxyIp;
+ }
+
+ /**
+ * The cancel status of this event. If this event is cancelled, the connection will be rejected.
+ *
+ * @return the cancel status of this event
+ */
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+ /**
+ * Sets the cancel status of this event. If this event is canceled, the connection will be rejected.
+ *
+ * @param cancelled the cancel status of this event.
+ */
+ @Override
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+}
diff --git a/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java
new file mode 100644
index 000000000..594e28ef0
--- /dev/null
+++ b/api/src/main/java/org/geysermc/geyser/api/event/java/ServerTransferEvent.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.api.event.java;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.common.value.qual.IntRange;
+import org.geysermc.geyser.api.connection.GeyserConnection;
+import org.geysermc.geyser.api.event.connection.ConnectionEvent;
+
+import java.util.Map;
+
+/**
+ * Fired when the Java server sends a transfer request to a different Java server.
+ * Geyser Extensions can listen to this event and set a target server ip/port for Bedrock players to be transferred to.
+ */
+public class ServerTransferEvent extends ConnectionEvent {
+
+ private final String host;
+ private final int port;
+ private String bedrockHost;
+ private int bedrockPort;
+ private final Map cookies;
+
+ public ServerTransferEvent(@NonNull GeyserConnection connection,
+ @NonNull String host, int port, @NonNull Map cookies) {
+ super(connection);
+ this.host = host;
+ this.port = port;
+ this.cookies = cookies;
+ this.bedrockHost = null;
+ this.bedrockPort = -1;
+ }
+
+ /**
+ * The host that the Java server requests a transfer to.
+ *
+ * @return the host
+ */
+ public @NonNull String host() {
+ return this.host;
+ }
+
+ /**
+ * The port that the Java server requests a transfer to.
+ *
+ * @return the port
+ */
+ public int port() {
+ return this.port;
+ }
+
+ /**
+ * The host that the Bedrock player should try and connect to.
+ * If this is not set, the Bedrock player will just be disconnected.
+ *
+ * @return the host where the Bedrock client will be transferred to, or null if not set.
+ */
+ public @Nullable String bedrockHost() {
+ return this.bedrockHost;
+ }
+
+ /**
+ * The port that the Bedrock player should try and connect to.
+ * If this is not set, the Bedrock player will just be disconnected.
+ *
+ * @return the port where the Bedrock client will be transferred to, or -1 if not set.
+ */
+ public int bedrockPort() {
+ return this.bedrockPort;
+ }
+
+ /**
+ * Sets the host for the Bedrock player to be transferred to
+ */
+ public void bedrockHost(@NonNull String host) {
+ if (host == null || host.isBlank()) {
+ throw new IllegalArgumentException("Server address cannot be null or blank");
+ }
+ this.bedrockHost = host;
+ }
+
+ /**
+ * Sets the port for the Bedrock player to be transferred to
+ */
+ public void bedrockPort(@IntRange(from = 0, to = 65535) int port) {
+ if (port < 0 || port > 65535) {
+ throw new IllegalArgumentException("Server port must be between 0 and 65535, was " + port);
+ }
+ this.bedrockPort = port;
+ }
+
+ /**
+ * Gets a map of the sessions current cookies.
+ *
+ * @return the connections cookies
+ */
+ public @NonNull Map cookies() {
+ return cookies;
+ }
+
+}
diff --git a/api/src/main/java/org/geysermc/geyser/api/item/custom/CustomItemData.java b/api/src/main/java/org/geysermc/geyser/api/item/custom/CustomItemData.java
index 404679e60..3b871cd74 100644
--- a/api/src/main/java/org/geysermc/geyser/api/item/custom/CustomItemData.java
+++ b/api/src/main/java/org/geysermc/geyser/api/item/custom/CustomItemData.java
@@ -29,6 +29,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.api.GeyserApi;
+import java.util.OptionalInt;
import java.util.Set;
/**
@@ -77,6 +78,20 @@ public interface CustomItemData {
*/
boolean displayHandheld();
+ /**
+ * Gets the item's creative category, or tab id.
+ *
+ * @return the item's creative category
+ */
+ @NonNull OptionalInt creativeCategory();
+
+ /**
+ * Gets the item's creative group.
+ *
+ * @return the item's creative group
+ */
+ @Nullable String creativeGroup();
+
/**
* Gets the item's texture size. This is to resize the item if the texture is not 16x16.
*
@@ -119,6 +134,10 @@ public interface CustomItemData {
Builder displayHandheld(boolean displayHandheld);
+ Builder creativeCategory(int creativeCategory);
+
+ Builder creativeGroup(@Nullable String creativeGroup);
+
Builder textureSize(int textureSize);
Builder renderOffsets(@Nullable CustomRenderOffsets renderOffsets);
diff --git a/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java b/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java
index 616a5bba6..2c283780c 100644
--- a/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java
+++ b/api/src/main/java/org/geysermc/geyser/api/item/custom/NonVanillaCustomItemData.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -30,7 +30,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.api.GeyserApi;
-import java.util.OptionalInt;
import java.util.Set;
/**
@@ -65,6 +64,14 @@ public interface NonVanillaCustomItemData extends CustomItemData {
*/
int maxDamage();
+ /**
+ * Gets the attack damage of the item.
+ * This is purely visual, and only applied to tools
+ *
+ * @return the attack damage of the item
+ */
+ int attackDamage();
+
/**
* Gets the tool type of the item.
*
@@ -107,20 +114,6 @@ public interface NonVanillaCustomItemData extends CustomItemData {
*/
@Nullable Set repairMaterials();
- /**
- * Gets the item's creative category, or tab id.
- *
- * @return the item's creative category
- */
- @NonNull OptionalInt creativeCategory();
-
- /**
- * Gets the item's creative group.
- *
- * @return the item's creative group
- */
- @Nullable String creativeGroup();
-
/**
* Gets if the item is a hat. This is used to determine if the item should be rendered on the player's head, and
* normally allow the player to equip it. This is not meant for armor.
@@ -168,6 +161,13 @@ public interface NonVanillaCustomItemData extends CustomItemData {
return displayHandheld();
}
+ /**
+ * Gets the block the item places.
+ *
+ * @return the block the item places
+ */
+ String block();
+
static NonVanillaCustomItemData.Builder builder() {
return GeyserApi.api().provider(NonVanillaCustomItemData.Builder.class);
}
@@ -184,6 +184,8 @@ public interface NonVanillaCustomItemData extends CustomItemData {
Builder maxDamage(int maxDamage);
+ Builder attackDamage(int attackDamage);
+
Builder toolType(@Nullable String toolType);
Builder toolTier(@Nullable String toolTier);
@@ -196,10 +198,6 @@ public interface NonVanillaCustomItemData extends CustomItemData {
Builder repairMaterials(@Nullable Set repairMaterials);
- Builder creativeCategory(int creativeCategory);
-
- Builder creativeGroup(@Nullable String creativeGroup);
-
Builder hat(boolean isHat);
Builder foil(boolean isFoil);
@@ -210,6 +208,8 @@ public interface NonVanillaCustomItemData extends CustomItemData {
Builder chargeable(boolean isChargeable);
+ Builder block(String block);
+
/**
* @deprecated Use {@link #displayHandheld(boolean)} instead.
*/
@@ -218,6 +218,12 @@ public interface NonVanillaCustomItemData extends CustomItemData {
return displayHandheld(isTool);
}
+ @Override
+ Builder creativeCategory(int creativeCategory);
+
+ @Override
+ Builder creativeGroup(@Nullable String creativeGroup);
+
@Override
Builder customItemOptions(@NonNull CustomItemOptions customItemOptions);
diff --git a/api/src/main/java/org/geysermc/geyser/api/pack/PathPackCodec.java b/api/src/main/java/org/geysermc/geyser/api/pack/PathPackCodec.java
index ee5db8242..a3770451a 100644
--- a/api/src/main/java/org/geysermc/geyser/api/pack/PathPackCodec.java
+++ b/api/src/main/java/org/geysermc/geyser/api/pack/PathPackCodec.java
@@ -42,4 +42,4 @@ public abstract class PathPackCodec extends PackCodec {
*/
@NonNull
public abstract Path path();
-}
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/geysermc/geyser/util/collection/package-info.java b/api/src/main/java/org/geysermc/geyser/api/skin/Cape.java
similarity index 66%
rename from core/src/main/java/org/geysermc/geyser/util/collection/package-info.java
rename to api/src/main/java/org/geysermc/geyser/api/skin/Cape.java
index 46fa5df11..1e7341ae4 100644
--- a/core/src/main/java/org/geysermc/geyser/util/collection/package-info.java
+++ b/api/src/main/java/org/geysermc/geyser/api/skin/Cape.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,12 +23,18 @@
* @link https://github.com/GeyserMC/Geyser
*/
+package org.geysermc.geyser.api.skin;
+
/**
- * Contains useful collections for use in Geyser.
- *
- * Of note are the fixed int maps. Designed for use with block states that are positive and sequential, they do not allow keys to be
- * added that are not greater by one versus the previous key. Because of this, speedy operations of {@link java.util.Map#get(java.lang.Object)}
- * and {@link java.util.Map#containsKey(java.lang.Object)} can be performed by simply checking the bounds of the map
- * size and its "start" integer.
+ * Represents a cape.
+ *
+ * @param textureUrl The URL of the cape texture
+ * @param capeId The ID of the cape
+ * @param capeData The raw cape image data in ARGB format
+ * @param failed If the cape failed to load, this is for things like fallback capes
*/
-package org.geysermc.geyser.util.collection;
\ No newline at end of file
+public record Cape(String textureUrl, String capeId, byte[] capeData, boolean failed) {
+ public Cape(String textureUrl, String capeId, byte[] capeData) {
+ this(textureUrl, capeId, capeData, false);
+ }
+}
diff --git a/api/src/main/java/org/geysermc/geyser/api/skin/Skin.java b/api/src/main/java/org/geysermc/geyser/api/skin/Skin.java
new file mode 100644
index 000000000..9b39ddfe8
--- /dev/null
+++ b/api/src/main/java/org/geysermc/geyser/api/skin/Skin.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.api.skin;
+
+/**
+ * Represents a skin.
+ *
+ * @param textureUrl The URL/ID of the skin texture
+ * @param skinData The raw skin image data in ARGB
+ * @param failed If the skin failed to load, this is for things like fallback skins
+ */
+public record Skin(String textureUrl, byte[] skinData, boolean failed) {
+ public Skin(String textureUrl, byte[] skinData) {
+ this(textureUrl, skinData, false);
+ }
+}
diff --git a/api/src/main/java/org/geysermc/geyser/api/skin/SkinData.java b/api/src/main/java/org/geysermc/geyser/api/skin/SkinData.java
new file mode 100644
index 000000000..9de4a3534
--- /dev/null
+++ b/api/src/main/java/org/geysermc/geyser/api/skin/SkinData.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.api.skin;
+
+/**
+ * Represents a full package of {@link Skin}, {@link Cape}, and {@link SkinGeometry}.
+ */
+public record SkinData(Skin skin, Cape cape, SkinGeometry geometry) {
+}
diff --git a/api/src/main/java/org/geysermc/geyser/api/skin/SkinGeometry.java b/api/src/main/java/org/geysermc/geyser/api/skin/SkinGeometry.java
new file mode 100644
index 000000000..5b40d2022
--- /dev/null
+++ b/api/src/main/java/org/geysermc/geyser/api/skin/SkinGeometry.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.api.skin;
+
+/**
+ * Represents geometry of a skin.
+ *
+ * @param geometryName The name of the geometry (JSON)
+ * @param geometryData The geometry data (JSON)
+ */
+public record SkinGeometry(String geometryName, String geometryData) {
+
+ public static SkinGeometry WIDE = getLegacy(false);
+ public static SkinGeometry SLIM = getLegacy(true);
+
+ /**
+ * Generate generic geometry
+ *
+ * @param isSlim if true, it will be the slimmer alex model
+ * @return The generic geometry object
+ */
+ private static SkinGeometry getLegacy(boolean isSlim) {
+ return new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.custom" + (isSlim ? "Slim" : "") + "\"}}", "");
+ }
+}
diff --git a/api/src/main/java/org/geysermc/geyser/api/util/CreativeCategory.java b/api/src/main/java/org/geysermc/geyser/api/util/CreativeCategory.java
index 207320b1e..245eb9bc2 100644
--- a/api/src/main/java/org/geysermc/geyser/api/util/CreativeCategory.java
+++ b/api/src/main/java/org/geysermc/geyser/api/util/CreativeCategory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -31,11 +31,10 @@ import org.checkerframework.checker.nullness.qual.NonNull;
* Represents the creative menu categories or tabs.
*/
public enum CreativeCategory {
- COMMANDS("commands", 1),
- CONSTRUCTION("construction", 2),
+ CONSTRUCTION("construction", 1),
+ NATURE("nature", 2),
EQUIPMENT("equipment", 3),
ITEMS("items", 4),
- NATURE("nature", 5),
NONE("none", 6);
private final String internalName;
diff --git a/api/src/main/java/org/geysermc/geyser/api/util/PlatformType.java b/api/src/main/java/org/geysermc/geyser/api/util/PlatformType.java
index 815381d6b..cda5e06e4 100644
--- a/api/src/main/java/org/geysermc/geyser/api/util/PlatformType.java
+++ b/api/src/main/java/org/geysermc/geyser/api/util/PlatformType.java
@@ -34,10 +34,12 @@ public record PlatformType(String platformName) {
public static final PlatformType ANDROID = new PlatformType("Android");
public static final PlatformType BUNGEECORD = new PlatformType("BungeeCord");
public static final PlatformType FABRIC = new PlatformType("Fabric");
+ public static final PlatformType NEOFORGE = new PlatformType("NeoForge");
public static final PlatformType SPIGOT = new PlatformType("Spigot");
@Deprecated
public static final PlatformType SPONGE = new PlatformType("Sponge");
public static final PlatformType STANDALONE = new PlatformType("Standalone");
public static final PlatformType VELOCITY = new PlatformType("Velocity");
+ public static final PlatformType VIAPROXY = new PlatformType("ViaProxy");
}
diff --git a/bootstrap/bungeecord/build.gradle.kts b/bootstrap/bungeecord/build.gradle.kts
index 4025569dd..910e50723 100644
--- a/bootstrap/bungeecord/build.gradle.kts
+++ b/bootstrap/bungeecord/build.gradle.kts
@@ -1,7 +1,7 @@
dependencies {
api(projects.core)
-
implementation(libs.adventure.text.serializer.bungeecord)
+ compileOnlyApi(libs.bungeecord.proxy)
}
platformRelocate("net.md_5.bungee.jni")
@@ -22,6 +22,7 @@ tasks.withType {
dependencies {
exclude(dependency("com.google.*:.*"))
+ exclude(dependency("io.netty.incubator:.*"))
exclude(dependency("io.netty:netty-transport-native-epoll:.*"))
exclude(dependency("io.netty:netty-transport-native-unix-common:.*"))
exclude(dependency("io.netty:netty-handler:.*"))
@@ -33,3 +34,8 @@ tasks.withType {
exclude(dependency("io.netty:netty-resolver-dns:.*"))
}
}
+
+modrinth {
+ uploadFile.set(tasks.getByPath("shadowJar"))
+ loaders.add("bungeecord")
+}
diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java
index daeb20102..e8cf7ee39 100644
--- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java
+++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java
@@ -26,22 +26,19 @@
package org.geysermc.geyser.platform.bungeecord;
import lombok.Getter;
+import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.geysermc.geyser.GeyserLogger;
import java.util.logging.Level;
import java.util.logging.Logger;
+@RequiredArgsConstructor
public class GeyserBungeeLogger implements GeyserLogger {
private final Logger logger;
@Getter @Setter
private boolean debug;
- public GeyserBungeeLogger(Logger logger, boolean debug) {
- this.logger = logger;
- this.debug = debug;
- }
-
@Override
public void severe(String message) {
logger.severe(message);
diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java
index 4191c8578..cd6b59f64 100644
--- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java
+++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java
@@ -58,14 +58,13 @@ import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
-import java.util.logging.Level;
public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
private GeyserCommandManager geyserCommandManager;
private GeyserBungeeConfiguration geyserConfig;
private GeyserBungeeInjector geyserInjector;
- private GeyserBungeeLogger geyserLogger;
+ private final GeyserBungeeLogger geyserLogger = new GeyserBungeeLogger(getLogger());
private IGeyserPingPassthrough geyserBungeePingPassthrough;
private GeyserImpl geyser;
@@ -82,21 +81,21 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
// Copied from ViaVersion.
// https://github.com/ViaVersion/ViaVersion/blob/b8072aad86695cc8ec6f5e4103e43baf3abf6cc5/bungee/src/main/java/us/myles/ViaVersion/BungeePlugin.java#L43
try {
- ProtocolConstants.class.getField("MINECRAFT_1_20_3");
+ ProtocolConstants.class.getField("MINECRAFT_1_21");
} catch (NoSuchFieldException e) {
- getLogger().warning(" / \\");
- getLogger().warning(" / \\");
- getLogger().warning(" / | \\");
- getLogger().warning(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName()));
- getLogger().warning(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
- getLogger().warning(" / o \\");
- getLogger().warning("/_____________\\");
+ geyserLogger.error(" / \\");
+ geyserLogger.error(" / \\");
+ geyserLogger.error(" / | \\");
+ geyserLogger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", getProxy().getName()));
+ geyserLogger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
+ geyserLogger.error(" / o \\");
+ geyserLogger.error("/_____________\\");
}
if (!this.loadConfig()) {
return;
}
- this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode());
+ this.geyserLogger.setDebug(geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
this.geyser = GeyserImpl.load(PlatformType.BUNGEECORD, this);
this.geyserInjector = new GeyserBungeeInjector(this);
@@ -293,7 +292,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap {
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class);
} catch (IOException ex) {
- getLogger().log(Level.SEVERE, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
+ geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
ex.printStackTrace();
return false;
}
diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts
deleted file mode 100644
index 66af130b3..000000000
--- a/bootstrap/fabric/build.gradle.kts
+++ /dev/null
@@ -1,124 +0,0 @@
-import net.fabricmc.loom.task.RemapJarTask
-
-plugins {
- id("fabric-loom") version "1.0-SNAPSHOT"
- id("com.modrinth.minotaur") version "2.+"
-}
-
-dependencies {
- //to change the versions see the gradle.properties file
- minecraft(libs.fabric.minecraft)
- mappings(loom.officialMojangMappings())
- modImplementation(libs.fabric.loader)
-
- // Fabric API. This is technically optional, but you probably want it anyway.
- modImplementation(libs.fabric.api)
-
- // This should be in the libs TOML, but something about modImplementation AND include just doesn't work
- include(modImplementation("me.lucko", "fabric-permissions-api", "0.2-SNAPSHOT"))
-
- // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs.
- // You may need to force-disable transitiveness on them.
-
- api(projects.core)
- shadow(projects.core) {
- exclude(group = "com.google.guava", module = "guava")
- exclude(group = "com.google.code.gson", module = "gson")
- exclude(group = "org.slf4j")
- exclude(group = "com.nukkitx.fastutil")
- exclude(group = "io.netty.incubator")
- }
-}
-
-loom {
- mixin.defaultRefmapName.set("geyser-fabric-refmap.json")
-}
-
-repositories {
- mavenLocal()
- maven("https://repo.opencollab.dev/maven-releases/")
- maven("https://repo.opencollab.dev/maven-snapshots/")
- maven("https://jitpack.io")
- maven("https://oss.sonatype.org/content/repositories/snapshots/")
- maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
-}
-
-application {
- mainClass.set("org.geysermc.geyser.platform.fabric.GeyserFabricMain")
-}
-
-tasks {
- // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
- // if it is present.
- // If you remove this task, sources will not be generated.
- sourcesJar {
- archiveClassifier.set("sources")
- from(sourceSets.main.get().allSource)
- }
-
- shadowJar {
- // Mirrors the example fabric project, otherwise tons of dependencies are shaded that shouldn't be
- configurations = listOf(project.configurations.shadow.get())
- // The remapped shadowJar is the final desired Geyser-Fabric.jar
- archiveVersion.set(project.version.toString())
- archiveClassifier.set("shaded")
-
- relocate("org.objectweb.asm", "org.geysermc.relocate.asm")
- relocate("org.yaml", "org.geysermc.relocate.yaml") // https://github.com/CardboardPowered/cardboard/issues/139
- relocate("com.fasterxml.jackson", "org.geysermc.relocate.jackson")
- relocate("net.kyori", "org.geysermc.relocate.kyori")
-
- dependencies {
- // Exclude everything EXCEPT some DNS stuff required for HAProxy
- exclude(dependency("io.netty:netty-transport-classes-epoll:.*"))
- exclude(dependency("io.netty:netty-transport-native-epoll:.*"))
- exclude(dependency("io.netty:netty-transport-native-unix-common:.*"))
- exclude(dependency("io.netty:netty-transport-classes-kqueue:.*"))
- exclude(dependency("io.netty:netty-transport-native-kqueue:.*"))
- exclude(dependency("io.netty:netty-handler:.*"))
- exclude(dependency("io.netty:netty-common:.*"))
- exclude(dependency("io.netty:netty-buffer:.*"))
- exclude(dependency("io.netty:netty-resolver:.*"))
- exclude(dependency("io.netty:netty-transport:.*"))
- exclude(dependency("io.netty:netty-codec:.*"))
- exclude(dependency("io.netty:netty-resolver-dns:.*"))
- exclude(dependency("io.netty:netty-resolver-dns-native-macos:.*"))
- }
- }
-
- remapJar {
- dependsOn(shadowJar)
- inputFile.set(shadowJar.get().archiveFile)
- archiveBaseName.set("Geyser-Fabric")
- archiveVersion.set("")
- archiveClassifier.set("")
- }
-
- register("remapModrinthJar", RemapJarTask::class) {
- dependsOn(shadowJar)
- inputFile.set(shadowJar.get().archiveFile)
- archiveBaseName.set("geyser-fabric")
- archiveVersion.set(project.version.toString() + "+build." + System.getenv("GITHUB_RUN_NUMBER"))
- archiveClassifier.set("")
- }
-}
-
-modrinth {
- token.set(System.getenv("MODRINTH_TOKEN")) // Even though this is the default value, apparently this prevents GitHub Actions caching the token?
- projectId.set("wKkoqHrH")
- versionNumber.set(project.version as String + "-" + System.getenv("GITHUB_RUN_NUMBER"))
- versionType.set("beta")
- changelog.set("A changelog can be found at https://github.com/GeyserMC/Geyser/commits")
-
- syncBodyFrom.set(rootProject.file("README.md").readText())
-
- uploadFile.set(tasks.getByPath("remapModrinthJar"))
- gameVersions.addAll("1.20.4")
-
- loaders.add("fabric")
- failSilently.set(true)
-
- dependencies {
- required.project("fabric-api")
- }
-}
diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java
deleted file mode 100644
index 9d7b81831..000000000
--- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * @author GeyserMC
- * @link https://github.com/GeyserMC/Geyser
- */
-
-package org.geysermc.geyser.platform.fabric.world;
-
-import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
-import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
-import me.lucko.fabric.api.permissions.v0.Permissions;
-import net.minecraft.core.BlockPos;
-import net.minecraft.nbt.*;
-import net.minecraft.server.MinecraftServer;
-import net.minecraft.server.level.ServerPlayer;
-import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.item.WritableBookItem;
-import net.minecraft.world.item.WrittenBookItem;
-import net.minecraft.world.level.block.entity.BannerBlockEntity;
-import net.minecraft.world.level.block.entity.BlockEntity;
-import net.minecraft.world.level.block.entity.LecternBlockEntity;
-import net.minecraft.world.level.chunk.LevelChunk;
-import org.checkerframework.checker.nullness.qual.NonNull;
-import org.cloudburstmc.math.vector.Vector3i;
-import org.cloudburstmc.nbt.NbtMap;
-import org.cloudburstmc.nbt.NbtMapBuilder;
-import org.cloudburstmc.nbt.NbtType;
-import org.geysermc.erosion.util.LecternUtils;
-import org.geysermc.geyser.level.GeyserWorldManager;
-import org.geysermc.geyser.session.GeyserSession;
-import org.geysermc.geyser.util.BlockEntityUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.CompletableFuture;
-
-public class GeyserFabricWorldManager extends GeyserWorldManager {
- private final MinecraftServer server;
-
- public GeyserFabricWorldManager(MinecraftServer server) {
- this.server = server;
- }
-
- @Override
- public boolean shouldExpectLecternHandled(GeyserSession session) {
- return true;
- }
-
- @Override
- public void sendLecternData(GeyserSession session, int x, int z, List blockEntityInfos) {
- server.execute(() -> {
- ServerPlayer player = getPlayer(session);
- if (player == null) {
- return;
- }
-
- //noinspection resource - level() is just a getter
- LevelChunk chunk = player.level().getChunk(x, z);
- final int chunkBlockX = x << 4;
- final int chunkBlockZ = z << 4;
- //noinspection ForLoopReplaceableByForEach - avoid constructing iterator
- for (int i = 0; i < blockEntityInfos.size(); i++) {
- BlockEntityInfo blockEntityInfo = blockEntityInfos.get(i);
- BlockEntity blockEntity = chunk.getBlockEntity(new BlockPos(chunkBlockX + blockEntityInfo.getX(),
- blockEntityInfo.getY(), chunkBlockZ + blockEntityInfo.getZ()));
- sendLecternData(session, blockEntity, true);
- }
- });
- }
-
- @Override
- public void sendLecternData(GeyserSession session, int x, int y, int z) {
- server.execute(() -> {
- ServerPlayer player = getPlayer(session);
- if (player == null) {
- return;
- }
- //noinspection resource - level() is just a getter
- BlockEntity blockEntity = player.level().getBlockEntity(new BlockPos(x, y, z));
- sendLecternData(session, blockEntity, false);
- });
- }
-
- private void sendLecternData(GeyserSession session, BlockEntity blockEntity, boolean isChunkLoad) {
- if (!(blockEntity instanceof LecternBlockEntity lectern)) {
- return;
- }
-
- int x = blockEntity.getBlockPos().getX();
- int y = blockEntity.getBlockPos().getY();
- int z = blockEntity.getBlockPos().getZ();
-
- if (!lectern.hasBook()) {
- if (!isChunkLoad) {
- BlockEntityUtils.updateBlockEntity(session, LecternUtils.getBaseLecternTag(x, y, z, 0).build(), Vector3i.from(x, y, z));
- }
- return;
- }
-
- ItemStack book = lectern.getBook();
- int pageCount = WrittenBookItem.getPageCount(book);
- boolean hasBookPages = pageCount > 0;
- NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x, y, z, hasBookPages ? pageCount : 1);
- lecternTag.putInt("page", lectern.getPage() / 2);
- NbtMapBuilder bookTag = NbtMap.builder()
- .putByte("Count", (byte) book.getCount())
- .putShort("Damage", (short) 0)
- .putString("Name", "minecraft:writable_book");
- List pages = new ArrayList<>(hasBookPages ? pageCount : 1);
- if (hasBookPages && WritableBookItem.makeSureTagIsValid(book.getTag())) {
- ListTag listTag = book.getTag().getList("pages", 8);
-
- for (int i = 0; i < listTag.size(); i++) {
- String page = listTag.getString(i);
- NbtMapBuilder pageBuilder = NbtMap.builder()
- .putString("photoname", "")
- .putString("text", page);
- pages.add(pageBuilder.build());
- }
- } else {
- // Empty page
- NbtMapBuilder pageBuilder = NbtMap.builder()
- .putString("photoname", "")
- .putString("text", "");
- pages.add(pageBuilder.build());
- }
-
- bookTag.putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, pages).build());
- lecternTag.putCompound("book", bookTag.build());
- NbtMap blockEntityTag = lecternTag.build();
- BlockEntityUtils.updateBlockEntity(session, blockEntityTag, Vector3i.from(x, y, z));
- }
-
- @Override
- public boolean hasPermission(GeyserSession session, String permission) {
- ServerPlayer player = getPlayer(session);
- return Permissions.check(player, permission);
- }
-
- @Override
- public GameMode getDefaultGameMode(GeyserSession session) {
- return GameMode.byId(server.getDefaultGameType().getId());
- }
-
- @NonNull
- @Override
- public CompletableFuture getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) {
- CompletableFuture future = new CompletableFuture<>();
- server.execute(() -> {
- ServerPlayer player = getPlayer(session);
- if (player == null) {
- future.complete(null);
- return;
- }
-
- BlockPos pos = new BlockPos(x, y, z);
- // Don't create a new block entity if invalid
- //noinspection resource - level() is just a getter
- BlockEntity blockEntity = player.level().getChunkAt(pos).getBlockEntity(pos);
- if (blockEntity instanceof BannerBlockEntity banner) {
- // Potentially exposes other NBT data? But we need to get the NBT data for the banner patterns *and*
- // the banner might have a custom name, both of which a Java client knows and caches
- ItemStack itemStack = banner.getItem();
- var tag = OpenNbtTagVisitor.convert("", itemStack.getOrCreateTag());
-
- future.complete(tag);
- return;
- }
- future.complete(null);
- });
- return future;
- }
-
- private ServerPlayer getPlayer(GeyserSession session) {
- return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid());
- }
-
- // Future considerations: option to clone; would affect arrays
- private static class OpenNbtTagVisitor implements TagVisitor {
- private String currentKey;
- private final com.github.steveice10.opennbt.tag.builtin.CompoundTag root;
- private com.github.steveice10.opennbt.tag.builtin.Tag currentTag;
-
- OpenNbtTagVisitor(String key) {
- root = new com.github.steveice10.opennbt.tag.builtin.CompoundTag(key);
- }
-
- @Override
- public void visitString(StringTag stringTag) {
- currentTag = new com.github.steveice10.opennbt.tag.builtin.StringTag(currentKey, stringTag.getAsString());
- }
-
- @Override
- public void visitByte(ByteTag byteTag) {
- currentTag = new com.github.steveice10.opennbt.tag.builtin.ByteTag(currentKey, byteTag.getAsByte());
- }
-
- @Override
- public void visitShort(ShortTag shortTag) {
- currentTag = new com.github.steveice10.opennbt.tag.builtin.ShortTag(currentKey, shortTag.getAsShort());
- }
-
- @Override
- public void visitInt(IntTag intTag) {
- currentTag = new com.github.steveice10.opennbt.tag.builtin.IntTag(currentKey, intTag.getAsInt());
- }
-
- @Override
- public void visitLong(LongTag longTag) {
- currentTag = new com.github.steveice10.opennbt.tag.builtin.LongTag(currentKey, longTag.getAsLong());
- }
-
- @Override
- public void visitFloat(FloatTag floatTag) {
- currentTag = new com.github.steveice10.opennbt.tag.builtin.FloatTag(currentKey, floatTag.getAsFloat());
- }
-
- @Override
- public void visitDouble(DoubleTag doubleTag) {
- currentTag = new com.github.steveice10.opennbt.tag.builtin.DoubleTag(currentKey, doubleTag.getAsDouble());
- }
-
- @Override
- public void visitByteArray(ByteArrayTag byteArrayTag) {
- currentTag = new com.github.steveice10.opennbt.tag.builtin.ByteArrayTag(currentKey, byteArrayTag.getAsByteArray());
- }
-
- @Override
- public void visitIntArray(IntArrayTag intArrayTag) {
- currentTag = new com.github.steveice10.opennbt.tag.builtin.IntArrayTag(currentKey, intArrayTag.getAsIntArray());
- }
-
- @Override
- public void visitLongArray(LongArrayTag longArrayTag) {
- currentTag = new com.github.steveice10.opennbt.tag.builtin.LongArrayTag(currentKey, longArrayTag.getAsLongArray());
- }
-
- @Override
- public void visitList(ListTag listTag) {
- var newList = new com.github.steveice10.opennbt.tag.builtin.ListTag(currentKey);
- for (Tag tag : listTag) {
- currentKey = "";
- tag.accept(this);
- newList.add(currentTag);
- }
- currentTag = newList;
- }
-
- @Override
- public void visitCompound(@NonNull CompoundTag compoundTag) {
- currentTag = convert(currentKey, compoundTag);
- }
-
- private static com.github.steveice10.opennbt.tag.builtin.CompoundTag convert(String name, CompoundTag compoundTag) {
- OpenNbtTagVisitor visitor = new OpenNbtTagVisitor(name);
- for (String key : compoundTag.getAllKeys()) {
- visitor.currentKey = key;
- Tag tag = Objects.requireNonNull(compoundTag.get(key));
- tag.accept(visitor);
- visitor.root.put(visitor.currentTag);
- }
- return visitor.root;
- }
-
- @Override
- public void visitEnd(@NonNull EndTag endTag) {
- }
- }
-}
diff --git a/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json b/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json
deleted file mode 100644
index aeb051809..000000000
--- a/bootstrap/fabric/src/main/resources/geyser-fabric.mixins.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "required": true,
- "package": "org.geysermc.geyser.platform.fabric.mixin",
- "compatibilityLevel": "JAVA_16",
- "refmap": "geyser-fabric-refmap.json",
- "client": [
- "client.IntegratedServerMixin"
- ],
- "server": [
- "server.MinecraftDedicatedServerMixin"
- ],
- "injectors": {
- "defaultRequire": 1
- }
-}
diff --git a/bootstrap/mod/build.gradle.kts b/bootstrap/mod/build.gradle.kts
new file mode 100644
index 000000000..32224d00b
--- /dev/null
+++ b/bootstrap/mod/build.gradle.kts
@@ -0,0 +1,22 @@
+architectury {
+ common("neoforge", "fabric")
+}
+
+loom {
+ mixin.defaultRefmapName.set("geyser-refmap.json")
+}
+
+afterEvaluate {
+ // We don't need these
+ tasks.named("remapModrinthJar").configure {
+ enabled = false
+ }
+}
+
+dependencies {
+ api(projects.core)
+ compileOnly(libs.mixin)
+
+ // Only here to suppress "unknown enum constant EnvType.CLIENT" warnings. DO NOT USE!
+ compileOnly(libs.fabric.loader)
+}
\ No newline at end of file
diff --git a/bootstrap/mod/fabric/build.gradle.kts b/bootstrap/mod/fabric/build.gradle.kts
new file mode 100644
index 000000000..25bd0af9d
--- /dev/null
+++ b/bootstrap/mod/fabric/build.gradle.kts
@@ -0,0 +1,70 @@
+plugins {
+ application
+}
+
+architectury {
+ platformSetupLoomIde()
+ fabric()
+}
+
+val includeTransitive: Configuration = configurations.getByName("includeTransitive")
+
+dependencies {
+ modImplementation(libs.fabric.loader)
+ modApi(libs.fabric.api)
+
+ api(project(":mod", configuration = "namedElements"))
+ shadow(project(path = ":mod", configuration = "transformProductionFabric")) {
+ isTransitive = false
+ }
+ shadow(projects.core) { isTransitive = false }
+ includeTransitive(projects.core)
+
+ // These are NOT transitively included, and instead shadowed + relocated.
+ // Avoids fabric complaining about non-SemVer versioning
+ shadow(libs.protocol.connection) { isTransitive = false }
+ shadow(libs.protocol.common) { isTransitive = false }
+ shadow(libs.protocol.codec) { isTransitive = false }
+ shadow(libs.mcauthlib) { isTransitive = false }
+ shadow(libs.raknet) { isTransitive = false }
+
+ // Consequences of shading + relocating mcauthlib: shadow/relocate mcpl!
+ shadow(libs.mcprotocollib) { isTransitive = false }
+
+ // Since we also relocate cloudburst protocol: shade erosion common
+ shadow(libs.erosion.common) { isTransitive = false }
+
+ // Let's shade in our own api/common module
+ shadow(projects.api) { isTransitive = false }
+ shadow(projects.common) { isTransitive = false }
+
+ // Permissions
+ modImplementation(libs.fabric.permissions)
+ include(libs.fabric.permissions)
+}
+
+application {
+ mainClass.set("org.geysermc.geyser.platform.fabric.GeyserFabricMain")
+}
+
+relocate("org.cloudburstmc.netty")
+relocate("org.cloudburstmc.protocol")
+relocate("com.github.steveice10.mc.auth")
+
+tasks {
+ remapJar {
+ archiveBaseName.set("Geyser-Fabric")
+ }
+
+ remapModrinthJar {
+ archiveBaseName.set("geyser-fabric")
+ }
+}
+
+modrinth {
+ loaders.add("fabric")
+ uploadFile.set(tasks.getByPath("remapModrinthJar"))
+ dependencies {
+ required.project("fabric-api")
+ }
+}
\ No newline at end of file
diff --git a/bootstrap/mod/fabric/gradle.properties b/bootstrap/mod/fabric/gradle.properties
new file mode 100644
index 000000000..90ee7a259
--- /dev/null
+++ b/bootstrap/mod/fabric/gradle.properties
@@ -0,0 +1 @@
+loom.platform=fabric
\ No newline at end of file
diff --git a/bootstrap/mod/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricBootstrap.java b/bootstrap/mod/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricBootstrap.java
new file mode 100644
index 000000000..c363ade8f
--- /dev/null
+++ b/bootstrap/mod/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricBootstrap.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.fabric;
+
+import me.lucko.fabric.api.permissions.v0.Permissions;
+import net.fabricmc.api.EnvType;
+import net.fabricmc.api.ModInitializer;
+import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
+import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
+import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
+import net.fabricmc.loader.api.FabricLoader;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.world.entity.player.Player;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
+import org.geysermc.geyser.platform.mod.GeyserModUpdateListener;
+
+public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInitializer {
+
+ public GeyserFabricBootstrap() {
+ super(new GeyserFabricPlatform());
+ }
+
+ @Override
+ public void onInitialize() {
+ if (isServer()) {
+ // Set as an event, so we can get the proper IP and port if needed
+ ServerLifecycleEvents.SERVER_STARTED.register((server) -> {
+ this.setServer(server);
+ onGeyserEnable();
+ });
+ } else {
+ ClientLifecycleEvents.CLIENT_STOPPING.register(($)-> {
+ onGeyserShutdown();
+ });
+ }
+
+ // These are only registered once
+ ServerLifecycleEvents.SERVER_STOPPING.register((server) -> {
+ if (isServer()) {
+ onGeyserShutdown();
+ } else {
+ onGeyserDisable();
+ }
+ });
+
+ ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> GeyserModUpdateListener.onPlayReady(handler.getPlayer()));
+
+ this.onGeyserInitialize();
+ }
+
+ @Override
+ public boolean isServer() {
+ return FabricLoader.getInstance().getEnvironmentType().equals(EnvType.SERVER);
+ }
+
+ @Override
+ public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) {
+ return Permissions.check(source, permissionNode);
+ }
+
+ @Override
+ public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel) {
+ return Permissions.check(source, permissionNode, permissionLevel);
+ }
+}
diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java b/bootstrap/mod/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java
similarity index 100%
rename from bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java
rename to bootstrap/mod/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricDumpInfo.java
diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMain.java b/bootstrap/mod/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMain.java
similarity index 100%
rename from bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMain.java
rename to bootstrap/mod/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMain.java
diff --git a/bootstrap/mod/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricPlatform.java b/bootstrap/mod/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricPlatform.java
new file mode 100644
index 000000000..4631ab493
--- /dev/null
+++ b/bootstrap/mod/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricPlatform.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.fabric;
+
+import net.fabricmc.loader.api.FabricLoader;
+import net.fabricmc.loader.api.ModContainer;
+import net.minecraft.server.MinecraftServer;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.geysermc.geyser.api.util.PlatformType;
+import org.geysermc.geyser.dump.BootstrapDumpInfo;
+import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
+import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.Optional;
+
+public class GeyserFabricPlatform implements GeyserModPlatform {
+
+ private final ModContainer mod;
+
+ public GeyserFabricPlatform() {
+ this.mod = FabricLoader.getInstance().getModContainer("geyser-fabric").orElseThrow();
+ }
+
+ @Override
+ public @NonNull PlatformType platformType() {
+ return PlatformType.FABRIC;
+ }
+
+ @Override
+ public @NonNull String configPath() {
+ return "Geyser-Fabric";
+ }
+
+ @Override
+ public @NonNull Path dataFolder(@NonNull String modId) {
+ return FabricLoader.getInstance().getConfigDir().resolve(modId);
+ }
+
+ @Override
+ public @NonNull BootstrapDumpInfo dumpInfo(@NonNull MinecraftServer server) {
+ return new GeyserFabricDumpInfo(server);
+ }
+
+ @Override
+ public boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap) {
+ Optional floodgate = FabricLoader.getInstance().getModContainer("floodgate");
+ if (floodgate.isPresent()) {
+ Path floodgateDataFolder = FabricLoader.getInstance().getConfigDir().resolve("floodgate");
+ bootstrap.getGeyserConfig().loadFloodgate(bootstrap, floodgateDataFolder);
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public @Nullable InputStream resolveResource(@NonNull String resource) {
+ // We need to handle this differently, because Fabric shares the classloader across multiple mods
+ Path path = this.mod.findPath(resource).orElse(null);
+ if (path == null) {
+ return null;
+ }
+
+ try {
+ return path.getFileSystem()
+ .provider()
+ .newInputStream(path);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+}
diff --git a/bootstrap/fabric/src/main/resources/fabric.mod.json b/bootstrap/mod/fabric/src/main/resources/fabric.mod.json
similarity index 61%
rename from bootstrap/fabric/src/main/resources/fabric.mod.json
rename to bootstrap/mod/fabric/src/main/resources/fabric.mod.json
index a192109e2..262f9833a 100644
--- a/bootstrap/fabric/src/main/resources/fabric.mod.json
+++ b/bootstrap/mod/fabric/src/main/resources/fabric.mod.json
@@ -9,23 +9,22 @@
],
"contact": {
"website": "${url}",
- "repo": "https://github.com/GeyserMC/Geyser-Fabric"
+ "repo": "https://github.com/GeyserMC/Geyser"
},
"license": "MIT",
- "icon": "assets/geyser-fabric/icon.png",
+ "icon": "assets/geyser/icon.png",
"environment": "*",
"entrypoints": {
"main": [
- "org.geysermc.geyser.platform.fabric.GeyserFabricMod"
+ "org.geysermc.geyser.platform.fabric.GeyserFabricBootstrap"
]
},
"mixins": [
- "geyser-fabric.mixins.json"
+ "geyser.mixins.json"
],
"depends": {
- "fabricloader": ">=0.15.2",
+ "fabricloader": ">=0.15.11",
"fabric": "*",
- "minecraft": ">=1.20.4",
- "fabric-permissions-api-v0": "*"
+ "minecraft": ">=1.21"
}
}
diff --git a/bootstrap/mod/neoforge/build.gradle.kts b/bootstrap/mod/neoforge/build.gradle.kts
new file mode 100644
index 000000000..e0e7c2dfa
--- /dev/null
+++ b/bootstrap/mod/neoforge/build.gradle.kts
@@ -0,0 +1,59 @@
+plugins {
+ application
+}
+
+// This is provided by "org.cloudburstmc.math.mutable" too, so yeet.
+// NeoForge's class loader is *really* annoying.
+provided("org.cloudburstmc.math", "api")
+
+architectury {
+ platformSetupLoomIde()
+ neoForge()
+}
+
+val includeTransitive: Configuration = configurations.getByName("includeTransitive")
+
+dependencies {
+ // See https://github.com/google/guava/issues/6618
+ modules {
+ module("com.google.guava:listenablefuture") {
+ replacedBy("com.google.guava:guava", "listenablefuture is part of guava")
+ }
+ }
+
+ neoForge(libs.neoforge.minecraft)
+
+ api(project(":mod", configuration = "namedElements"))
+ shadow(project(path = ":mod", configuration = "transformProductionNeoForge")) {
+ isTransitive = false
+ }
+ shadow(projects.core) { isTransitive = false }
+
+ // Let's shade in our own api
+ shadow(projects.api) { isTransitive = false }
+
+ // cannot be shaded, since neoforge will complain if floodgate-neoforge tries to provide this
+ include(projects.common)
+
+ // Include all transitive deps of core via JiJ
+ includeTransitive(projects.core)
+}
+
+application {
+ mainClass.set("org.geysermc.geyser.platform.forge.GeyserNeoForgeMain")
+}
+
+tasks {
+ remapJar {
+ archiveBaseName.set("Geyser-NeoForge")
+ }
+
+ remapModrinthJar {
+ archiveBaseName.set("geyser-neoforge")
+ }
+}
+
+modrinth {
+ loaders.add("neoforge")
+ uploadFile.set(tasks.getByPath("remapModrinthJar"))
+}
\ No newline at end of file
diff --git a/bootstrap/mod/neoforge/gradle.properties b/bootstrap/mod/neoforge/gradle.properties
new file mode 100644
index 000000000..2914393db
--- /dev/null
+++ b/bootstrap/mod/neoforge/gradle.properties
@@ -0,0 +1 @@
+loom.platform=neoforge
\ No newline at end of file
diff --git a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeBootstrap.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeBootstrap.java
new file mode 100644
index 000000000..b97e42389
--- /dev/null
+++ b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeBootstrap.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.neoforge;
+
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.world.entity.player.Player;
+import net.neoforged.fml.ModContainer;
+import net.neoforged.fml.common.Mod;
+import net.neoforged.fml.loading.FMLLoader;
+import net.neoforged.neoforge.common.NeoForge;
+import net.neoforged.neoforge.event.GameShuttingDownEvent;
+import net.neoforged.neoforge.event.entity.player.PlayerEvent;
+import net.neoforged.neoforge.event.server.ServerStartedEvent;
+import net.neoforged.neoforge.event.server.ServerStoppingEvent;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
+import org.geysermc.geyser.platform.mod.GeyserModUpdateListener;
+
+@Mod(ModConstants.MOD_ID)
+public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
+
+ private final GeyserNeoForgePermissionHandler permissionHandler = new GeyserNeoForgePermissionHandler();
+
+ public GeyserNeoForgeBootstrap(ModContainer container) {
+ super(new GeyserNeoForgePlatform(container));
+
+ if (isServer()) {
+ // Set as an event so we can get the proper IP and port if needed
+ NeoForge.EVENT_BUS.addListener(this::onServerStarted);
+ } else {
+ NeoForge.EVENT_BUS.addListener(this::onClientStopping);
+ }
+
+ NeoForge.EVENT_BUS.addListener(this::onServerStopping);
+ NeoForge.EVENT_BUS.addListener(this::onPlayerJoin);
+ NeoForge.EVENT_BUS.addListener(this.permissionHandler::onPermissionGather);
+
+ this.onGeyserInitialize();
+ }
+
+ private void onServerStarted(ServerStartedEvent event) {
+ this.setServer(event.getServer());
+ this.onGeyserEnable();
+ }
+
+ private void onServerStopping(ServerStoppingEvent event) {
+ if (isServer()) {
+ this.onGeyserShutdown();
+ } else {
+ this.onGeyserDisable();
+ }
+ }
+
+ private void onClientStopping(GameShuttingDownEvent ignored) {
+ this.onGeyserShutdown();
+ }
+
+ private void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) {
+ GeyserModUpdateListener.onPlayReady(event.getEntity());
+ }
+
+ @Override
+ public boolean isServer() {
+ return FMLLoader.getDist().isDedicatedServer();
+ }
+
+ @Override
+ public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) {
+ return this.permissionHandler.hasPermission(source, permissionNode);
+ }
+
+ @Override
+ public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel) {
+ return this.permissionHandler.hasPermission(source, permissionNode, permissionLevel);
+ }
+}
diff --git a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeDumpInfo.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeDumpInfo.java
new file mode 100644
index 000000000..623f68d3a
--- /dev/null
+++ b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeDumpInfo.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.neoforge;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import net.minecraft.server.MinecraftServer;
+import net.neoforged.api.distmarker.Dist;
+import net.neoforged.fml.ModList;
+import net.neoforged.fml.loading.FMLLoader;
+import net.neoforged.neoforgespi.language.IModInfo;
+import org.geysermc.geyser.dump.BootstrapDumpInfo;
+import org.geysermc.geyser.text.AsteriskSerializer;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+public class GeyserNeoForgeDumpInfo extends BootstrapDumpInfo {
+
+ private final String platformName;
+ private final String platformVersion;
+ private final String minecraftVersion;
+ private final Dist dist;
+
+ @AsteriskSerializer.Asterisk(isIp = true)
+ private final String serverIP;
+ private final int serverPort;
+ private final boolean onlineMode;
+ private final List mods;
+
+ public GeyserNeoForgeDumpInfo(MinecraftServer server) {
+ this.platformName = FMLLoader.launcherHandlerName();
+ this.platformVersion = FMLLoader.versionInfo().neoForgeVersion();
+ this.minecraftVersion = FMLLoader.versionInfo().mcVersion();
+ this.dist = FMLLoader.getDist();
+ this.serverIP = server.getLocalIp() == null ? "unknown" : server.getLocalIp();
+ this.serverPort = server.getPort();
+ this.onlineMode = server.usesAuthentication();
+ this.mods = new ArrayList<>();
+
+ for (IModInfo mod : ModList.get().getMods()) {
+ this.mods.add(new ModInfo(
+ ModList.get().isLoaded(mod.getModId()),
+ mod.getModId(),
+ mod.getVersion().toString(),
+ mod.getModURL().map(URL::toString).orElse("")
+ ));
+ }
+ }
+
+ @Getter
+ @AllArgsConstructor
+ public static class ModInfo {
+ public boolean enabled;
+ public String name;
+ public String version;
+ public String url;
+ }
+}
\ No newline at end of file
diff --git a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeMain.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeMain.java
new file mode 100644
index 000000000..70bac2a40
--- /dev/null
+++ b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgeMain.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.neoforge;
+
+import org.geysermc.geyser.GeyserMain;
+
+public class GeyserNeoForgeMain extends GeyserMain {
+
+ public static void main(String[] args) {
+ new GeyserNeoForgeMain().displayMessage();
+ }
+
+ @Override
+ public String getPluginType() {
+ return "NeoForge";
+ }
+
+ @Override
+ public String getPluginFolder() {
+ return "mods";
+ }
+}
diff --git a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePermissionHandler.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePermissionHandler.java
new file mode 100644
index 000000000..0a5f8f052
--- /dev/null
+++ b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePermissionHandler.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.neoforge;
+
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.entity.player.Player;
+import net.neoforged.neoforge.server.permission.PermissionAPI;
+import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent;
+import net.neoforged.neoforge.server.permission.nodes.PermissionDynamicContextKey;
+import net.neoforged.neoforge.server.permission.nodes.PermissionNode;
+import net.neoforged.neoforge.server.permission.nodes.PermissionType;
+import net.neoforged.neoforge.server.permission.nodes.PermissionTypes;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.geysermc.geyser.Constants;
+import org.geysermc.geyser.GeyserImpl;
+import org.geysermc.geyser.api.command.Command;
+import org.geysermc.geyser.command.GeyserCommandManager;
+
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+import java.util.Map;
+
+public class GeyserNeoForgePermissionHandler {
+
+ private static final Constructor> PERMISSION_NODE_CONSTRUCTOR;
+
+ static {
+ try {
+ @SuppressWarnings("rawtypes")
+ Constructor constructor = PermissionNode.class.getDeclaredConstructor(
+ String.class,
+ PermissionType.class,
+ PermissionNode.PermissionResolver.class,
+ PermissionDynamicContextKey[].class
+ );
+ constructor.setAccessible(true);
+ PERMISSION_NODE_CONSTRUCTOR = constructor;
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("Unable to construct PermissionNode!", e);
+ }
+ }
+
+ private final Map> permissionNodes = new HashMap<>();
+
+ public void onPermissionGather(PermissionGatherEvent.Nodes event) {
+ this.registerNode(Constants.UPDATE_PERMISSION, event);
+
+ GeyserCommandManager commandManager = GeyserImpl.getInstance().commandManager();
+ for (Map.Entry entry : commandManager.commands().entrySet()) {
+ Command command = entry.getValue();
+
+ // Don't register aliases
+ if (!command.name().equals(entry.getKey())) {
+ continue;
+ }
+
+ this.registerNode(command.permission(), event);
+ }
+
+ for (Map commands : commandManager.extensionCommands().values()) {
+ for (Map.Entry entry : commands.entrySet()) {
+ Command command = entry.getValue();
+
+ // Don't register aliases
+ if (!command.name().equals(entry.getKey())) {
+ continue;
+ }
+
+ this.registerNode(command.permission(), event);
+ }
+ }
+ }
+
+ public boolean hasPermission(@NonNull Player source, @NonNull String permissionNode) {
+ PermissionNode node = this.permissionNodes.get(permissionNode);
+ if (node == null) {
+ GeyserImpl.getInstance().getLogger().warning("Unable to find permission node " + permissionNode);
+ return false;
+ }
+
+ return PermissionAPI.getPermission((ServerPlayer) source, node);
+ }
+
+ public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel) {
+ if (!source.isPlayer()) {
+ return true;
+ }
+ assert source.getPlayer() != null;
+ boolean permission = this.hasPermission(source.getPlayer(), permissionNode);
+ if (!permission) {
+ return source.getPlayer().hasPermissions(permissionLevel);
+ }
+
+ return true;
+ }
+
+ private void registerNode(String node, PermissionGatherEvent.Nodes event) {
+ PermissionNode permissionNode = this.createNode(node);
+
+ // NeoForge likes to crash if you try and register a duplicate node
+ if (!event.getNodes().contains(permissionNode)) {
+ event.addNodes(permissionNode);
+ this.permissionNodes.put(node, permissionNode);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private PermissionNode createNode(String node) {
+ // The typical constructors in PermissionNode require a
+ // mod id, which means our permission nodes end up becoming
+ // geyser_neoforge. instead of just . We work around
+ // this by using reflection to access the constructor that
+ // doesn't require a mod id or ResourceLocation.
+ try {
+ return (PermissionNode) PERMISSION_NODE_CONSTRUCTOR.newInstance(
+ node,
+ PermissionTypes.BOOLEAN,
+ (PermissionNode.PermissionResolver) (player, playerUUID, context) -> false,
+ new PermissionDynamicContextKey[0]
+ );
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to create permission node " + node, e);
+ }
+ }
+}
diff --git a/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePlatform.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePlatform.java
new file mode 100644
index 000000000..41562baf3
--- /dev/null
+++ b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/GeyserNeoForgePlatform.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.neoforge;
+
+import net.minecraft.server.MinecraftServer;
+import net.neoforged.fml.ModContainer;
+import net.neoforged.fml.ModList;
+import net.neoforged.fml.loading.FMLPaths;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.geysermc.geyser.api.util.PlatformType;
+import org.geysermc.geyser.dump.BootstrapDumpInfo;
+import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
+import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+public class GeyserNeoForgePlatform implements GeyserModPlatform {
+
+ private final ModContainer container;
+
+ public GeyserNeoForgePlatform(ModContainer container) {
+ this.container = container;
+ }
+
+ @Override
+ public @NonNull PlatformType platformType() {
+ return PlatformType.NEOFORGE;
+ }
+
+ @Override
+ public @NonNull String configPath() {
+ return "Geyser-NeoForge";
+ }
+
+ @Override
+ public @NonNull Path dataFolder(@NonNull String modId) {
+ return FMLPaths.CONFIGDIR.get().resolve(modId);
+ }
+
+ @Override
+ public @NonNull BootstrapDumpInfo dumpInfo(@NonNull MinecraftServer server) {
+ return new GeyserNeoForgeDumpInfo(server);
+ }
+
+ @Override
+ public boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap) {
+ if (ModList.get().isLoaded("floodgate")) {
+ Path floodgateDataFolder = FMLPaths.CONFIGDIR.get().resolve("floodgate");
+ bootstrap.getGeyserConfig().loadFloodgate(bootstrap, floodgateDataFolder);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public @Nullable InputStream resolveResource(@NonNull String resource) {
+ try {
+ Path path = container.getModInfo().getOwningFile().getFile().findResource(resource);
+ return Files.newInputStream(path);
+ } catch (IOException e) {
+ return null;
+ }
+ }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/item/type/FlowerItem.java b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/ModConstants.java
similarity index 82%
rename from core/src/main/java/org/geysermc/geyser/item/type/FlowerItem.java
rename to bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/ModConstants.java
index c65eec1d2..aa72bb2a0 100644
--- a/core/src/main/java/org/geysermc/geyser/item/type/FlowerItem.java
+++ b/bootstrap/mod/neoforge/src/main/java/org/geysermc/geyser/platform/neoforge/ModConstants.java
@@ -23,11 +23,8 @@
* @link https://github.com/GeyserMC/Geyser
*/
-package org.geysermc.geyser.item.type;
+package org.geysermc.geyser.platform.neoforge;
-// If blocks are implemented, then this class is not needed.
-public class FlowerItem extends BlockItem {
- public FlowerItem(String javaIdentifier, Builder builder) {
- super(javaIdentifier, builder);
- }
+public class ModConstants {
+ public static final String MOD_ID = "geyser_neoforge";
}
diff --git a/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml b/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml
new file mode 100644
index 000000000..fa01bb6ec
--- /dev/null
+++ b/bootstrap/mod/neoforge/src/main/resources/META-INF/neoforge.mods.toml
@@ -0,0 +1,25 @@
+modLoader="javafml"
+loaderVersion="[1,)"
+license="MIT"
+[[mods]]
+modId="geyser_neoforge"
+version="${version}"
+displayName="Geyser"
+displayURL="https://geysermc.org/"
+logoFile= "../assets/geyser/icon.png"
+authors="GeyserMC"
+description="${description}"
+[[mixins]]
+config = "geyser.mixins.json"
+[[dependencies.geyser_neoforge]]
+ modId="neoforge"
+ type="required"
+ versionRange="[21.0.0-beta,)"
+ ordering="NONE"
+ side="BOTH"
+[[dependencies.geyser_neoforge]]
+ modId="minecraft"
+ type="required"
+ versionRange="[1.21,)"
+ ordering="NONE"
+ side="BOTH"
\ No newline at end of file
diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserChannelGetter.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserChannelGetter.java
new file mode 100644
index 000000000..8dc0026bf
--- /dev/null
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserChannelGetter.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.mod;
+
+import io.netty.channel.ChannelFuture;
+
+import java.util.List;
+
+/**
+ * Represents a getter to the server channels in the connection listener class.
+ */
+public interface GeyserChannelGetter {
+
+ /**
+ * Returns the channels.
+ *
+ * @return The channels.
+ */
+ List geyser$getChannels();
+}
diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java
similarity index 69%
rename from bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java
rename to bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java
index 756063af7..d7373f0a9 100644
--- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricMod.java
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModBootstrap.java
@@ -23,22 +23,17 @@
* @link https://github.com/GeyserMC/Geyser
*/
-package org.geysermc.geyser.platform.fabric;
+package org.geysermc.geyser.platform.mod;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import lombok.Getter;
+import lombok.RequiredArgsConstructor;
import lombok.Setter;
-import net.fabricmc.api.EnvType;
-import net.fabricmc.api.ModInitializer;
-import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
-import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
-import net.fabricmc.loader.api.FabricLoader;
-import net.fabricmc.loader.api.ModContainer;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.server.MinecraftServer;
-import org.apache.logging.log4j.LogManager;
+import net.minecraft.world.entity.player.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.GeyserBootstrap;
@@ -46,7 +41,6 @@ import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.GeyserLogger;
import org.geysermc.geyser.api.command.Command;
import org.geysermc.geyser.api.extension.Extension;
-import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.command.GeyserCommand;
import org.geysermc.geyser.command.GeyserCommandManager;
import org.geysermc.geyser.configuration.GeyserConfiguration;
@@ -54,68 +48,58 @@ import org.geysermc.geyser.dump.BootstrapDumpInfo;
import org.geysermc.geyser.level.WorldManager;
import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
-import org.geysermc.geyser.platform.fabric.command.GeyserFabricCommandExecutor;
-import org.geysermc.geyser.platform.fabric.world.GeyserFabricWorldManager;
+import org.geysermc.geyser.platform.mod.command.GeyserModCommandExecutor;
+import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
+import org.geysermc.geyser.platform.mod.world.GeyserModWorldManager;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.util.FileUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.net.SocketAddress;
import java.nio.file.Path;
import java.util.Map;
-import java.util.Optional;
import java.util.UUID;
-public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
+@RequiredArgsConstructor
+public abstract class GeyserModBootstrap implements GeyserBootstrap {
@Getter
- private static GeyserFabricMod instance;
+ private static GeyserModBootstrap instance;
+
+ private final GeyserModPlatform platform;
+
private GeyserImpl geyser;
- private ModContainer mod;
private Path dataFolder;
@Setter
private MinecraftServer server;
private GeyserCommandManager geyserCommandManager;
- private GeyserFabricConfiguration geyserConfig;
- private GeyserFabricLogger geyserLogger;
+ private GeyserModConfiguration geyserConfig;
+ private GeyserModInjector geyserInjector;
+ private final GeyserModLogger geyserLogger = new GeyserModLogger();
private IGeyserPingPassthrough geyserPingPassthrough;
private WorldManager geyserWorldManager;
- @Override
- public void onInitialize() {
- instance = this;
- mod = FabricLoader.getInstance().getModContainer("geyser-fabric").orElseThrow();
- onGeyserInitialize();
- }
-
@Override
public void onGeyserInitialize() {
- if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) {
- // Set as an event, so we can get the proper IP and port if needed
- ServerLifecycleEvents.SERVER_STARTED.register((server) -> {
- this.server = server;
- onGeyserEnable();
- });
- }
-
- // These are only registered once
- ServerLifecycleEvents.SERVER_STOPPING.register((server) -> onGeyserShutdown());
- ServerPlayConnectionEvents.JOIN.register((handler, $, $$) -> GeyserFabricUpdateListener.onPlayReady(handler));
-
- dataFolder = FabricLoader.getInstance().getConfigDir().resolve("Geyser-Fabric");
+ instance = this;
+ dataFolder = this.platform.dataFolder(this.platform.configPath());
GeyserLocale.init(this);
if (!loadConfig()) {
return;
}
- this.geyserLogger = new GeyserFabricLogger(geyserConfig.isDebugMode());
+ this.geyserLogger.setDebug(geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
- this.geyser = GeyserImpl.load(PlatformType.FABRIC, this);
+ this.geyser = GeyserImpl.load(this.platform.platformType(), this);
+
+ // Create command manager here, since the permission handler on neo needs it
+ this.geyserCommandManager = new GeyserCommandManager(geyser);
+ this.geyserCommandManager.init();
}
- @Override
public void onGeyserEnable() {
if (GeyserImpl.getInstance().isReloading()) {
if (!loadConfig()) {
@@ -123,35 +107,39 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
}
this.geyserLogger.setDebug(geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
- } else {
- this.geyserCommandManager = new GeyserCommandManager(geyser);
- this.geyserCommandManager.init();
}
+ GeyserImpl.start();
+
if (geyserConfig.isLegacyPingPassthrough()) {
this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(geyser);
} else {
this.geyserPingPassthrough = new ModPingPassthrough(server, geyserLogger);
}
- GeyserImpl.start();
-
- // No need to re-register commands, or re-recreate the world manager when reloading
+ // No need to re-register commands, or try to re-inject
if (GeyserImpl.getInstance().isReloading()) {
return;
}
- this.geyserWorldManager = new GeyserFabricWorldManager(server);
+ this.geyserWorldManager = new GeyserModWorldManager(server);
+
+ // We want to do this late in the server startup process to allow other mods
+ // To do their job injecting, then connect into *that*
+ this.geyserInjector = new GeyserModInjector(server, this.platform);
+ if (isServer()) {
+ this.geyserInjector.initializeLocalChannel(this);
+ }
// Start command building
// Set just "geyser" as the help command
- GeyserFabricCommandExecutor helpExecutor = new GeyserFabricCommandExecutor(geyser,
+ GeyserModCommandExecutor helpExecutor = new GeyserModCommandExecutor(geyser,
(GeyserCommand) geyser.commandManager().getCommands().get("help"));
LiteralArgumentBuilder builder = Commands.literal("geyser").executes(helpExecutor);
// Register all subcommands as valid
for (Map.Entry command : geyser.commandManager().getCommands().entrySet()) {
- GeyserFabricCommandExecutor executor = new GeyserFabricCommandExecutor(geyser, (GeyserCommand) command.getValue());
+ GeyserModCommandExecutor executor = new GeyserModCommandExecutor(geyser, (GeyserCommand) command.getValue());
builder.then(Commands.literal(command.getKey())
.executes(executor)
// Could also test for Bedrock but depending on when this is called it may backfire
@@ -171,12 +159,12 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
}
// Register help command for just "/"
- GeyserFabricCommandExecutor extensionHelpExecutor = new GeyserFabricCommandExecutor(geyser,
+ GeyserModCommandExecutor extensionHelpExecutor = new GeyserModCommandExecutor(geyser,
(GeyserCommand) extensionCommands.get("help"));
LiteralArgumentBuilder extCmdBuilder = Commands.literal(extensionMapEntry.getKey().description().id()).executes(extensionHelpExecutor);
for (Map.Entry command : extensionCommands.entrySet()) {
- GeyserFabricCommandExecutor executor = new GeyserFabricCommandExecutor(geyser, (GeyserCommand) command.getValue());
+ GeyserModCommandExecutor executor = new GeyserModCommandExecutor(geyser, (GeyserCommand) command.getValue());
extCmdBuilder.then(Commands.literal(command.getKey())
.executes(executor)
.requires(executor::testPermission)
@@ -201,11 +189,14 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
geyser.shutdown();
geyser = null;
}
- this.server = null;
+ if (geyserInjector != null) {
+ geyserInjector.shutdown();
+ this.server = null;
+ }
}
@Override
- public GeyserConfiguration getGeyserConfig() {
+ public GeyserModConfiguration getGeyserConfig() {
return geyserConfig;
}
@@ -236,7 +227,7 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
@Override
public BootstrapDumpInfo getDumpInfo() {
- return new GeyserFabricDumpInfo(server);
+ return this.platform.dumpInfo(this.server);
}
@Override
@@ -252,38 +243,37 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
}
@Override
- public int getServerPort() {
- return ((GeyserServerPortGetter) server).geyser$getServerPort();
+ public SocketAddress getSocketAddress() {
+ return this.geyserInjector.getServerSocketAddress();
}
@Override
- public boolean testFloodgatePluginPresent() {
- Optional floodgate = FabricLoader.getInstance().getModContainer("floodgate");
- if (floodgate.isPresent()) {
- geyserConfig.loadFloodgate(this, floodgate.orElse(null));
- return true;
+ public int getServerPort() {
+ if (isServer()) {
+ return ((GeyserServerPortGetter) server).geyser$getServerPort();
+ } else {
+ // Set in the IntegratedServerMixin
+ return geyserConfig.getRemote().port();
}
- return false;
+ }
+
+ public abstract boolean isServer();
+
+ @Override
+ public boolean testFloodgatePluginPresent() {
+ return this.platform.testFloodgatePluginPresent(this);
}
@Nullable
@Override
public InputStream getResourceOrNull(String resource) {
- // We need to handle this differently, because Fabric shares the classloader across multiple mods
- Path path = this.mod.findPath(resource).orElse(null);
- if (path == null) {
- return null;
- }
-
- try {
- return path.getFileSystem()
- .provider()
- .newInputStream(path);
- } catch (IOException e) {
- return null;
- }
+ return this.platform.resolveResource(resource);
}
+ public abstract boolean hasPermission(@NonNull Player source, @NonNull String permissionNode);
+
+ public abstract boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode, int permissionLevel);
+
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean loadConfig() {
try {
@@ -294,10 +284,10 @@ public class GeyserFabricMod implements ModInitializer, GeyserBootstrap {
File configFile = FileUtils.fileOrCopiedFromResource(dataFolder.resolve("config.yml").toFile(), "config.yml",
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
- this.geyserConfig = FileUtils.loadConfig(configFile, GeyserFabricConfiguration.class);
+ this.geyserConfig = FileUtils.loadConfig(configFile, GeyserModConfiguration.class);
return true;
} catch (IOException ex) {
- LogManager.getLogger("geyser-fabric").error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
+ geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
ex.printStackTrace();
return false;
}
diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModCompressionDisabler.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModCompressionDisabler.java
new file mode 100644
index 000000000..631a21510
--- /dev/null
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModCompressionDisabler.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.mod;
+
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelOutboundHandlerAdapter;
+import io.netty.channel.ChannelPromise;
+import net.minecraft.network.protocol.login.ClientboundGameProfilePacket;
+import net.minecraft.network.protocol.login.ClientboundLoginCompressionPacket;
+
+/**
+ * Disables the compression packet (and the compression handlers from being added to the pipeline) for Geyser clients
+ * that won't be receiving the data over the network.
+ *
+ * As of 1.8 - 1.17.1, compression is enabled in the Netty pipeline by adding a listener after a packet is written.
+ * If we simply "cancel" or don't forward the packet, then the listener is never called.
+ */
+public class GeyserModCompressionDisabler extends ChannelOutboundHandlerAdapter {
+
+ @Override
+ public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
+ Class> msgClass = msg.getClass();
+ // Don't let any compression packet get through
+ if (!ClientboundLoginCompressionPacket.class.isAssignableFrom(msgClass)) {
+ if (ClientboundGameProfilePacket.class.isAssignableFrom(msgClass)) {
+
+ // We're past the point that a compression packet can be sent, so we can safely yeet ourselves away
+ ctx.channel().pipeline().remove(this);
+ }
+ super.write(ctx, msg, promise);
+ }
+ }
+}
diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricConfiguration.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModConfiguration.java
similarity index 80%
rename from bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricConfiguration.java
rename to bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModConfiguration.java
index f557d16c0..a24380bd6 100644
--- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricConfiguration.java
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModConfiguration.java
@@ -23,23 +23,20 @@
* @link https://github.com/GeyserMC/Geyser
*/
-package org.geysermc.geyser.platform.fabric;
+package org.geysermc.geyser.platform.mod;
import com.fasterxml.jackson.annotation.JsonIgnore;
-import net.fabricmc.loader.api.FabricLoader;
-import net.fabricmc.loader.api.ModContainer;
import org.geysermc.geyser.FloodgateKeyLoader;
import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
import java.nio.file.Path;
-public class GeyserFabricConfiguration extends GeyserJacksonConfiguration {
+public class GeyserModConfiguration extends GeyserJacksonConfiguration {
@JsonIgnore
private Path floodgateKeyPath;
- public void loadFloodgate(GeyserFabricMod geyser, ModContainer floodgate) {
+ public void loadFloodgate(GeyserModBootstrap geyser, Path floodgateDataFolder) {
Path geyserDataFolder = geyser.getConfigFolder();
- Path floodgateDataFolder = floodgate != null ? FabricLoader.getInstance().getConfigDir().resolve("floodgate") : null;
floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgateDataFolder, geyserDataFolder, geyser.getGeyserLogger());
}
diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModInjector.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModInjector.java
new file mode 100644
index 000000000..624eccb3f
--- /dev/null
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModInjector.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.mod;
+
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.DefaultEventLoopGroup;
+import io.netty.channel.local.LocalAddress;
+import io.netty.util.concurrent.DefaultThreadFactory;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.network.ServerConnectionListener;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.geysermc.geyser.GeyserBootstrap;
+import org.geysermc.geyser.GeyserImpl;
+import org.geysermc.geyser.network.netty.GeyserInjector;
+import org.geysermc.geyser.network.netty.LocalServerChannelWrapper;
+import org.geysermc.geyser.platform.mod.platform.GeyserModPlatform;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+
+public class GeyserModInjector extends GeyserInjector {
+
+ private final MinecraftServer server;
+ private final GeyserModPlatform platform;
+ private DefaultEventLoopGroup eventLoopGroup;
+
+ /**
+ * Used to uninject ourselves on shutdown.
+ */
+ private List allServerChannels;
+
+ public GeyserModInjector(MinecraftServer server, GeyserModPlatform platform) {
+ this.server = server;
+ this.platform = platform;
+ }
+
+ @Override
+ protected void initializeLocalChannel0(GeyserBootstrap bootstrap) throws Exception {
+ ServerConnectionListener connection = this.server.getConnection();
+
+ // Find the channel that Minecraft uses to listen to connections
+ ChannelFuture listeningChannel = null;
+ this.allServerChannels = ((GeyserChannelGetter) connection).geyser$getChannels();
+ for (ChannelFuture o : allServerChannels) {
+ listeningChannel = o;
+ break;
+ }
+
+ if (listeningChannel == null) {
+ throw new RuntimeException("Unable to find listening channel!");
+ }
+
+ // Making this a function prevents childHandler from being treated as a non-final variable
+ ChannelInitializer childHandler = getChildHandler(bootstrap, listeningChannel);
+ // This method is what initializes the connection in Java Edition, after Netty is all set.
+ Method initChannel = childHandler.getClass().getDeclaredMethod("initChannel", Channel.class);
+ initChannel.setAccessible(true);
+
+ // Separate variable so we can shut it down later
+ eventLoopGroup = new DefaultEventLoopGroup(0, new DefaultThreadFactory("Geyser " + this.platform.platformType().platformName() + " connection thread", Thread.MAX_PRIORITY));
+ ChannelFuture channelFuture = (new ServerBootstrap()
+ .channel(LocalServerChannelWrapper.class)
+ .childHandler(new ChannelInitializer<>() {
+ @Override
+ protected void initChannel(@NonNull Channel ch) throws Exception {
+ initChannel.invoke(childHandler, ch);
+
+ int index = ch.pipeline().names().indexOf("encoder");
+ String baseName = index != -1 ? "encoder" : "outbound_config";
+
+ if (bootstrap.getGeyserConfig().isDisableCompression()) {
+ ch.pipeline().addAfter(baseName, "geyser-compression-disabler", new GeyserModCompressionDisabler());
+ }
+ }
+ })
+ // Set to MAX_PRIORITY as MultithreadEventLoopGroup#newDefaultThreadFactory which DefaultEventLoopGroup implements does by default
+ .group(eventLoopGroup)
+ .localAddress(LocalAddress.ANY))
+ .bind()
+ .syncUninterruptibly();
+ // We don't need to add to the list, but plugins like ProtocolSupport and ProtocolLib that add to the main pipeline
+ // will work when we add to the list.
+ allServerChannels.add(channelFuture);
+ this.localChannel = channelFuture;
+ this.serverSocketAddress = channelFuture.channel().localAddress();
+ }
+
+ @SuppressWarnings("unchecked")
+ private ChannelInitializer getChildHandler(GeyserBootstrap bootstrap, ChannelFuture listeningChannel) {
+ List names = listeningChannel.channel().pipeline().names();
+ ChannelInitializer childHandler = null;
+ for (String name : names) {
+ ChannelHandler handler = listeningChannel.channel().pipeline().get(name);
+ try {
+ Field childHandlerField = handler.getClass().getDeclaredField("childHandler");
+ childHandlerField.setAccessible(true);
+ childHandler = (ChannelInitializer) childHandlerField.get(handler);
+ break;
+ } catch (Exception e) {
+ if (bootstrap.getGeyserConfig().isDebugMode()) {
+ bootstrap.getGeyserLogger().debug("The handler " + name + " isn't a ChannelInitializer. THIS ERROR IS SAFE TO IGNORE!");
+ e.printStackTrace();
+ }
+ }
+ }
+ if (childHandler == null) {
+ throw new RuntimeException();
+ }
+ return childHandler;
+ }
+
+ @Override
+ public void shutdown() {
+ if (this.allServerChannels != null) {
+ this.allServerChannels.remove(this.localChannel);
+ this.allServerChannels = null;
+ }
+
+ if (eventLoopGroup != null) {
+ try {
+ eventLoopGroup.shutdownGracefully().sync();
+ eventLoopGroup = null;
+ } catch (Exception e) {
+ GeyserImpl.getInstance().getLogger().error("Unable to shut down injector! " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ super.shutdown();
+ }
+}
diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricLogger.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModLogger.java
similarity index 89%
rename from bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricLogger.java
rename to bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModLogger.java
index 180197f2d..9260288d7 100644
--- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricLogger.java
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModLogger.java
@@ -23,7 +23,7 @@
* @link https://github.com/GeyserMC/Geyser
*/
-package org.geysermc.geyser.platform.fabric;
+package org.geysermc.geyser.platform.mod;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
@@ -32,15 +32,11 @@ import org.apache.logging.log4j.Logger;
import org.geysermc.geyser.GeyserLogger;
import org.geysermc.geyser.text.ChatColor;
-public class GeyserFabricLogger implements GeyserLogger {
- private final Logger logger = LogManager.getLogger("geyser-fabric");
+public class GeyserModLogger implements GeyserLogger {
+ private final Logger logger = LogManager.getLogger("geyser");
private boolean debug;
- public GeyserFabricLogger(boolean isDebug) {
- debug = isDebug;
- }
-
@Override
public void severe(String message) {
logger.fatal(message);
@@ -73,7 +69,7 @@ public class GeyserFabricLogger implements GeyserLogger {
@Override
public void sendMessage(Component message) {
- // As of Java Edition 1.19.2, Fabric's console doesn't natively support legacy format
+ // As of Java Edition 1.19.2, Minecraft's console doesn't natively support legacy format
String flattened = LegacyComponentSerializer.legacySection().serialize(message);
// Add the reset at the end, or else format will persist... forever.
// https://cdn.discordapp.com/attachments/573909525132738590/1033904509170225242/unknown.png
diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricUpdateListener.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModUpdateListener.java
similarity index 68%
rename from bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricUpdateListener.java
rename to bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModUpdateListener.java
index 1ea69cbe2..11ca0bc4f 100644
--- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserFabricUpdateListener.java
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserModUpdateListener.java
@@ -23,21 +23,22 @@
* @link https://github.com/GeyserMC/Geyser
*/
-package org.geysermc.geyser.platform.fabric;
+package org.geysermc.geyser.platform.mod;
-import me.lucko.fabric.api.permissions.v0.Permissions;
-import net.minecraft.server.network.ServerGamePacketListenerImpl;
+import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.world.entity.player.Player;
import org.geysermc.geyser.Constants;
-import org.geysermc.geyser.platform.fabric.command.FabricCommandSender;
+import org.geysermc.geyser.platform.mod.command.ModCommandSender;
import org.geysermc.geyser.util.VersionCheckUtils;
-public final class GeyserFabricUpdateListener {
- public static void onPlayReady(ServerGamePacketListenerImpl handler) {
- if (Permissions.check(handler.player, Constants.UPDATE_PERMISSION, 2)) {
- VersionCheckUtils.checkForGeyserUpdate(() -> new FabricCommandSender(handler.player.createCommandSourceStack()));
+public final class GeyserModUpdateListener {
+ public static void onPlayReady(Player player) {
+ CommandSourceStack stack = player.createCommandSourceStack();
+ if (GeyserModBootstrap.getInstance().hasPermission(stack, Constants.UPDATE_PERMISSION, 2)) {
+ VersionCheckUtils.checkForGeyserUpdate(() -> new ModCommandSender(stack));
}
}
- private GeyserFabricUpdateListener() {
+ private GeyserModUpdateListener() {
}
}
diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserServerPortGetter.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserServerPortGetter.java
similarity index 97%
rename from bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserServerPortGetter.java
rename to bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserServerPortGetter.java
index 4f1c8b638..fad0d1678 100644
--- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/GeyserServerPortGetter.java
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/GeyserServerPortGetter.java
@@ -23,7 +23,7 @@
* @link https://github.com/GeyserMC/Geyser
*/
-package org.geysermc.geyser.platform.fabric;
+package org.geysermc.geyser.platform.mod;
import net.minecraft.server.MinecraftServer;
diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/ModPingPassthrough.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/ModPingPassthrough.java
similarity index 90%
rename from bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/ModPingPassthrough.java
rename to bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/ModPingPassthrough.java
index e74be7fb7..a2bbfa379 100644
--- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/ModPingPassthrough.java
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/ModPingPassthrough.java
@@ -23,12 +23,13 @@
* @link https://github.com/GeyserMC/Geyser
*/
-package org.geysermc.geyser.platform.fabric;
+package org.geysermc.geyser.platform.mod;
import lombok.AllArgsConstructor;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
+import net.minecraft.core.RegistryAccess;
import net.minecraft.network.Connection;
import net.minecraft.network.PacketSendListener;
import net.minecraft.network.protocol.Packet;
@@ -39,10 +40,11 @@ import net.minecraft.network.protocol.status.ServerStatusPacketListener;
import net.minecraft.network.protocol.status.ServerboundStatusRequestPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.network.ServerStatusPacketListenerImpl;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.GeyserLogger;
import org.geysermc.geyser.ping.GeyserPingInfo;
import org.geysermc.geyser.ping.IGeyserPingPassthrough;
-import org.jetbrains.annotations.Nullable;
import java.net.InetSocketAddress;
import java.util.Objects;
@@ -68,7 +70,7 @@ public class ModPingPassthrough implements IGeyserPingPassthrough {
StatusInterceptor connection = new StatusInterceptor();
ServerStatusPacketListener statusPacketListener = new ServerStatusPacketListenerImpl(status, connection);
- statusPacketListener.handleStatusRequest(new ServerboundStatusRequestPacket());
+ statusPacketListener.handleStatusRequest(ServerboundStatusRequestPacket.INSTANCE);
// mods like MiniMOTD (that inject into the above method) have now processed the response
status = Objects.requireNonNull(connection.status, "status response");
} catch (Exception e) {
@@ -78,7 +80,7 @@ public class ModPingPassthrough implements IGeyserPingPassthrough {
}
}
- String jsonDescription = net.minecraft.network.chat.Component.Serializer.toJson(status.description());
+ String jsonDescription = net.minecraft.network.chat.Component.Serializer.toJson(status.description(), RegistryAccess.EMPTY);
String legacyDescription = LEGACY_SERIALIZER.serialize(GSON_SERIALIZER.deserializeOr(jsonDescription, Component.empty()));
return new GeyserPingInfo(
@@ -100,7 +102,7 @@ public class ModPingPassthrough implements IGeyserPingPassthrough {
}
@Override
- public void send(Packet> packet, @Nullable PacketSendListener packetSendListener, boolean bl) {
+ public void send(@NonNull Packet> packet, @Nullable PacketSendListener packetSendListener, boolean bl) {
if (packet instanceof ClientboundStatusResponsePacket statusResponse) {
status = statusResponse.status();
}
diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandExecutor.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/GeyserModCommandExecutor.java
similarity index 82%
rename from bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandExecutor.java
rename to bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/GeyserModCommandExecutor.java
index 86b50d431..694dc732e 100644
--- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/GeyserFabricCommandExecutor.java
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/GeyserModCommandExecutor.java
@@ -23,31 +23,31 @@
* @link https://github.com/GeyserMC/Geyser
*/
-package org.geysermc.geyser.platform.fabric.command;
+package org.geysermc.geyser.platform.mod.command;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.context.CommandContext;
-import me.lucko.fabric.api.permissions.v0.Permissions;
import net.minecraft.commands.CommandSourceStack;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.command.GeyserCommand;
import org.geysermc.geyser.command.GeyserCommandExecutor;
+import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.text.GeyserLocale;
import java.util.Collections;
-public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implements Command {
+public class GeyserModCommandExecutor extends GeyserCommandExecutor implements Command {
private final GeyserCommand command;
- public GeyserFabricCommandExecutor(GeyserImpl connector, GeyserCommand command) {
- super(connector, Collections.singletonMap(command.name(), command));
+ public GeyserModCommandExecutor(GeyserImpl geyser, GeyserCommand command) {
+ super(geyser, Collections.singletonMap(command.name(), command));
this.command = command;
}
public boolean testPermission(CommandSourceStack source) {
- return Permissions.check(source, command.permission(), command.isSuggestedOpOnly() ? 2 : 0);
+ return GeyserModBootstrap.getInstance().hasPermission(source, command.permission(), command.isSuggestedOpOnly() ? 2 : 0);
}
@Override
@@ -57,7 +57,7 @@ public class GeyserFabricCommandExecutor extends GeyserCommandExecutor implement
public int runWithArgs(CommandContext context, String args) {
CommandSourceStack source = context.getSource();
- FabricCommandSender sender = new FabricCommandSender(source);
+ ModCommandSender sender = new ModCommandSender(source);
GeyserSession session = getGeyserSession(sender);
if (!testPermission(source)) {
sender.sendMessage(ChatColor.RED + GeyserLocale.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.locale()));
diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/FabricCommandSender.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSender.java
similarity index 85%
rename from bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/FabricCommandSender.java
rename to bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSender.java
index 28875ec6e..5bebfae93 100644
--- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/command/FabricCommandSender.java
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/command/ModCommandSender.java
@@ -23,25 +23,26 @@
* @link https://github.com/GeyserMC/Geyser
*/
-package org.geysermc.geyser.platform.fabric.command;
+package org.geysermc.geyser.platform.mod.command;
-import me.lucko.fabric.api.permissions.v0.Permissions;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.minecraft.commands.CommandSourceStack;
+import net.minecraft.core.RegistryAccess;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.command.GeyserCommandSource;
+import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
import org.geysermc.geyser.text.ChatColor;
import java.util.Objects;
-public class FabricCommandSender implements GeyserCommandSource {
+public class ModCommandSender implements GeyserCommandSource {
private final CommandSourceStack source;
- public FabricCommandSender(CommandSourceStack source) {
+ public ModCommandSender(CommandSourceStack source) {
this.source = source;
}
@@ -63,7 +64,7 @@ public class FabricCommandSender implements GeyserCommandSource {
public void sendMessage(net.kyori.adventure.text.Component message) {
if (source.getEntity() instanceof ServerPlayer player) {
String decoded = GsonComponentSerializer.gson().serialize(message);
- player.displayClientMessage(Objects.requireNonNull(Component.Serializer.fromJson(decoded)), false);
+ player.displayClientMessage(Objects.requireNonNull(Component.Serializer.fromJson(decoded, RegistryAccess.EMPTY)), false);
return;
}
GeyserCommandSource.super.sendMessage(message);
@@ -76,6 +77,6 @@ public class FabricCommandSender implements GeyserCommandSource {
@Override
public boolean hasPermission(String permission) {
- return Permissions.check(source, permission, source.getServer().getOperatorUserPermissionLevel());
+ return GeyserModBootstrap.getInstance().hasPermission(source, permission, source.getServer().getOperatorUserPermissionLevel());
}
}
diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/client/IntegratedServerMixin.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/client/IntegratedServerMixin.java
similarity index 85%
rename from bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/client/IntegratedServerMixin.java
rename to bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/client/IntegratedServerMixin.java
index 999a077bb..ece2f730a 100644
--- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/client/IntegratedServerMixin.java
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/client/IntegratedServerMixin.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,18 +23,16 @@
* @link https://github.com/GeyserMC/Geyser
*/
-package org.geysermc.geyser.platform.fabric.mixin.client;
+package org.geysermc.geyser.platform.mod.mixin.client;
-import net.fabricmc.api.EnvType;
-import net.fabricmc.api.Environment;
import net.minecraft.client.Minecraft;
import net.minecraft.client.server.IntegratedServer;
import net.minecraft.network.chat.Component;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.GameType;
import org.geysermc.geyser.GeyserImpl;
-import org.geysermc.geyser.platform.fabric.GeyserFabricMod;
-import org.geysermc.geyser.platform.fabric.GeyserServerPortGetter;
+import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
+import org.geysermc.geyser.platform.mod.GeyserServerPortGetter;
import org.geysermc.geyser.text.GeyserLocale;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
@@ -45,7 +43,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.Objects;
-@Environment(EnvType.CLIENT)
@Mixin(IntegratedServer.class)
public class IntegratedServerMixin implements GeyserServerPortGetter {
@Shadow
@@ -57,8 +54,10 @@ public class IntegratedServerMixin implements GeyserServerPortGetter {
private void onOpenToLan(GameType gameType, boolean cheatsAllowed, int port, CallbackInfoReturnable cir) {
if (cir.getReturnValueZ()) {
// If the LAN is opened, starts Geyser.
- GeyserFabricMod.getInstance().setServer((MinecraftServer) (Object) this);
- GeyserFabricMod.getInstance().onGeyserEnable();
+ GeyserModBootstrap instance = GeyserModBootstrap.getInstance();
+ instance.setServer((MinecraftServer) (Object) this);
+ instance.getGeyserConfig().getRemote().setPort(port);
+ instance.onGeyserEnable();
// Ensure player locale has been loaded, in case it's different from Java system language
GeyserLocale.loadGeyserLocale(this.minecraft.options.languageCode);
// Give indication that Geyser is loaded
diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/DedicatedServerMixin.java
similarity index 76%
rename from bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java
rename to bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/DedicatedServerMixin.java
index 23e148775..3b809d321 100644
--- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/mixin/server/MinecraftDedicatedServerMixin.java
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/DedicatedServerMixin.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
* @link https://github.com/GeyserMC/Geyser
*/
-package org.geysermc.geyser.platform.fabric.mixin.server;
+package org.geysermc.geyser.platform.mod.mixin.server;
import com.mojang.datafixers.DataFixer;
import net.minecraft.server.MinecraftServer;
@@ -33,14 +33,14 @@ import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.world.level.storage.LevelStorageSource;
-import org.geysermc.geyser.platform.fabric.GeyserServerPortGetter;
+import org.geysermc.geyser.platform.mod.GeyserServerPortGetter;
import org.spongepowered.asm.mixin.Mixin;
import java.net.Proxy;
@Mixin(DedicatedServer.class)
-public abstract class MinecraftDedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter {
- public MinecraftDedicatedServerMixin(Thread thread, LevelStorageSource.LevelStorageAccess levelStorageAccess, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer dataFixer, Services services, ChunkProgressListenerFactory chunkProgressListenerFactory) {
+public abstract class DedicatedServerMixin extends MinecraftServer implements GeyserServerPortGetter {
+ public DedicatedServerMixin(Thread thread, LevelStorageSource.LevelStorageAccess levelStorageAccess, PackRepository packRepository, WorldStem worldStem, Proxy proxy, DataFixer dataFixer, Services services, ChunkProgressListenerFactory chunkProgressListenerFactory) {
super(thread, levelStorageAccess, packRepository, worldStem, proxy, dataFixer, services, chunkProgressListenerFactory);
}
diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/ServerConnectionListenerMixin.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/ServerConnectionListenerMixin.java
new file mode 100644
index 000000000..52941d631
--- /dev/null
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/mixin/server/ServerConnectionListenerMixin.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.mod.mixin.server;
+
+import io.netty.channel.ChannelFuture;
+import net.minecraft.server.network.ServerConnectionListener;
+import org.geysermc.geyser.platform.mod.GeyserChannelGetter;
+import org.spongepowered.asm.mixin.Final;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.Shadow;
+
+import java.util.List;
+
+@Mixin(ServerConnectionListener.class)
+public abstract class ServerConnectionListenerMixin implements GeyserChannelGetter {
+
+ @Shadow @Final private List channels;
+
+ @Override
+ public List geyser$getChannels() {
+ return this.channels;
+ }
+}
diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/platform/GeyserModPlatform.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/platform/GeyserModPlatform.java
new file mode 100644
index 000000000..2f615591b
--- /dev/null
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/platform/GeyserModPlatform.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.mod.platform;
+
+import net.minecraft.server.MinecraftServer;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.geysermc.geyser.api.util.PlatformType;
+import org.geysermc.geyser.dump.BootstrapDumpInfo;
+import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
+
+import java.io.InputStream;
+import java.nio.file.Path;
+
+/**
+ * An interface which holds common methods that have different
+ * APIs on their respective mod platforms.
+ */
+public interface GeyserModPlatform {
+
+ /**
+ * Gets the {@link PlatformType} of the mod platform.
+ *
+ * @return the platform type of the mod platform
+ */
+ @NonNull
+ PlatformType platformType();
+
+ /**
+ * Gets the config path of the mod platform.
+ *
+ * @return the config path of the mod platform
+ */
+ @NonNull
+ String configPath();
+
+ /**
+ * Gets the data folder of the mod platform.
+ *
+ * @return the data folder of the mod platform
+ */
+ @NonNull
+ Path dataFolder(@NonNull String modId);
+
+ /**
+ * Gets the dump info of the mod platform.
+ *
+ * @param server the server to get the dump info from
+ * @return the dump info of the mod platform
+ */
+ @NonNull
+ BootstrapDumpInfo dumpInfo(@NonNull MinecraftServer server);
+
+ /**
+ * Tests if the Floodgate plugin is present on the mod platform.
+ *
+ * @return {@code true} if the Floodgate plugin is present on the mod platform, {@code false} otherwise
+ */
+ boolean testFloodgatePluginPresent(@NonNull GeyserModBootstrap bootstrap);
+
+ /**
+ * Resolves a resource from the mod jar.
+ *
+ * @param resource the name of the resource
+ * @return the input stream of the resource
+ */
+ @Nullable
+ InputStream resolveResource(@NonNull String resource);
+}
diff --git a/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java
new file mode 100644
index 000000000..ef8c3ec0a
--- /dev/null
+++ b/bootstrap/mod/src/main/java/org/geysermc/geyser/platform/mod/world/GeyserModWorldManager.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.mod.world;
+
+import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
+import net.minecraft.SharedConstants;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.RegistryAccess;
+import net.minecraft.core.component.DataComponents;
+import net.minecraft.network.chat.Component;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.entity.BannerBlockEntity;
+import net.minecraft.world.level.block.entity.BannerPatternLayers;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.chunk.ChunkAccess;
+import net.minecraft.world.level.chunk.LevelChunkSection;
+import net.minecraft.world.level.chunk.status.ChunkStatus;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.geysermc.geyser.level.GeyserWorldManager;
+import org.geysermc.geyser.network.GameProtocol;
+import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.util.MinecraftKey;
+import org.geysermc.mcprotocollib.protocol.data.game.Holder;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+public class GeyserModWorldManager extends GeyserWorldManager {
+
+ private static final GsonComponentSerializer GSON_SERIALIZER = GsonComponentSerializer.gson();
+ private final MinecraftServer server;
+
+ public GeyserModWorldManager(MinecraftServer server) {
+ this.server = server;
+ }
+
+ @Override
+ public int getBlockAt(GeyserSession session, int x, int y, int z) {
+ // If the protocol version of Geyser and the server are not the
+ // same, fallback to the chunk cache. May be able to update this
+ // in the future to use ViaVersion however, like Spigot does.
+ if (SharedConstants.getCurrentVersion().getProtocolVersion() != GameProtocol.getJavaProtocolVersion()) {
+ return super.getBlockAt(session, x, y, z);
+ }
+
+ ServerPlayer player = this.getPlayer(session);
+ if (player == null) {
+ return 0;
+ }
+
+ Level level = player.level();
+ if (y < level.getMinBuildHeight()) {
+ return 0;
+ }
+
+ ChunkAccess chunk = level.getChunkSource().getChunk(x >> 4, z >> 4, ChunkStatus.FULL, false);
+ if (chunk == null) {
+ return 0;
+ }
+
+ int worldOffset = level.getMinBuildHeight() >> 4;
+ int chunkOffset = (y >> 4) - worldOffset;
+ if (chunkOffset < chunk.getSections().length) {
+ LevelChunkSection section = chunk.getSections()[chunkOffset];
+ if (section != null && !section.hasOnlyAir()) {
+ return Block.getId(section.getBlockState(x & 15, y & 15, z & 15));
+ }
+ }
+
+ return 0;
+ }
+
+ @Override
+ public boolean hasOwnChunkCache() {
+ return SharedConstants.getCurrentVersion().getProtocolVersion() == GameProtocol.getJavaProtocolVersion();
+ }
+
+ @Override
+ public boolean hasPermission(GeyserSession session, String permission) {
+ ServerPlayer player = getPlayer(session);
+ return GeyserModBootstrap.getInstance().hasPermission(player, permission);
+ }
+
+ @Override
+ public GameMode getDefaultGameMode(GeyserSession session) {
+ return GameMode.byId(server.getDefaultGameType().getId());
+ }
+
+ @NonNull
+ @Override
+ public CompletableFuture getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) {
+ CompletableFuture future = new CompletableFuture<>();
+ server.execute(() -> {
+ ServerPlayer player = getPlayer(session);
+ if (player == null) {
+ future.complete(null);
+ return;
+ }
+
+ BlockPos pos = new BlockPos(x, y, z);
+ // Don't create a new block entity if invalid
+ //noinspection resource - level() is just a getter
+ BlockEntity blockEntity = player.level().getChunkAt(pos).getBlockEntity(pos);
+ if (blockEntity instanceof BannerBlockEntity banner) {
+ // Potentially exposes other NBT data? But we need to get the NBT data for the banner patterns *and*
+ // the banner might have a custom name, both of which a Java client knows and caches
+ ItemStack itemStack = banner.getItem();
+
+ org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents components =
+ new org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents(new HashMap<>());
+
+ components.put(DataComponentType.DAMAGE, itemStack.getDamageValue());
+
+ Component customName = itemStack.getComponents().get(DataComponents.CUSTOM_NAME);
+ if (customName != null) {
+ components.put(DataComponentType.CUSTOM_NAME, toKyoriComponent(customName));
+ }
+
+ BannerPatternLayers pattern = itemStack.get(DataComponents.BANNER_PATTERNS);
+ if (pattern != null) {
+ components.put(DataComponentType.BANNER_PATTERNS, toPatternList(pattern));
+ }
+
+ future.complete(components);
+ return;
+ }
+ future.complete(null);
+ });
+ return future;
+ }
+
+ private ServerPlayer getPlayer(GeyserSession session) {
+ return server.getPlayerList().getPlayer(session.getPlayerEntity().getUuid());
+ }
+
+ private static net.kyori.adventure.text.Component toKyoriComponent(Component component) {
+ String json = Component.Serializer.toJson(component, RegistryAccess.EMPTY);
+ return GSON_SERIALIZER.deserializeOr(json, net.kyori.adventure.text.Component.empty());
+ }
+
+ private static List toPatternList(BannerPatternLayers patternLayers) {
+ return patternLayers.layers().stream()
+ .map(layer -> {
+ BannerPatternLayer.BannerPattern pattern = new BannerPatternLayer.BannerPattern(
+ MinecraftKey.key(layer.pattern().value().assetId().toString()), layer.pattern().value().translationKey()
+ );
+ return new BannerPatternLayer(Holder.ofCustom(pattern), layer.color().getId());
+ })
+ .toList();
+ }
+}
diff --git a/bootstrap/mod/src/main/resources/geyser.mixins.json b/bootstrap/mod/src/main/resources/geyser.mixins.json
new file mode 100644
index 000000000..47b2f60f3
--- /dev/null
+++ b/bootstrap/mod/src/main/resources/geyser.mixins.json
@@ -0,0 +1,18 @@
+{
+ "required": true,
+ "minVersion": "0.8",
+ "package": "org.geysermc.geyser.platform.mod.mixin",
+ "compatibilityLevel": "JAVA_17",
+ "mixins": [
+ "server.ServerConnectionListenerMixin"
+ ],
+ "server": [
+ "server.DedicatedServerMixin"
+ ],
+ "client": [
+ "client.IntegratedServerMixin"
+ ],
+ "injectors": {
+ "defaultRequire": 1
+ }
+}
diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts
index 129064cd4..fcb85f100 100644
--- a/bootstrap/spigot/build.gradle.kts
+++ b/bootstrap/spigot/build.gradle.kts
@@ -4,25 +4,27 @@ dependencies {
isTransitive = false
}
+ implementation(libs.erosion.bukkit.nms) {
+ attributes {
+ attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 21)
+ }
+ }
+
implementation(variantOf(libs.adapters.spigot) {
classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations
})
+ implementation(variantOf(libs.adapters.paper) {
+ classifier("all") // otherwise the unshaded jar is used without the shaded NMS implementations
+ })
implementation(libs.commodore)
implementation(libs.adventure.text.serializer.bungeecord)
-
- // Both folia-api and paper-mojangapi only provide Java 17 versions for 1.19
- compileOnly(libs.folia.api) {
- attributes {
- attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
- }
- }
- compileOnly(libs.paper.mojangapi) {
- attributes {
- attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17)
- }
- }
+
+ compileOnly(libs.folia.api)
+ compileOnly(libs.paper.mojangapi)
+
+ compileOnlyApi(libs.viaversion)
}
platformRelocate("it.unimi.dsi.fastutil")
@@ -41,6 +43,12 @@ application {
}
tasks.withType {
+
+ // Prevents Paper 1.20.5+ from remapping Geyser
+ manifest {
+ attributes["paperweight-mappings-namespace"] = "mojang"
+ }
+
archiveBaseName.set("Geyser-Spigot")
dependencies {
@@ -48,6 +56,7 @@ tasks.withType {
// We cannot shade Netty, or else native libraries will not load
// Needed because older Spigot builds do not provide the haproxy module
+ exclude(dependency("io.netty.incubator:.*"))
exclude(dependency("io.netty:netty-transport-classes-epoll:.*"))
exclude(dependency("io.netty:netty-transport-native-epoll:.*"))
exclude(dependency("io.netty:netty-transport-native-unix-common:.*"))
@@ -67,3 +76,8 @@ tasks.withType {
exclude(dependency("com.mojang:.*"))
}
}
+
+modrinth {
+ uploadFile.set(tasks.getByPath("shadowJar"))
+ loaders.addAll("spigot", "paper")
+}
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperLogger.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperLogger.java
index 930f84cec..9ebd6519a 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperLogger.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperLogger.java
@@ -34,8 +34,8 @@ import java.util.logging.Logger;
public final class GeyserPaperLogger extends GeyserSpigotLogger {
private final ComponentLogger componentLogger;
- public GeyserPaperLogger(Plugin plugin, Logger logger, boolean debug) {
- super(logger, debug);
+ public GeyserPaperLogger(Plugin plugin, Logger logger) {
+ super(logger);
componentLogger = plugin.getComponentLogger();
}
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java
index ad31131bd..5dcfbd0f8 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java
@@ -25,7 +25,7 @@
package org.geysermc.geyser.platform.spigot;
-import com.github.steveice10.mc.protocol.MinecraftProtocol;
+import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
import com.viaversion.viaversion.bukkit.handlers.BukkitChannelInitializer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
@@ -119,8 +119,11 @@ public class GeyserSpigotInjector extends GeyserInjector {
protected void initChannel(@NonNull Channel ch) throws Exception {
initChannel.invoke(childHandler, ch);
+ int index = ch.pipeline().names().indexOf("encoder");
+ String baseName = index != -1 ? "encoder" : "outbound_config";
+
if (bootstrap.getGeyserConfig().isDisableCompression() && GeyserSpigotCompressionDisabler.ENABLED) {
- ch.pipeline().addAfter("encoder", "geyser-compression-disabler", new GeyserSpigotCompressionDisabler());
+ ch.pipeline().addAfter(baseName, "geyser-compression-disabler", new GeyserSpigotCompressionDisabler());
}
}
})
@@ -177,6 +180,7 @@ public class GeyserSpigotInjector extends GeyserInjector {
bootstrap.getGeyserConfig().getRemote().port(), this.serverSocketAddress,
InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper());
session.connect();
+ session.disconnect("");
}
@Override
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java
index fe56cba1c..5c6101eae 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java
@@ -25,15 +25,15 @@
package org.geysermc.geyser.platform.spigot;
-import lombok.AllArgsConstructor;
import lombok.Getter;
+import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.geysermc.geyser.GeyserLogger;
import java.util.logging.Level;
import java.util.logging.Logger;
-@AllArgsConstructor
+@RequiredArgsConstructor
public class GeyserSpigotLogger implements GeyserLogger {
private final Logger logger;
@Getter @Setter
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java
index 1bc1718d7..2d13155f2 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java
@@ -46,6 +46,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.Constants;
import org.geysermc.geyser.GeyserBootstrap;
import org.geysermc.geyser.GeyserImpl;
+import org.geysermc.geyser.adapters.paper.PaperAdapters;
import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
import org.geysermc.geyser.api.command.Command;
import org.geysermc.geyser.api.extension.Extension;
@@ -78,14 +79,14 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
-import java.util.logging.Level;
public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
private GeyserSpigotCommandManager geyserCommandManager;
private GeyserSpigotConfiguration geyserConfig;
private GeyserSpigotInjector geyserInjector;
- private GeyserSpigotLogger geyserLogger;
+ private final GeyserSpigotLogger geyserLogger = GeyserPaperLogger.supported() ?
+ new GeyserPaperLogger(this, getLogger()) : new GeyserSpigotLogger(getLogger());
private IGeyserPingPassthrough geyserSpigotPingPassthrough;
private GeyserSpigotWorldManager geyserWorldManager;
@@ -113,12 +114,12 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
// We depend on this as a fallback in certain scenarios
BlockData.class.getMethod("getAsString");
} catch (ClassNotFoundException | NoSuchMethodException e) {
- getLogger().severe("*********************************************");
- getLogger().severe("");
- getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.header"));
- getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.13.2"));
- getLogger().severe("");
- getLogger().severe("*********************************************");
+ geyserLogger.error("*********************************************");
+ geyserLogger.error("");
+ geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.header"));
+ geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server.message", "1.13.2"));
+ geyserLogger.error("");
+ geyserLogger.error("*********************************************");
Bukkit.getPluginManager().disablePlugin(this);
return;
}
@@ -127,12 +128,12 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
Class.forName("net.md_5.bungee.chat.ComponentSerializer");
} catch (ClassNotFoundException e) {
if (!PaperAdventure.canSendMessageUsingComponent()) { // Prepare for Paper eventually removing Bungee chat
- getLogger().severe("*********************************************");
- getLogger().severe("");
- getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.header", getServer().getName()));
- getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.message", "Paper"));
- getLogger().severe("");
- getLogger().severe("*********************************************");
+ geyserLogger.error("*********************************************");
+ geyserLogger.error("");
+ geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.header", getServer().getName()));
+ geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_server_type.message", "Paper"));
+ geyserLogger.error("");
+ geyserLogger.error("*********************************************");
Bukkit.getPluginManager().disablePlugin(this);
return;
}
@@ -141,11 +142,11 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
try {
Class.forName("io.netty.util.internal.ObjectPool$ObjectCreator");
} catch (ClassNotFoundException e) {
- getLogger().severe("*********************************************");
- getLogger().severe("");
- getLogger().severe("This version of Spigot is using an outdated version of netty. Please use Paper instead!");
- getLogger().severe("");
- getLogger().severe("*********************************************");
+ geyserLogger.error("*********************************************");
+ geyserLogger.error("");
+ geyserLogger.error("This version of Spigot is using an outdated version of netty. Please use Paper instead!");
+ geyserLogger.error("");
+ geyserLogger.error("*********************************************");
Bukkit.getPluginManager().disablePlugin(this);
return;
}
@@ -153,8 +154,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
if (!loadConfig()) {
return;
}
- this.geyserLogger = GeyserPaperLogger.supported() ? new GeyserPaperLogger(this, getLogger(), geyserConfig.isDebugMode())
- : new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode());
+ this.geyserLogger.setDebug(geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
// Turn "(MC: 1.16.4)" into 1.16.4.
@@ -244,17 +244,29 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
if (Boolean.parseBoolean(System.getProperty("Geyser.UseDirectAdapters", "true"))) {
try {
- String name = Bukkit.getServer().getClass().getPackage().getName();
- String nmsVersion = name.substring(name.lastIndexOf('.') + 1);
- SpigotAdapters.registerWorldAdapter(nmsVersion);
+ boolean isPaper = false;
+ try {
+ String name = Bukkit.getServer().getClass().getPackage().getName();
+ String nmsVersion = name.substring(name.lastIndexOf('.') + 1);
+ SpigotAdapters.registerWorldAdapter(nmsVersion);
+ geyserLogger.debug("Using spigot NMS adapter for nms version: " + nmsVersion);
+ } catch (Exception e) { // Likely running on Paper 1.20.5+
+ geyserLogger.debug("Unable to find spigot world manager: " + e.getMessage());
+ //noinspection deprecation
+ int protocolVersion = Bukkit.getUnsafe().getProtocolVersion();
+ PaperAdapters.registerClosestWorldAdapter(protocolVersion);
+ isPaper = true;
+ geyserLogger.debug("Using paper world adapter for protocol version: " + protocolVersion);
+ }
+
if (isViaVersion && isViaVersionNeeded()) {
- this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this);
+ this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this, isPaper);
} else {
// No ViaVersion
- this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this);
+ this.geyserWorldManager = new GeyserSpigotNativeWorldManager(this, isPaper);
}
- geyserLogger.debug("Using NMS adapter: " + this.geyserWorldManager.getClass() + ", " + nmsVersion);
- } catch (Exception e) {
+ geyserLogger.debug("Using world manager of type: " + this.geyserWorldManager.getClass().getSimpleName());
+ } catch (Throwable e) {
if (geyserConfig.isDebugMode()) {
geyserLogger.debug("Error while attempting to find NMS adapter. Most likely, this can be safely ignored. :)");
e.printStackTrace();
@@ -433,7 +445,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
return false;
}
for (int i = protocolList.size() - 1; i >= 0; i--) {
- MappingData mappingData = protocolList.get(i).getProtocol().getMappingData();
+ MappingData mappingData = protocolList.get(i).protocol().getMappingData();
if (mappingData != null) {
return true;
}
@@ -474,7 +486,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap {
(x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class);
} catch (IOException ex) {
- getLogger().log(Level.SEVERE, GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
+ geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
ex.printStackTrace();
Bukkit.getPluginManager().disablePlugin(this);
return false;
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/PaperAdventure.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/PaperAdventure.java
index 9e0b14b11..fa7555ac6 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/PaperAdventure.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/PaperAdventure.java
@@ -25,7 +25,7 @@
package org.geysermc.geyser.platform.spigot;
-import com.github.steveice10.mc.protocol.data.DefaultComponentSerializer;
+import org.geysermc.mcprotocollib.protocol.data.DefaultComponentSerializer;
import net.kyori.adventure.text.Component;
import org.bukkit.command.CommandSender;
import org.checkerframework.checker.nullness.qual.Nullable;
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java
index 01b0be9f2..963f5bac3 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java
@@ -25,10 +25,8 @@
package org.geysermc.geyser.platform.spigot.world;
-import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValueType;
-import org.cloudburstmc.math.vector.Vector3i;
-import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
-import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
+import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
@@ -40,13 +38,17 @@ import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPistonEvent;
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPistonRetractEvent;
+import org.cloudburstmc.math.vector.Vector3i;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.block.BlockStateValues;
+import org.geysermc.geyser.level.block.property.Properties;
+import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.PistonCache;
import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
+import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
import java.util.List;
import java.util.Map;
@@ -85,7 +87,7 @@ public class GeyserPistonListener implements Listener {
PistonValueType type = isExtend ? PistonValueType.PUSHING : PistonValueType.PULLING;
boolean sticky = event.isSticky();
- Object2IntMap attachedBlocks = new Object2IntArrayMap<>();
+ Object2ObjectMap attachedBlocks = new Object2ObjectArrayMap<>();
boolean blocksFilled = false;
for (Map.Entry entry : geyser.getSessionManager().getSessions().entrySet()) {
@@ -108,10 +110,10 @@ public class GeyserPistonListener implements Listener {
List blocks = isExtend ? ((BlockPistonExtendEvent) event).getBlocks() : ((BlockPistonRetractEvent) event).getBlocks();
for (Block block : blocks) {
Location attachedLocation = block.getLocation();
- int blockId = worldManager.getBlockNetworkId(block);
+ BlockState state = BlockState.of(worldManager.getBlockNetworkId(block));
// Ignore blocks that will be destroyed
- if (BlockStateValues.canPistonMoveBlock(blockId, isExtend)) {
- attachedBlocks.put(getVector(attachedLocation), blockId);
+ if (BlockStateValues.canPistonMoveBlock(state, isExtend)) {
+ attachedBlocks.put(getVector(attachedLocation), state);
}
}
blocksFilled = true;
@@ -119,7 +121,7 @@ public class GeyserPistonListener implements Listener {
int pistonBlockId = worldManager.getBlockNetworkId(event.getBlock());
// event.getDirection() is unreliable
- Direction orientation = BlockStateValues.getPistonOrientation(pistonBlockId);
+ Direction orientation = BlockState.of(pistonBlockId).getValue(Properties.FACING);
session.executeInEventLoop(() -> {
PistonCache pistonCache = session.getPistonCache();
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java
index 71aba11f9..1cdd77c64 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java
@@ -33,7 +33,7 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
import org.geysermc.geyser.GeyserImpl;
-import org.geysermc.geyser.level.block.BlockStateValues;
+import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.platform.spigot.world.manager.GeyserSpigotWorldManager;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession;
@@ -59,11 +59,11 @@ public class GeyserSpigotBlockPlaceListener implements Listener {
event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())));
} else {
String javaBlockId = event.getBlockPlaced().getBlockData().getAsString();
- placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, BlockStateValues.JAVA_AIR_ID)));
+ placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getOrDefault(javaBlockId, Block.JAVA_AIR_ID)));
}
placeBlockSoundPacket.setIdentifier(":");
session.sendUpstreamPacket(placeBlockSoundPacket);
session.setLastBlockPlacePosition(null);
- session.setLastBlockPlacedId(null);
+ session.setLastBlockPlaced(null);
}
}
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java
index 021db5ec1..fe2dda053 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java
@@ -46,8 +46,8 @@ public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorl
private final Int2IntMap oldToNewBlockId;
- public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin) {
- super(plugin);
+ public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin, boolean isPaper) {
+ super(plugin, isPaper);
IntList allBlockStates = adapter.getAllBlockStates();
oldToNewBlockId = new Int2IntOpenHashMap(allBlockStates.size());
ProtocolVersion serverVersion = plugin.getServerProtocolVersion();
@@ -58,7 +58,7 @@ public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorl
int newBlockId = oldBlockId;
// protocolList should *not* be null; we checked for that before initializing this class
for (int i = protocolList.size() - 1; i >= 0; i--) {
- MappingData mappingData = protocolList.get(i).getProtocol().getMappingData();
+ MappingData mappingData = protocolList.get(i).protocol().getMappingData();
if (mappingData != null) {
newBlockId = mappingData.getNewBlockStateId(newBlockId);
}
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java
index 00212663c..c99ca4e78 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java
@@ -26,27 +26,34 @@
package org.geysermc.geyser.platform.spigot.world.manager;
import org.bukkit.Bukkit;
+import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.checkerframework.checker.nullness.qual.Nullable;
+import org.geysermc.geyser.adapters.WorldAdapter;
+import org.geysermc.geyser.adapters.paper.PaperAdapters;
import org.geysermc.geyser.adapters.spigot.SpigotAdapters;
-import org.geysermc.geyser.adapters.spigot.SpigotWorldAdapter;
import org.geysermc.geyser.level.block.BlockStateValues;
+import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.session.GeyserSession;
public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager {
- protected final SpigotWorldAdapter adapter;
+ protected final WorldAdapter adapter;
- public GeyserSpigotNativeWorldManager(Plugin plugin) {
+ public GeyserSpigotNativeWorldManager(Plugin plugin, boolean isPaper) {
super(plugin);
- adapter = SpigotAdapters.getWorldAdapter();
+ if (isPaper) {
+ adapter = PaperAdapters.getWorldAdapter();
+ } else {
+ adapter = SpigotAdapters.getWorldAdapter();
+ }
}
@Override
public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername());
if (player == null) {
- return BlockStateValues.JAVA_AIR_ID;
+ return Block.JAVA_AIR_ID;
}
return adapter.getBlockAt(player.getWorld(), x, y, z);
}
diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java
index 42f0d17f4..e247a72c7 100644
--- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java
+++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java
@@ -25,31 +25,24 @@
package org.geysermc.geyser.platform.spigot.world.manager;
-import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
-import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo;
-import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import org.bukkit.Bukkit;
-import org.bukkit.Chunk;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
-import org.cloudburstmc.nbt.NbtMap;
-import org.geysermc.erosion.bukkit.BukkitLecterns;
-import org.geysermc.erosion.bukkit.BukkitUtils;
import org.geysermc.erosion.bukkit.PickBlockUtils;
import org.geysermc.erosion.bukkit.SchedulerUtils;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.level.GameRule;
import org.geysermc.geyser.level.WorldManager;
-import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.registry.BlockRegistries;
import org.geysermc.geyser.session.GeyserSession;
-import org.geysermc.geyser.util.BlockEntityUtils;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
-import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
@@ -58,23 +51,21 @@ import java.util.concurrent.CompletableFuture;
*/
public class GeyserSpigotWorldManager extends WorldManager {
private final Plugin plugin;
- private final BukkitLecterns lecterns;
public GeyserSpigotWorldManager(Plugin plugin) {
this.plugin = plugin;
- this.lecterns = new BukkitLecterns(plugin);
}
@Override
public int getBlockAt(GeyserSession session, int x, int y, int z) {
Player bukkitPlayer;
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
- return BlockStateValues.JAVA_AIR_ID;
+ return org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID;
}
World world = bukkitPlayer.getWorld();
if (!world.isChunkLoaded(x >> 4, z >> 4)) {
// If the chunk isn't loaded, how could we even be here?
- return BlockStateValues.JAVA_AIR_ID;
+ return org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID;
}
return getBlockNetworkId(world.getBlockAt(x, y, z));
@@ -85,9 +76,9 @@ public class GeyserSpigotWorldManager extends WorldManager {
// Terrible behavior, but this is basically what's always been happening behind the scenes anyway.
CompletableFuture blockData = new CompletableFuture<>();
Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString()));
- return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), BlockStateValues.JAVA_AIR_ID);
+ return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(blockData.join(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID);
}
- return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID);
+ return BlockRegistries.JAVA_IDENTIFIER_TO_ID.getOrDefault(block.getBlockData().getAsString(), org.geysermc.geyser.level.block.type.Block.JAVA_AIR_ID); // TODO could just make this a BlockState lookup?
}
@Override
@@ -95,69 +86,6 @@ public class GeyserSpigotWorldManager extends WorldManager {
return true;
}
- @Override
- public void sendLecternData(GeyserSession session, int x, int y, int z) {
- Player bukkitPlayer;
- if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
- return;
- }
-
- Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
- // Run as a task to prevent async issues
- SchedulerUtils.runTask(this.plugin, () -> sendLecternData(session, block, false), block);
- }
-
- public void sendLecternData(GeyserSession session, int x, int z, List blockEntityInfos) {
- Player bukkitPlayer;
- if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) {
- return;
- }
- if (SchedulerUtils.FOLIA) {
- Chunk chunk = getChunk(bukkitPlayer.getWorld(), x, z);
- if (chunk == null) {
- return;
- }
- Bukkit.getRegionScheduler().execute(this.plugin, bukkitPlayer.getWorld(), x, z, () ->
- sendLecternData(session, chunk, blockEntityInfos));
- } else {
- Bukkit.getScheduler().runTask(this.plugin, () -> {
- Chunk chunk = getChunk(bukkitPlayer.getWorld(), x, z);
- if (chunk == null) {
- return;
- }
- sendLecternData(session, chunk, blockEntityInfos);
- });
- }
- }
-
- private @Nullable Chunk getChunk(World world, int x, int z) {
- if (!world.isChunkLoaded(x, z)) {
- return null;
- }
- return world.getChunkAt(x, z);
- }
-
- private void sendLecternData(GeyserSession session, Chunk chunk, List blockEntityInfos) {
- //noinspection ForLoopReplaceableByForEach - avoid constructing Iterator
- for (int i = 0; i < blockEntityInfos.size(); i++) {
- BlockEntityInfo info = blockEntityInfos.get(i);
- Block block = chunk.getBlock(info.getX(), info.getY(), info.getZ());
- sendLecternData(session, block, true);
- }
- }
-
- private void sendLecternData(GeyserSession session, Block block, boolean isChunkLoad) {
- NbtMap blockEntityTag = this.lecterns.getLecternData(block, isChunkLoad);
- if (blockEntityTag != null) {
- BlockEntityUtils.updateBlockEntity(session, blockEntityTag, BukkitUtils.getVector(block.getLocation()));
- }
- }
-
- @Override
- public boolean shouldExpectLecternHandled(GeyserSession session) {
- return true;
- }
-
public boolean getGameRuleBool(GeyserSession session, GameRule gameRule) {
org.bukkit.GameRule> bukkitGameRule = org.bukkit.GameRule.getByName(gameRule.getJavaID());
if (bukkitGameRule == null) {
@@ -205,18 +133,17 @@ public class GeyserSpigotWorldManager extends WorldManager {
}
@Override
- public @NonNull CompletableFuture<@Nullable CompoundTag> getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) {
- CompletableFuture<@Nullable CompoundTag> future = new CompletableFuture<>();
+ public @NonNull CompletableFuture<@Nullable DataComponents> getPickItemComponents(GeyserSession session, int x, int y, int z, boolean addNbtData) {
Player bukkitPlayer;
if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) {
- future.complete(null);
- return future;
+ return CompletableFuture.completedFuture(null);
}
+ CompletableFuture> future = new CompletableFuture<>();
Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z);
// Paper 1.19.3 complains about async access otherwise.
// java.lang.IllegalStateException: Tile is null, asynchronous access?
SchedulerUtils.runTask(this.plugin, () -> future.complete(PickBlockUtils.pickBlock(block)), block);
- return future;
+ return future.thenApply(RAW_TRANSFORMER);
}
/**
diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java
index 039004867..f289fa2ba 100644
--- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java
+++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java
@@ -71,7 +71,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
private GeyserCommandManager geyserCommandManager;
private GeyserStandaloneConfiguration geyserConfig;
- private GeyserStandaloneLogger geyserLogger;
+ private final GeyserStandaloneLogger geyserLogger = new GeyserStandaloneLogger();
private IGeyserPingPassthrough geyserPingPassthrough;
private GeyserStandaloneGUI gui;
@Getter
@@ -181,8 +181,6 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap {
}
}
- this.geyserLogger = new GeyserStandaloneLogger();
-
if (useGui && gui == null) {
gui = new GeyserStandaloneGUI(geyserLogger);
gui.redirectSystemStreams();
diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java
index c3e2e10e8..b82d8cc94 100644
--- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java
+++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java
@@ -100,7 +100,7 @@ public class GeyserStandaloneGUI {
Container cp = frame.getContentPane();
// Fetch and set the icon for the frame
- URL image = getClass().getClassLoader().getResource("icon.png");
+ URL image = getClass().getClassLoader().getResource("assets/geyser/icon.png");
if (image != null) {
ImageIcon icon = new ImageIcon(image);
frame.setIconImage(icon.getImage());
diff --git a/bootstrap/velocity/build.gradle.kts b/bootstrap/velocity/build.gradle.kts
index 8908b2afd..4daad9784 100644
--- a/bootstrap/velocity/build.gradle.kts
+++ b/bootstrap/velocity/build.gradle.kts
@@ -1,15 +1,19 @@
dependencies {
annotationProcessor(libs.velocity.api)
api(projects.core)
+
+ compileOnlyApi(libs.velocity.api)
}
platformRelocate("com.fasterxml.jackson")
platformRelocate("it.unimi.dsi.fastutil")
platformRelocate("net.kyori.adventure.text.serializer.gson.legacyimpl")
+platformRelocate("org.yaml")
exclude("com.google.*:*")
-// Needed because Velocity provides every dependency except netty-resolver-dns
+// Needed because Velocity provides every dependency except netty-resolver-dns
+exclude("io.netty.incubator:.*")
exclude("io.netty:netty-transport-native-epoll:*")
exclude("io.netty:netty-transport-native-unix-common:*")
exclude("io.netty:netty-transport-native-kqueue:*")
@@ -54,6 +58,7 @@ tasks.withType {
exclude(dependency("io.netty:netty-transport:.*"))
exclude(dependency("io.netty:netty-codec:.*"))
exclude(dependency("io.netty:netty-codec-haproxy:.*"))
+ exclude(dependency("io.netty.incubator:.*"))
exclude(dependency("org.slf4j:.*"))
exclude(dependency("org.ow2.asm:.*"))
// Exclude all Kyori dependencies except the legacy NBT serializer
@@ -64,4 +69,9 @@ tasks.withType {
exclude(dependency("net.kyori:adventure-text-serializer-legacy:.*"))
exclude(dependency("net.kyori:adventure-nbt:.*"))
}
+}
+
+modrinth {
+ uploadFile.set(tasks.getByPath("shadowJar"))
+ loaders.addAll("velocity")
}
\ No newline at end of file
diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java
index 567870e7f..4d10e4daf 100644
--- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java
+++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java
@@ -25,13 +25,13 @@
package org.geysermc.geyser.platform.velocity;
-import lombok.AllArgsConstructor;
import lombok.Getter;
+import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.geysermc.geyser.GeyserLogger;
import org.slf4j.Logger;
-@AllArgsConstructor
+@RequiredArgsConstructor
public class GeyserVelocityLogger implements GeyserLogger {
private final Logger logger;
@Getter @Setter
diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java
index 8944ea134..b2258d3a3 100644
--- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java
+++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java
@@ -26,6 +26,7 @@
package org.geysermc.geyser.platform.velocity;
import com.velocitypowered.api.event.proxy.ProxyPingEvent;
+import com.velocitypowered.api.network.ProtocolState;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.InboundConnection;
import com.velocitypowered.api.proxy.ProxyServer;
@@ -88,6 +89,11 @@ public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough {
public ProtocolVersion getProtocolVersion() {
return ProtocolVersion.MAXIMUM_VERSION;
}
+
+ @Override
+ public ProtocolState getProtocolState() {
+ return ProtocolState.STATUS;
+ }
}
}
diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java
index 347a47d63..539bdadbf 100644
--- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java
+++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java
@@ -64,44 +64,44 @@ import java.util.UUID;
@Plugin(id = "geyser", name = GeyserImpl.NAME + "-Velocity", version = GeyserImpl.VERSION, url = "https://geysermc.org", authors = "GeyserMC")
public class GeyserVelocityPlugin implements GeyserBootstrap {
- @Inject
- private Logger logger;
-
- @Inject
- private ProxyServer proxyServer;
-
- @Inject
- private CommandManager commandManager;
+ private final ProxyServer proxyServer;
+ private final CommandManager commandManager;
+ private final GeyserVelocityLogger geyserLogger;
private GeyserCommandManager geyserCommandManager;
private GeyserVelocityConfiguration geyserConfig;
private GeyserVelocityInjector geyserInjector;
- private GeyserVelocityLogger geyserLogger;
private IGeyserPingPassthrough geyserPingPassthrough;
-
private GeyserImpl geyser;
@Getter
private final Path configFolder = Paths.get("plugins/" + GeyserImpl.NAME + "-Velocity/");
+ @Inject
+ public GeyserVelocityPlugin(ProxyServer server, Logger logger, CommandManager manager) {
+ this.geyserLogger = new GeyserVelocityLogger(logger);
+ this.proxyServer = server;
+ this.commandManager = manager;
+ }
+
@Override
public void onGeyserInitialize() {
GeyserLocale.init(this);
if (!ProtocolVersion.isSupported(GameProtocol.getJavaProtocolVersion())) {
- logger.error(" / \\");
- logger.error(" / \\");
- logger.error(" / | \\");
- logger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", proxyServer.getVersion().getName()));
- logger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
- logger.error(" / o \\");
- logger.error("/_____________\\");
+ geyserLogger.error(" / \\");
+ geyserLogger.error(" / \\");
+ geyserLogger.error(" / | \\");
+ geyserLogger.error(" / | \\ " + GeyserLocale.getLocaleStringLog("geyser.bootstrap.unsupported_proxy", proxyServer.getVersion().getName()));
+ geyserLogger.error(" / \\ " + GeyserLocale.getLocaleStringLog("geyser.may_not_work_as_intended_all_caps"));
+ geyserLogger.error(" / o \\");
+ geyserLogger.error("/_____________\\");
}
if (!loadConfig()) {
return;
}
- this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode());
+ this.geyserLogger.setDebug(geyserConfig.isDebugMode());
GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger);
this.geyser = GeyserImpl.load(PlatformType.VELOCITY, this);
@@ -249,7 +249,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap {
"config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
this.geyserConfig = FileUtils.loadConfig(configFile, GeyserVelocityConfiguration.class);
} catch (IOException ex) {
- logger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
+ geyserLogger.error(GeyserLocale.getLocaleStringLog("geyser.config.failed"), ex);
ex.printStackTrace();
return false;
}
diff --git a/bootstrap/viaproxy/build.gradle.kts b/bootstrap/viaproxy/build.gradle.kts
new file mode 100644
index 000000000..6eadc790f
--- /dev/null
+++ b/bootstrap/viaproxy/build.gradle.kts
@@ -0,0 +1,29 @@
+dependencies {
+ api(projects.core)
+
+ compileOnlyApi(libs.viaproxy)
+}
+
+platformRelocate("net.kyori")
+platformRelocate("org.yaml")
+platformRelocate("it.unimi.dsi.fastutil")
+platformRelocate("org.cloudburstmc.netty")
+
+// These dependencies are already present on the platform
+provided(libs.viaproxy)
+
+application {
+ mainClass.set("org.geysermc.geyser.platform.viaproxy.GeyserViaProxyMain")
+}
+
+tasks.withType {
+ archiveBaseName.set("Geyser-ViaProxy")
+
+ dependencies {
+ exclude(dependency("com.google.*:.*"))
+ exclude(dependency("io.netty:.*"))
+ exclude(dependency("io.netty.incubator:.*"))
+ exclude(dependency("org.slf4j:.*"))
+ exclude(dependency("org.ow2.asm:.*"))
+ }
+}
diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java
new file mode 100644
index 000000000..afc46fa6a
--- /dev/null
+++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyConfiguration.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+package org.geysermc.geyser.platform.viaproxy;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import net.raphimc.vialegacy.api.LegacyProtocolVersion;
+import net.raphimc.viaproxy.ViaProxy;
+import net.raphimc.viaproxy.protocoltranslator.viaproxy.ViaProxyConfig;
+import org.geysermc.geyser.configuration.GeyserJacksonConfiguration;
+
+import java.io.File;
+import java.nio.file.Path;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@SuppressWarnings("FieldMayBeFinal") // Jackson requires that the fields are not final
+public class GeyserViaProxyConfiguration extends GeyserJacksonConfiguration {
+
+ private RemoteConfiguration remote = new RemoteConfiguration() {
+ @Override
+ public boolean isForwardHost() {
+ return super.isForwardHost() || !ViaProxy.getConfig().getWildcardDomainHandling().equals(ViaProxyConfig.WildcardDomainHandling.NONE);
+ }
+ };
+
+ @Override
+ public Path getFloodgateKeyPath() {
+ return new File(GeyserViaProxyPlugin.ROOT_FOLDER, this.getFloodgateKeyFile()).toPath();
+ }
+
+ @Override
+ public int getPingPassthroughInterval() {
+ int interval = super.getPingPassthroughInterval();
+ if (interval < 15 && ViaProxy.getConfig().getTargetVersion() != null && ViaProxy.getConfig().getTargetVersion().olderThanOrEqualTo(LegacyProtocolVersion.r1_6_4)) {
+ // <= 1.6.4 servers sometimes block incoming connections from an IP address if too many connections are made
+ interval = 15;
+ }
+ return interval;
+ }
+
+ @Override
+ public RemoteConfiguration getRemote() {
+ return this.remote;
+ }
+
+}
diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyDumpInfo.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyDumpInfo.java
new file mode 100644
index 000000000..0bfc9d022
--- /dev/null
+++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyDumpInfo.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+package org.geysermc.geyser.platform.viaproxy;
+
+import lombok.Getter;
+import net.raphimc.viaproxy.ViaProxy;
+import net.raphimc.viaproxy.plugins.ViaProxyPlugin;
+import org.geysermc.geyser.dump.BootstrapDumpInfo;
+import org.geysermc.geyser.text.AsteriskSerializer;
+
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Getter
+public class GeyserViaProxyDumpInfo extends BootstrapDumpInfo {
+
+ private final String platformVersion;
+ private final boolean onlineMode;
+
+ @AsteriskSerializer.Asterisk(isIp = true)
+ private final String serverIP;
+ private final int serverPort;
+ private final List plugins;
+
+ public GeyserViaProxyDumpInfo() {
+ this.platformVersion = ViaProxy.VERSION;
+ this.onlineMode = ViaProxy.getConfig().isProxyOnlineMode();
+ if (ViaProxy.getConfig().getBindAddress() instanceof InetSocketAddress inetSocketAddress) {
+ this.serverIP = inetSocketAddress.getHostString();
+ this.serverPort = inetSocketAddress.getPort();
+ } else {
+ this.serverIP = "unsupported";
+ this.serverPort = 0;
+ }
+ this.plugins = new ArrayList<>();
+
+ for (ViaProxyPlugin plugin : ViaProxy.getPluginManager().getPlugins()) {
+ this.plugins.add(new PluginInfo(true, plugin.getName(), plugin.getVersion(), "unknown", Collections.singletonList(plugin.getAuthor())));
+ }
+ }
+
+}
diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyLogger.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyLogger.java
new file mode 100644
index 000000000..10f414b51
--- /dev/null
+++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyLogger.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+package org.geysermc.geyser.platform.viaproxy;
+
+import net.raphimc.viaproxy.cli.ConsoleFormatter;
+import org.apache.logging.log4j.Logger;
+import org.geysermc.geyser.GeyserLogger;
+import org.geysermc.geyser.command.GeyserCommandSource;
+
+public class GeyserViaProxyLogger implements GeyserLogger, GeyserCommandSource {
+
+ private final Logger logger;
+ private boolean debug;
+
+ public GeyserViaProxyLogger(Logger logger) {
+ this.logger = logger;
+ }
+
+ @Override
+ public void severe(String message) {
+ this.logger.fatal(ConsoleFormatter.convert(message));
+ }
+
+ @Override
+ public void severe(String message, Throwable error) {
+ this.logger.fatal(ConsoleFormatter.convert(message), error);
+ }
+
+ @Override
+ public void error(String message) {
+ this.logger.error(ConsoleFormatter.convert(message));
+ }
+
+ @Override
+ public void error(String message, Throwable error) {
+ this.logger.error(ConsoleFormatter.convert(message), error);
+ }
+
+ @Override
+ public void warning(String message) {
+ this.logger.warn(ConsoleFormatter.convert(message));
+ }
+
+ @Override
+ public void info(String message) {
+ this.logger.info(ConsoleFormatter.convert(message));
+ }
+
+ @Override
+ public void debug(String message) {
+ if (this.debug) {
+ this.logger.debug(ConsoleFormatter.convert(message));
+ }
+ }
+
+ @Override
+ public void setDebug(boolean debug) {
+ this.debug = debug;
+ }
+
+ @Override
+ public boolean isDebug() {
+ return this.debug;
+ }
+
+}
diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyMain.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyMain.java
new file mode 100644
index 000000000..582a97d78
--- /dev/null
+++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyMain.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.viaproxy;
+
+import org.geysermc.geyser.GeyserMain;
+
+public class GeyserViaProxyMain extends GeyserMain {
+
+ public static void main(String[] args) {
+ new GeyserViaProxyMain().displayMessage();
+ }
+
+ public String getPluginType() {
+ return "ViaProxy";
+ }
+
+ public String getPluginFolder() {
+ return "plugins";
+ }
+
+}
diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java
new file mode 100644
index 000000000..bdc80335a
--- /dev/null
+++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/GeyserViaProxyPlugin.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+package org.geysermc.geyser.platform.viaproxy;
+
+import net.lenni0451.lambdaevents.EventHandler;
+import net.raphimc.vialegacy.api.LegacyProtocolVersion;
+import net.raphimc.viaproxy.ViaProxy;
+import net.raphimc.viaproxy.plugins.PluginManager;
+import net.raphimc.viaproxy.plugins.ViaProxyPlugin;
+import net.raphimc.viaproxy.plugins.events.ConsoleCommandEvent;
+import net.raphimc.viaproxy.plugins.events.ProxyStartEvent;
+import net.raphimc.viaproxy.plugins.events.ProxyStopEvent;
+import net.raphimc.viaproxy.plugins.events.ShouldVerifyOnlineModeEvent;
+import org.apache.logging.log4j.LogManager;
+import org.geysermc.geyser.GeyserBootstrap;
+import org.geysermc.geyser.GeyserImpl;
+import org.geysermc.geyser.GeyserLogger;
+import org.geysermc.geyser.api.event.EventRegistrar;
+import org.geysermc.geyser.api.network.AuthType;
+import org.geysermc.geyser.api.util.PlatformType;
+import org.geysermc.geyser.command.GeyserCommandManager;
+import org.geysermc.geyser.configuration.GeyserConfiguration;
+import org.geysermc.geyser.dump.BootstrapDumpInfo;
+import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough;
+import org.geysermc.geyser.ping.IGeyserPingPassthrough;
+import org.geysermc.geyser.platform.viaproxy.listener.GeyserServerTransferListener;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.text.GeyserLocale;
+import org.geysermc.geyser.util.FileUtils;
+import org.geysermc.geyser.util.LoopbackUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.UUID;
+
+public class GeyserViaProxyPlugin extends ViaProxyPlugin implements GeyserBootstrap, EventRegistrar {
+
+ public static final File ROOT_FOLDER = new File(PluginManager.PLUGINS_DIR, "Geyser");
+
+ private final GeyserViaProxyLogger logger = new GeyserViaProxyLogger(LogManager.getLogger("Geyser"));
+ private GeyserViaProxyConfiguration config;
+ private GeyserImpl geyser;
+ private GeyserCommandManager commandManager;
+ private IGeyserPingPassthrough pingPassthrough;
+
+ @Override
+ public void onEnable() {
+ ROOT_FOLDER.mkdirs();
+
+ GeyserLocale.init(this);
+ this.onGeyserInitialize();
+
+ ViaProxy.EVENT_MANAGER.register(this);
+ }
+
+ @Override
+ public void onDisable() {
+ this.onGeyserShutdown();
+ }
+
+ @EventHandler
+ private void onConsoleCommand(final ConsoleCommandEvent event) {
+ final String command = event.getCommand().startsWith("/") ? event.getCommand().substring(1) : event.getCommand();
+ if (this.getGeyserCommandManager().runCommand(this.getGeyserLogger(), command + " " + String.join(" ", event.getArgs()))) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ private void onShouldVerifyOnlineModeEvent(final ShouldVerifyOnlineModeEvent event) {
+ final UUID uuid = event.getProxyConnection().getGameProfile().getId();
+ if (uuid == null) return;
+
+ final GeyserSession connection = GeyserImpl.getInstance().onlineConnections().stream().filter(s -> s.javaUuid().equals(uuid)).findAny().orElse(null);
+ if (connection == null) return;
+
+ if (connection.javaUsername().equals(event.getProxyConnection().getGameProfile().getName())) {
+ event.setCancelled(true);
+ }
+ }
+
+ @EventHandler
+ private void onProxyStart(final ProxyStartEvent event) {
+ this.onGeyserEnable();
+ }
+
+ @EventHandler
+ private void onProxyStop(final ProxyStopEvent event) {
+ this.onGeyserDisable();
+ }
+
+ @Override
+ public void onGeyserInitialize() {
+ if (!this.loadConfig()) {
+ return;
+ }
+
+ this.geyser = GeyserImpl.load(PlatformType.VIAPROXY, this);
+ this.geyser.eventBus().register(this, new GeyserServerTransferListener());
+ LoopbackUtil.checkAndApplyLoopback(this.logger);
+ }
+
+ @Override
+ public void onGeyserEnable() {
+ if (GeyserImpl.getInstance().isReloading()) {
+ if (!this.loadConfig()) {
+ return;
+ }
+ }
+
+ this.commandManager = new GeyserCommandManager(this.geyser);
+ this.commandManager.init();
+
+ GeyserImpl.start();
+
+ if (ViaProxy.getConfig().getTargetVersion() != null && ViaProxy.getConfig().getTargetVersion().newerThanOrEqualTo(LegacyProtocolVersion.b1_8tob1_8_1)) {
+ // Only initialize the ping passthrough if the protocol version is above beta 1.7.3, as that's when the status protocol was added
+ this.pingPassthrough = GeyserLegacyPingPassthrough.init(this.geyser);
+ }
+ }
+
+ @Override
+ public void onGeyserDisable() {
+ this.geyser.disable();
+ }
+
+ @Override
+ public void onGeyserShutdown() {
+ this.geyser.shutdown();
+ }
+
+ @Override
+ public GeyserConfiguration getGeyserConfig() {
+ return this.config;
+ }
+
+ @Override
+ public GeyserLogger getGeyserLogger() {
+ return this.logger;
+ }
+
+ @Override
+ public GeyserCommandManager getGeyserCommandManager() {
+ return this.commandManager;
+ }
+
+ @Override
+ public IGeyserPingPassthrough getGeyserPingPassthrough() {
+ return this.pingPassthrough;
+ }
+
+ @Override
+ public Path getConfigFolder() {
+ return ROOT_FOLDER.toPath();
+ }
+
+ @Override
+ public BootstrapDumpInfo getDumpInfo() {
+ return new GeyserViaProxyDumpInfo();
+ }
+
+ @NotNull
+ @Override
+ public String getServerBindAddress() {
+ if (ViaProxy.getConfig().getBindAddress() instanceof InetSocketAddress socketAddress) {
+ return socketAddress.getHostString();
+ } else {
+ throw new IllegalStateException("Unsupported bind address type: " + ViaProxy.getConfig().getBindAddress().getClass().getName());
+ }
+ }
+
+ @Override
+ public int getServerPort() {
+ if (ViaProxy.getConfig().getBindAddress() instanceof InetSocketAddress socketAddress) {
+ return socketAddress.getPort();
+ } else {
+ throw new IllegalStateException("Unsupported bind address type: " + ViaProxy.getConfig().getBindAddress().getClass().getName());
+ }
+ }
+
+ @Override
+ public boolean testFloodgatePluginPresent() {
+ return false;
+ }
+
+ private boolean loadConfig() {
+ try {
+ final File configFile = FileUtils.fileOrCopiedFromResource(new File(ROOT_FOLDER, "config.yml"), "config.yml", s -> s.replaceAll("generateduuid", UUID.randomUUID().toString()), this);
+ this.config = FileUtils.loadConfig(configFile, GeyserViaProxyConfiguration.class);
+ } catch (IOException e) {
+ this.logger.severe(GeyserLocale.getLocaleStringLog("geyser.config.failed"), e);
+ return false;
+ }
+ this.config.getRemote().setAuthType(Files.isRegularFile(this.config.getFloodgateKeyPath()) ? AuthType.FLOODGATE : AuthType.OFFLINE);
+ this.logger.setDebug(this.config.isDebugMode());
+ GeyserConfiguration.checkGeyserConfiguration(this.config, this.logger);
+ return true;
+ }
+
+}
diff --git a/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/listener/GeyserServerTransferListener.java b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/listener/GeyserServerTransferListener.java
new file mode 100644
index 000000000..64b3cc56e
--- /dev/null
+++ b/bootstrap/viaproxy/src/main/java/org/geysermc/geyser/platform/viaproxy/listener/GeyserServerTransferListener.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.platform.viaproxy.listener;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.net.HostAndPort;
+import org.geysermc.event.PostOrder;
+import org.geysermc.event.subscribe.Subscribe;
+import org.geysermc.geyser.api.event.bedrock.SessionLoginEvent;
+import org.geysermc.geyser.api.event.java.ServerTransferEvent;
+import org.geysermc.geyser.session.GeyserSession;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class GeyserServerTransferListener {
+
+ private final Cache> cookieStorages = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build();
+
+ @Subscribe(postOrder = PostOrder.FIRST)
+ private void onServerTransfer(final ServerTransferEvent event) {
+ this.cookieStorages.put(event.connection().xuid(), event.cookies());
+ final GeyserSession geyserSession = (GeyserSession) event.connection();
+ final HostAndPort hostAndPort = HostAndPort.fromString(geyserSession.getClientData().getServerAddress()).withDefaultPort(19132);
+ event.bedrockHost(hostAndPort.getHost());
+ event.bedrockPort(hostAndPort.getPort());
+ }
+
+ @Subscribe(postOrder = PostOrder.FIRST)
+ private void onSessionLogin(final SessionLoginEvent event) {
+ final Map cookies = this.cookieStorages.asMap().remove(event.connection().xuid());
+ if (cookies != null) {
+ event.cookies(cookies);
+ event.transferring(true);
+ }
+ }
+
+}
diff --git a/bootstrap/viaproxy/src/main/resources/viaproxy.yml b/bootstrap/viaproxy/src/main/resources/viaproxy.yml
new file mode 100644
index 000000000..66fbdb932
--- /dev/null
+++ b/bootstrap/viaproxy/src/main/resources/viaproxy.yml
@@ -0,0 +1,5 @@
+name: "${name}-ViaProxy"
+version: "${version}"
+author: "${author}"
+main: "org.geysermc.geyser.platform.viaproxy.GeyserViaProxyPlugin"
+min-version: "3.2.1"
diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts
index c0c683920..190386667 100644
--- a/build-logic/build.gradle.kts
+++ b/build-logic/build.gradle.kts
@@ -4,14 +4,20 @@ plugins {
repositories {
gradlePluginPortal()
- maven("https://repo.opencollab.dev/maven-snapshots")
+
+ maven("https://repo.opencollab.dev/maven-snapshots/")
+ maven("https://maven.fabricmc.net/")
+ maven("https://maven.neoforged.net/releases")
+ maven("https://maven.architectury.dev/")
}
dependencies {
- implementation("net.kyori", "indra-common", "3.1.1")
- implementation("com.github.johnrengelman", "shadow", "7.1.3-SNAPSHOT")
-
- // Within the gradle plugin classpath, there is a version conflict between loom and some other
- // plugin for databind. This fixes it: minimum 2.13.2 is required by loom.
- implementation("com.fasterxml.jackson.core:jackson-databind:2.14.0")
+ // this is OK as long as the same version catalog is used in the main build and build-logic
+ // see https://github.com/gradle/gradle/issues/15383#issuecomment-779893192
+ implementation(files(libs.javaClass.superclass.protectionDomain.codeSource.location))
+ implementation(libs.indra)
+ implementation(libs.shadow)
+ implementation(libs.architectury.plugin)
+ implementation(libs.architectury.loom)
+ implementation(libs.minotaur)
}
diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts
new file mode 100644
index 000000000..63bde189b
--- /dev/null
+++ b/build-logic/settings.gradle.kts
@@ -0,0 +1,11 @@
+@file:Suppress("UnstableApiUsage")
+
+dependencyResolutionManagement {
+ versionCatalogs {
+ create("libs") {
+ from(files("../gradle/libs.versions.toml"))
+ }
+ }
+}
+
+rootProject.name = "build-logic"
\ No newline at end of file
diff --git a/build-logic/src/main/kotlin/LibsAccessor.kt b/build-logic/src/main/kotlin/LibsAccessor.kt
new file mode 100644
index 000000000..2a0c09eb6
--- /dev/null
+++ b/build-logic/src/main/kotlin/LibsAccessor.kt
@@ -0,0 +1,6 @@
+import org.gradle.accessors.dm.LibrariesForLibs
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.getByType
+
+val Project.libs: LibrariesForLibs
+ get() = rootProject.extensions.getByType()
\ No newline at end of file
diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt
index 1e1732852..41e11344b 100644
--- a/build-logic/src/main/kotlin/extensions.kt
+++ b/build-logic/src/main/kotlin/extensions.kt
@@ -24,11 +24,17 @@
*/
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
+import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.artifacts.MinimalExternalModuleDependency
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.provider.Provider
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.options.Option
+import org.gradle.api.tasks.TaskAction
import org.gradle.kotlin.dsl.named
+import java.io.File
+import java.net.URL
fun Project.relocate(pattern: String) {
tasks.named("shadowJar") {
@@ -52,22 +58,63 @@ fun Project.platformRelocate(pattern: String, exclusion: String = "") {
val providedDependencies = mutableMapOf>()
-fun Project.provided(pattern: String, name: String, version: String, excludedOn: Int = 0b110) {
+fun getProvidedDependenciesForProject(projectName: String): MutableSet {
+ return providedDependencies.getOrDefault(projectName, emptySet()).toMutableSet()
+}
+
+fun Project.provided(pattern: String, name: String, excludedOn: Int = 0b110) {
providedDependencies.getOrPut(project.name) { mutableSetOf() }
- .add("${calcExclusion(pattern, 0b100, excludedOn)}:" +
- "${calcExclusion(name, 0b10, excludedOn)}:" +
- calcExclusion(version, 0b1, excludedOn))
- dependencies.add("compileOnlyApi", "$pattern:$name:$version")
+ .add("${calcExclusion(pattern, 0b100, excludedOn)}:${calcExclusion(name, 0b10, excludedOn)}")
}
fun Project.provided(dependency: ProjectDependency) =
- provided(dependency.group!!, dependency.name, dependency.version!!)
+ provided(dependency.group!!, dependency.name)
fun Project.provided(dependency: MinimalExternalModuleDependency) =
- provided(dependency.module.group, dependency.module.name, dependency.versionConstraint.requiredVersion)
+ provided(dependency.module.group, dependency.module.name)
fun Project.provided(provider: Provider) =
provided(provider.get())
+open class DownloadFilesTask : DefaultTask() {
+ @Input
+ var urls: List = listOf()
+
+ @Input
+ var destinationDir: String = ""
+
+ @Option(option="suffix", description="suffix")
+ @Input
+ var suffix: String = ""
+
+ @Input
+ var suffixedFiles: List = listOf()
+
+ @TaskAction
+ fun downloadAndAddSuffix() {
+ urls.forEach { fileUrl ->
+ val fileName = fileUrl.substringAfterLast("/")
+ val baseName = fileName.substringBeforeLast(".")
+ val extension = fileName.substringAfterLast(".", "")
+ val shouldSuffix = fileName in suffixedFiles
+ val suffixedFileName = if (shouldSuffix && extension.isNotEmpty()) "$baseName.$suffix.$extension" else fileName
+ val outputFile = File(destinationDir, suffixedFileName)
+
+ if (!outputFile.parentFile.exists()) {
+ outputFile.parentFile.mkdirs()
+ }
+
+ URL(fileUrl).openStream().use { input ->
+ outputFile.outputStream().use { output ->
+ input.copyTo(output)
+ }
+ }
+
+ println("Downloaded: $suffixedFileName")
+ }
+ }
+}
+
private fun calcExclusion(section: String, bit: Int, excludedOn: Int): String =
- if (excludedOn and bit > 0) section else ""
\ No newline at end of file
+ if (excludedOn and bit > 0) section else ""
+
diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts
index 01c769733..950c0184b 100644
--- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts
+++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts
@@ -22,8 +22,8 @@ indra {
tasks {
processResources {
- // Spigot, BungeeCord, Velocity, Fabric
- filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json")) {
+ // Spigot, BungeeCord, Velocity, Fabric, ViaProxy, NeoForge
+ filesMatching(listOf("plugin.yml", "bungee.yml", "velocity-plugin.json", "fabric.mod.json", "viaproxy.yml", "META-INF/neoforge.mods.toml")) {
expand(
"id" to "geyser",
"name" to "Geyser",
diff --git a/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts
new file mode 100644
index 000000000..7952bcf14
--- /dev/null
+++ b/build-logic/src/main/kotlin/geyser.modded-conventions.gradle.kts
@@ -0,0 +1,123 @@
+@file:Suppress("UnstableApiUsage")
+
+import net.fabricmc.loom.task.RemapJarTask
+import org.gradle.kotlin.dsl.dependencies
+import org.gradle.kotlin.dsl.maven
+
+plugins {
+ id("geyser.publish-conventions")
+ id("architectury-plugin")
+ id("dev.architectury.loom")
+}
+
+// These are provided by Minecraft/modded platforms already, no need to include them
+provided("com.google.code.gson", "gson")
+provided("com.google.guava", ".*")
+provided("org.slf4j", "slf4j-api")
+provided("com.nukkitx.fastutil", ".*")
+provided("org.cloudburstmc.fastutil.maps", ".*")
+provided("org.cloudburstmc.fastutil.sets", ".*")
+provided("org.cloudburstmc.fastutil.commons", ".*")
+provided("org.cloudburstmc.fastutil", ".*")
+provided("org.checkerframework", "checker-qual")
+provided("io.netty", "netty-transport-classes-epoll")
+provided("io.netty", "netty-transport-native-epoll")
+provided("io.netty", "netty-transport-native-unix-common")
+provided("io.netty", "netty-transport-classes-kqueue")
+provided("io.netty", "netty-transport-native-kqueue")
+provided("io.netty.incubator", "netty-incubator-transport-native-io_uring")
+provided("io.netty.incubator", "netty-incubator-transport-classes-io_uring")
+provided("io.netty", "netty-handler")
+provided("io.netty", "netty-common")
+provided("io.netty", "netty-buffer")
+provided("io.netty", "netty-resolver")
+provided("io.netty", "netty-transport")
+provided("io.netty", "netty-codec")
+provided("io.netty", "netty-resolver-dns")
+provided("io.netty", "netty-resolver-dns-native-macos")
+provided("org.ow2.asm", "asm")
+
+architectury {
+ minecraft = libs.minecraft.get().version as String
+}
+
+loom {
+ silentMojangMappingsLicense()
+}
+
+indra {
+ javaVersions {
+ target(21)
+ }
+}
+
+configurations {
+ create("includeTransitive").isTransitive = true
+}
+
+tasks {
+ // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
+ // if it is present.
+ // If you remove this task, sources will not be generated.
+ sourcesJar {
+ archiveClassifier.set("sources")
+ from(sourceSets.main.get().allSource)
+ }
+
+ shadowJar {
+ // Mirrors the example fabric project, otherwise tons of dependencies are shaded that shouldn't be
+ configurations = listOf(project.configurations.shadow.get())
+ // The remapped shadowJar is the final desired mod jar
+ archiveVersion.set(project.version.toString())
+ archiveClassifier.set("shaded")
+ }
+
+ remapJar {
+ dependsOn(shadowJar)
+ inputFile.set(shadowJar.get().archiveFile)
+ archiveClassifier.set("")
+ archiveVersion.set("")
+ }
+
+ register("remapModrinthJar", RemapJarTask::class) {
+ dependsOn(shadowJar)
+ inputFile.set(shadowJar.get().archiveFile)
+ archiveVersion.set(project.version.toString() + "+build." + System.getenv("BUILD_NUMBER"))
+ archiveClassifier.set("")
+ }
+}
+
+afterEvaluate {
+ val providedDependencies = getProvidedDependenciesForProject(project.name)
+
+ // These are shaded, no need to JiJ them
+ configurations["shadow"].dependencies.forEach {shadowed ->
+ //println("Not including shadowed dependency: ${shadowed.group}:${shadowed.name}")
+ providedDependencies.add("${shadowed.group}:${shadowed.name}")
+ }
+
+ // Now: Include all transitive dependencies that aren't excluded
+ configurations["includeTransitive"].resolvedConfiguration.resolvedArtifacts.forEach { dep ->
+ if (!providedDependencies.contains("${dep.moduleVersion.id.group}:${dep.moduleVersion.id.name}")
+ and !providedDependencies.contains("${dep.moduleVersion.id.group}:.*")) {
+ //println("Including dependency via JiJ: ${dep.id}")
+ dependencies.add("include", dep.moduleVersion.id.toString())
+ } else {
+ //println("Not including ${dep.id} for ${project.name}!")
+ }
+ }
+}
+
+dependencies {
+ minecraft(libs.minecraft)
+ mappings(loom.officialMojangMappings())
+}
+
+repositories {
+ // mavenLocal()
+ maven("https://repo.opencollab.dev/main")
+ maven("https://jitpack.io")
+ maven("https://oss.sonatype.org/content/repositories/snapshots/")
+ maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
+ maven("https://maven.neoforged.net/releases")
+}
\ No newline at end of file
diff --git a/build-logic/src/main/kotlin/geyser.modrinth-uploading-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.modrinth-uploading-conventions.gradle.kts
new file mode 100644
index 000000000..a4a8cd7d6
--- /dev/null
+++ b/build-logic/src/main/kotlin/geyser.modrinth-uploading-conventions.gradle.kts
@@ -0,0 +1,18 @@
+plugins {
+ id("com.modrinth.minotaur")
+}
+
+// Ensure that the readme is synched
+tasks.modrinth.get().dependsOn(tasks.modrinthSyncBody)
+
+modrinth {
+ token.set(System.getenv("MODRINTH_TOKEN") ?: "") // Even though this is the default value, apparently this prevents GitHub Actions caching the token?
+ projectId.set("geyser")
+ versionNumber.set(project.version as String + "-" + System.getenv("BUILD_NUMBER"))
+ versionType.set("beta")
+ changelog.set("A changelog can be found at https://github.com/GeyserMC/Geyser/commits")
+ gameVersions.add(libs.minecraft.get().version as String)
+ failSilently.set(true)
+
+ syncBodyFrom.set(rootProject.file("README.md").readText())
+}
\ No newline at end of file
diff --git a/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts
index 036ee803c..eca587721 100644
--- a/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts
+++ b/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts
@@ -7,3 +7,9 @@ indra {
publishSnapshotsTo("geysermc", "https://repo.opencollab.dev/maven-snapshots")
publishReleasesTo("geysermc", "https://repo.opencollab.dev/maven-releases")
}
+
+publishing {
+ // skip shadow jar from publishing. Workaround for https://github.com/johnrengelman/shadow/issues/651
+ val javaComponent = project.components["java"] as AdhocComponentWithVariants
+ javaComponent.withVariantsFromConfiguration(configurations["shadowRuntimeElements"]) { skip() }
+}
\ No newline at end of file
diff --git a/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts
index dde85c33a..c160e5ec6 100644
--- a/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts
+++ b/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts
@@ -7,7 +7,6 @@ plugins {
tasks {
named("jar") {
- archiveClassifier.set("unshaded")
from(project.rootProject.file("LICENSE"))
}
val shadowJar = named("shadowJar") {
diff --git a/build.gradle.kts b/build.gradle.kts
index a72b8a484..dfbf9837f 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,9 +1,9 @@
plugins {
`java-library`
// Ensure AP works in eclipse (no effect on other IDEs)
- `eclipse`
+ eclipse
id("geyser.build-logic")
- id("io.freefair.lombok") version "6.3.0" apply false
+ alias(libs.plugins.lombok) apply false
}
allprojects {
@@ -12,17 +12,25 @@ allprojects {
description = properties["description"] as String
}
-java {
- toolchain {
- languageVersion.set(JavaLanguageVersion.of(17))
- }
-}
-
-val platforms = setOf(
- projects.fabric,
+val basePlatforms = setOf(
projects.bungeecord,
projects.spigot,
projects.standalone,
+ projects.velocity,
+ projects.viaproxy
+).map { it.dependencyProject }
+
+val moddedPlatforms = setOf(
+ projects.fabric,
+ projects.neoforge,
+ projects.mod
+).map { it.dependencyProject }
+
+val modrinthPlatforms = setOf(
+ projects.bungeecord,
+ projects.fabric,
+ projects.neoforge,
+ projects.spigot,
projects.velocity
).map { it.dependencyProject }
@@ -34,7 +42,14 @@ subprojects {
}
when (this) {
- in platforms -> plugins.apply("geyser.platform-conventions")
+ in basePlatforms -> plugins.apply("geyser.platform-conventions")
+ in moddedPlatforms -> plugins.apply("geyser.modded-conventions")
else -> plugins.apply("geyser.base-conventions")
}
-}
+
+ // Not combined with platform-conventions as that also contains
+ // platforms which we cant publish to modrinth
+ if (modrinthPlatforms.contains(this)) {
+ plugins.apply("geyser.modrinth-uploading-conventions")
+ }
+}
\ No newline at end of file
diff --git a/core/build.gradle.kts b/core/build.gradle.kts
index f67b652be..a27c4fc89 100644
--- a/core/build.gradle.kts
+++ b/core/build.gradle.kts
@@ -1,12 +1,15 @@
import net.kyori.blossom.BlossomExtension
plugins {
- id("net.kyori.blossom")
- id("net.kyori.indra.git")
+ alias(libs.plugins.blossom)
id("geyser.publish-conventions")
}
dependencies {
+ constraints {
+ implementation(libs.raknet) // Ensure protocol does not override the RakNet version
+ }
+
api(projects.common)
api(projects.api)
@@ -21,7 +24,6 @@ dependencies {
implementation(libs.websocket)
api(libs.bundles.protocol)
- implementation(libs.blockstateupdater)
api(libs.mcauthlib)
api(libs.mcprotocollib) {
@@ -44,6 +46,8 @@ dependencies {
implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-x86_64" } }
implementation(libs.netty.transport.native.epoll) { artifact { classifier = "linux-aarch_64" } }
implementation(libs.netty.transport.native.kqueue) { artifact { classifier = "osx-x86_64" } }
+ implementation(libs.netty.transport.native.io.uring) { artifact { classifier = "linux-x86_64" } }
+ implementation(libs.netty.transport.native.io.uring) { artifact { classifier = "linux-aarch_64" } }
// Adventure text serialization
api(libs.bundles.adventure)
@@ -63,11 +67,6 @@ dependencies {
api(libs.events)
}
-configurations.api {
- // This is still experimental - additionally, it could only really benefit standalone
- exclude(group = "io.netty.incubator", module = "netty-incubator-transport-native-io_uring")
-}
-
tasks.processResources {
// This is solely for backwards compatibility for other programs that used this file before the switch to gradle.
// It used to be generated by the maven Git-Commit-Id-Plugin
@@ -98,7 +97,7 @@ configure {
}
fun Project.buildNumber(): Int =
- (System.getenv("GITHUB_RUN_NUMBER") ?: jenkinsBuildNumber())?.let { Integer.parseInt(it) } ?: -1
+ (System.getenv("BUILD_NUMBER"))?.let { Integer.parseInt(it) } ?: -1
inner class GitInfo {
val branch: String
@@ -131,5 +130,18 @@ inner class GitInfo {
}
}
-// todo remove this when we're not using Jenkins anymore
-fun jenkinsBuildNumber(): String? = System.getenv("BUILD_NUMBER")
+// Manual task to download the bedrock data files from the CloudburstMC/Data repository
+// Invoke with ./gradlew :core:downloadBedrockData --suffix=1_20_70
+// Set suffix to the current Bedrock version
+tasks.register("downloadBedrockData") {
+ urls = listOf(
+ "https://raw.githubusercontent.com/CloudburstMC/Data/master/entity_identifiers.dat",
+ "https://raw.githubusercontent.com/CloudburstMC/Data/master/biome_definitions.dat",
+ "https://raw.githubusercontent.com/CloudburstMC/Data/master/block_palette.nbt",
+ "https://raw.githubusercontent.com/CloudburstMC/Data/master/creative_items.json",
+ "https://raw.githubusercontent.com/CloudburstMC/Data/master/runtime_item_states.json"
+ )
+ suffixedFiles = listOf("block_palette.nbt", "creative_items.json", "runtime_item_states.json")
+
+ destinationDir = "$projectDir/src/main/resources/bedrock"
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java
index f87acc2d4..cc31de9c5 100644
--- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java
+++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java
@@ -29,7 +29,6 @@ import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.github.steveice10.packetlib.tcp.TcpSession;
import io.netty.channel.epoll.Epoll;
import io.netty.util.NettyRuntime;
import io.netty.util.concurrent.DefaultThreadFactory;
@@ -56,11 +55,7 @@ import org.geysermc.geyser.api.GeyserApi;
import org.geysermc.geyser.api.command.CommandSource;
import org.geysermc.geyser.api.event.EventBus;
import org.geysermc.geyser.api.event.EventRegistrar;
-import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent;
-import org.geysermc.geyser.api.event.lifecycle.GeyserPostReloadEvent;
-import org.geysermc.geyser.api.event.lifecycle.GeyserPreInitializeEvent;
-import org.geysermc.geyser.api.event.lifecycle.GeyserPreReloadEvent;
-import org.geysermc.geyser.api.event.lifecycle.GeyserShutdownEvent;
+import org.geysermc.geyser.api.event.lifecycle.*;
import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.api.network.BedrockListener;
import org.geysermc.geyser.api.network.RemoteServer;
@@ -84,19 +79,15 @@ import org.geysermc.geyser.scoreboard.ScoreboardUpdater;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.PendingMicrosoftAuthentication;
import org.geysermc.geyser.session.SessionManager;
+import org.geysermc.geyser.session.cache.RegistryCache;
import org.geysermc.geyser.skin.FloodgateSkinUploader;
import org.geysermc.geyser.skin.ProvidedSkins;
import org.geysermc.geyser.skin.SkinProvider;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.translator.text.MessageTranslator;
-import org.geysermc.geyser.util.AssetUtils;
-import org.geysermc.geyser.util.CooldownUtils;
-import org.geysermc.geyser.util.DimensionUtils;
-import org.geysermc.geyser.util.Metrics;
-import org.geysermc.geyser.util.NewsHandler;
-import org.geysermc.geyser.util.VersionCheckUtils;
-import org.geysermc.geyser.util.WebUtils;
+import org.geysermc.geyser.util.*;
+import org.geysermc.mcprotocollib.network.tcp.TcpSession;
import java.io.File;
import java.io.FileWriter;
@@ -107,14 +98,7 @@ import java.net.UnknownHostException;
import java.nio.file.Path;
import java.security.Key;
import java.text.DecimalFormat;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-import java.util.UUID;
+import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
@@ -187,6 +171,12 @@ public class GeyserImpl implements GeyserApi {
*/
private volatile boolean isReloading;
+ /**
+ * Determines if Geyser is currently enabled. This is used to determine if {@link #disable()} should be called during {@link #shutdown()}.
+ */
+ @Setter
+ private boolean isEnabled;
+
private GeyserImpl(PlatformType platformType, GeyserBootstrap bootstrap) {
instance = this;
@@ -224,6 +214,8 @@ public class GeyserImpl implements GeyserApi {
Registries.init();
BlockRegistries.init();
+ RegistryCache.init();
+
/* Initialize translators */
EntityDefinitions.init();
MessageTranslator.init();
@@ -233,6 +225,7 @@ public class GeyserImpl implements GeyserApi {
if (ex != null) {
return;
}
+
MinecraftLocale.ensureEN_US();
String locale = GeyserLocale.getDefaultLocale();
if (!"en_us".equals(locale)) {
@@ -362,15 +355,17 @@ public class GeyserImpl implements GeyserApi {
logger.info("Broadcast port set from system property: " + parsedPort);
}
- boolean floodgatePresent = bootstrap.testFloodgatePluginPresent();
- if (config.getRemote().authType() == AuthType.FLOODGATE && !floodgatePresent) {
- logger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " "
- + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
- return;
- } else if (config.isAutoconfiguredRemote() && floodgatePresent) {
- // Floodgate installed means that the user wants Floodgate authentication
- logger.debug("Auto-setting to Floodgate authentication.");
- config.getRemote().setAuthType(AuthType.FLOODGATE);
+ if (platformType != PlatformType.VIAPROXY) {
+ boolean floodgatePresent = bootstrap.testFloodgatePluginPresent();
+ if (config.getRemote().authType() == AuthType.FLOODGATE && !floodgatePresent) {
+ logger.severe(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " "
+ + GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.disabling"));
+ return;
+ } else if (config.isAutoconfiguredRemote() && floodgatePresent) {
+ // Floodgate installed means that the user wants Floodgate authentication
+ logger.debug("Auto-setting to Floodgate authentication.");
+ config.getRemote().setAuthType(AuthType.FLOODGATE);
+ }
}
}
@@ -655,14 +650,18 @@ public class GeyserImpl implements GeyserApi {
this.erosionUnixListener.close();
}
+ // todo check
+ //Registries.RESOURCE_PACKS.get().clear();
ResourcePackLoader.clear();
- bootstrap.getGeyserLogger().info(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.done"));
+ this.setEnabled(false);
}
public void shutdown() {
shuttingDown = true;
- this.disable();
+ if (isEnabled) {
+ this.disable();
+ }
this.commandManager().getCommands().clear();
// Disable extensions, fire the shutdown event
@@ -774,6 +773,7 @@ public class GeyserImpl implements GeyserApi {
return 0;
}
+ //noinspection DataFlowIssue
return Integer.parseInt(BUILD_NUMBER);
}
@@ -795,6 +795,7 @@ public class GeyserImpl implements GeyserApi {
} else {
instance.initialize();
}
+ instance.setEnabled(true);
}
public GeyserLogger getLogger() {
diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java
index 1ff12dea3..5952ea00d 100644
--- a/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java
+++ b/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java
@@ -25,12 +25,12 @@
package org.geysermc.geyser.command.defaults;
-import com.github.steveice10.mc.protocol.data.game.ClientCommand;
-import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.command.GeyserCommand;
import org.geysermc.geyser.command.GeyserCommandSource;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.ClientCommand;
+import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket;
public class StatisticsCommand extends GeyserCommand {
diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java
index 6f05221e2..fb66a002a 100644
--- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java
+++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -72,8 +72,10 @@ public interface GeyserConfiguration {
boolean isDebugMode();
+ @Deprecated
boolean isAllowThirdPartyCapes();
+ @Deprecated
boolean isAllowThirdPartyEars();
String getShowCooldown();
diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java
index b0db58481..e4e82165f 100644
--- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java
+++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java
@@ -40,6 +40,7 @@ import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.network.CIDRMatcher;
import org.geysermc.geyser.text.AsteriskSerializer;
import org.geysermc.geyser.text.GeyserLocale;
+import org.geysermc.geyser.util.WebUtils;
import java.io.IOException;
import java.nio.file.Path;
@@ -93,7 +94,7 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
private boolean debugMode = false;
@JsonProperty("allow-third-party-capes")
- private boolean allowThirdPartyCapes = true;
+ private boolean allowThirdPartyCapes = false;
@JsonProperty("show-cooldown")
private String showCooldown = "title";
@@ -237,7 +238,18 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
List matchers = this.whitelistedIPsMatchers;
if (matchers == null) {
synchronized (this) {
- this.whitelistedIPsMatchers = matchers = proxyProtocolWhitelistedIPs.stream()
+ // Check if proxyProtocolWhitelistedIPs contains URLs we need to fetch and parse by line
+ List whitelistedCIDRs = new ArrayList<>();
+ for (String ip: proxyProtocolWhitelistedIPs) {
+ if (!ip.startsWith("http")) {
+ whitelistedCIDRs.add(ip);
+ continue;
+ }
+
+ WebUtils.getLineStream(ip).forEach(whitelistedCIDRs::add);
+ }
+
+ this.whitelistedIPsMatchers = matchers = whitelistedCIDRs.stream()
.map(CIDRMatcher::new)
.collect(Collectors.toList());
}
diff --git a/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java
index 6a56c536a..7851fadfd 100644
--- a/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java
+++ b/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java
@@ -27,8 +27,8 @@ package org.geysermc.geyser.dump;
import lombok.AllArgsConstructor;
import lombok.Getter;
-import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.GeyserImpl;
+import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.text.AsteriskSerializer;
import java.util.List;
diff --git a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java
index 818607314..6989dc10a 100644
--- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java
+++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java
@@ -56,12 +56,7 @@ import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Properties;
+import java.util.*;
import java.util.stream.Collectors;
@Getter
@@ -78,6 +73,7 @@ public class DumpInfo {
private final GeyserConfiguration config;
private final Floodgate floodgate;
private final Object2IntMap userPlatforms;
+ private final int connectionAttempts;
private final HashInfo hashInfo;
private final RamInfo ramInfo;
private LogsInfo logsInfo;
@@ -129,6 +125,8 @@ public class DumpInfo {
userPlatforms.put(device, userPlatforms.getOrDefault(device, 0) + 1);
}
+ this.connectionAttempts = GeyserImpl.getInstance().getGeyserServer().getConnectionAttempts();
+
this.bootstrapInfo = GeyserImpl.getInstance().getBootstrap().getDumpInfo();
this.flagsInfo = new FlagsInfo();
diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java
index 8b430d559..31aa7cc73 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java
@@ -25,14 +25,15 @@
package org.geysermc.geyser.entity;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
-import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.entity.factory.EntityFactory;
+import org.geysermc.geyser.entity.properties.GeyserEntityProperties;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.translator.entity.EntityMetadataTranslator;
@@ -49,10 +50,10 @@ import java.util.function.BiConsumer;
* @param the entity type this definition represents
*/
public record EntityDefinition(EntityFactory factory, EntityType entityType, String identifier,
- float width, float height, float offset, List> translators) {
+ float width, float height, float offset, GeyserEntityProperties registeredProperties, List> translators) {
public static Builder inherited(EntityFactory factory, EntityDefinition super T> parent) {
- return new Builder<>(factory, parent.entityType, parent.identifier, parent.width, parent.height, parent.offset, new ObjectArrayList<>(parent.translators));
+ return new Builder<>(factory, parent.entityType, parent.identifier, parent.width, parent.height, parent.offset, parent.registeredProperties, new ObjectArrayList<>(parent.translators));
}
public static Builder builder(EntityFactory factory) {
@@ -87,6 +88,7 @@ public record EntityDefinition(EntityFactory factory, Entit
private float width;
private float height;
private float offset = 0.00001f;
+ private GeyserEntityProperties registeredProperties;
private final List> translators;
private Builder(EntityFactory factory) {
@@ -94,13 +96,14 @@ public record EntityDefinition(EntityFactory factory, Entit
translators = new ObjectArrayList<>();
}
- public Builder(EntityFactory factory, EntityType type, String identifier, float width, float height, float offset, List> translators) {
+ public Builder(EntityFactory factory, EntityType type, String identifier, float width, float height, float offset, GeyserEntityProperties registeredProperties, List> translators) {
this.factory = factory;
this.type = type;
this.identifier = identifier;
this.width = width;
this.height = height;
this.offset = offset;
+ this.registeredProperties = registeredProperties;
this.translators = translators;
}
@@ -127,6 +130,11 @@ public record EntityDefinition(EntityFactory factory, Entit
return this;
}
+ public Builder properties(GeyserEntityProperties registeredProperties) {
+ this.registeredProperties = registeredProperties;
+ return this;
+ }
+
public >> Builder addTranslator(MetadataType type, BiConsumer translateFunction) {
translators.add(new EntityMetadataTranslator<>(type, translateFunction));
return this;
@@ -149,10 +157,13 @@ public record EntityDefinition(EntityFactory factory, Entit
if (identifier == null && type != null) {
identifier = "minecraft:" + type.name().toLowerCase(Locale.ROOT);
}
- EntityDefinition definition = new EntityDefinition<>(factory, type, identifier, width, height, offset, translators);
+ EntityDefinition definition = new EntityDefinition<>(factory, type, identifier, width, height, offset, registeredProperties, translators);
if (register && definition.entityType() != null) {
Registries.ENTITY_DEFINITIONS.get().putIfAbsent(definition.entityType(), definition);
Registries.JAVA_ENTITY_IDENTIFIERS.get().putIfAbsent("minecraft:" + type.name().toLowerCase(Locale.ROOT), definition);
+ if (definition.registeredProperties() != null) {
+ Registries.BEDROCK_ENTITY_PROPERTIES.get().add(definition.registeredProperties().toNbtMap(identifier));
+ }
}
return definition;
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java
index e9d49fbd8..1496f8a82 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java
@@ -25,12 +25,16 @@
package org.geysermc.geyser.entity;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
+import org.geysermc.geyser.entity.type.AbstractWindChargeEntity;
+import org.geysermc.geyser.entity.factory.EntityFactory;
+import org.geysermc.geyser.entity.type.living.monster.raid.RavagerEntity;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
+import org.geysermc.geyser.entity.properties.GeyserEntityProperties;
import org.geysermc.geyser.entity.type.*;
import org.geysermc.geyser.entity.type.living.*;
import org.geysermc.geyser.entity.type.living.animal.*;
@@ -53,13 +57,17 @@ import org.geysermc.geyser.translator.text.MessageTranslator;
public final class EntityDefinitions {
public static final EntityDefinition ALLAY;
public static final EntityDefinition AREA_EFFECT_CLOUD;
+ public static final EntityDefinition ARMADILLO;
public static final EntityDefinition ARMOR_STAND;
- public static final EntityDefinition ARROW;
+ public static final EntityDefinition ARROW;
public static final EntityDefinition AXOLOTL;
public static final EntityDefinition BAT;
public static final EntityDefinition BEE;
public static final EntityDefinition BLAZE;
public static final EntityDefinition BOAT;
+ public static final EntityDefinition BOGGED;
+ public static final EntityDefinition BREEZE;
+ public static final EntityDefinition BREEZE_WIND_CHARGE;
public static final EntityDefinition CAMEL;
public static final EntityDefinition CAT;
public static final EntityDefinition CAVE_SPIDER;
@@ -130,7 +138,7 @@ public final class EntityDefinitions {
public static final EntityDefinition POTION;
public static final EntityDefinition PUFFERFISH;
public static final EntityDefinition RABBIT;
- public static final EntityDefinition RAVAGER;
+ public static final EntityDefinition RAVAGER;
public static final EntityDefinition SALMON;
public static final EntityDefinition SHEEP;
public static final EntityDefinition SHULKER;
@@ -162,6 +170,7 @@ public final class EntityDefinitions {
public static final EntityDefinition VINDICATOR;
public static final EntityDefinition WANDERING_TRADER;
public static final EntityDefinition WARDEN;
+ public static final EntityDefinition WIND_CHARGE;
public static final EntityDefinition WITCH;
public static final EntityDefinition WITHER;
public static final EntityDefinition WITHER_SKELETON;
@@ -200,7 +209,6 @@ public final class EntityDefinitions {
.type(EntityType.AREA_EFFECT_CLOUD)
.height(0.5f).width(1.0f)
.addTranslator(MetadataType.FLOAT, AreaEffectCloudEntity::setRadius)
- .addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.EFFECT_COLOR, entityMetadata.getValue()))
.addTranslator(null) // Waiting
.addTranslator(MetadataType.PARTICLE, AreaEffectCloudEntity::setParticle)
.build();
@@ -233,7 +241,7 @@ public final class EntityDefinitions {
.addTranslator(MetadataType.BOOLEAN,
(enderCrystalEntity, entityMetadata) -> enderCrystalEntity.setFlag(EntityFlag.SHOW_BOTTOM, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) // There is a base located on the ender crystal
.build();
- EXPERIENCE_ORB = EntityDefinition.inherited(null, entityBase)
+ EXPERIENCE_ORB = EntityDefinition.inherited(ExpOrbEntity::new, entityBase)
.type(EntityType.EXPERIENCE_ORB)
.identifier("minecraft:xp_orb")
.build();
@@ -295,6 +303,7 @@ public final class EntityDefinitions {
TNT = EntityDefinition.inherited(TNTEntity::new, entityBase)
.type(EntityType.TNT)
.heightAndWidth(0.98f)
+ .offset(0.49f)
.addTranslator(MetadataType.INT, TNTEntity::setFuseLength)
.build();
@@ -372,14 +381,26 @@ public final class EntityDefinitions {
.heightAndWidth(0.25f)
.build();
+ EntityFactory windChargeSupplier = AbstractWindChargeEntity::new;
+ BREEZE_WIND_CHARGE = EntityDefinition.inherited(windChargeSupplier, entityBase)
+ .type(EntityType.BREEZE_WIND_CHARGE)
+ .identifier("minecraft:breeze_wind_charge_projectile")
+ .heightAndWidth(0.3125f)
+ .build();
+ WIND_CHARGE = EntityDefinition.inherited(windChargeSupplier, entityBase)
+ .type(EntityType.WIND_CHARGE)
+ .identifier("minecraft:wind_charge_projectile")
+ .heightAndWidth(0.3125f)
+ .build();
+
EntityDefinition abstractArrowBase = EntityDefinition.inherited(AbstractArrowEntity::new, entityBase)
.addTranslator(MetadataType.BYTE, AbstractArrowEntity::setArrowFlags)
.addTranslator(null) // "Piercing level"
.build();
- ARROW = EntityDefinition.inherited(TippedArrowEntity::new, abstractArrowBase)
+ ARROW = EntityDefinition.inherited(ArrowEntity::new, abstractArrowBase)
.type(EntityType.ARROW)
.heightAndWidth(0.25f)
- .addTranslator(MetadataType.INT, TippedArrowEntity::setPotionEffectColor)
+ .addTranslator(MetadataType.INT, ArrowEntity::setPotionEffectColor)
.build();
SPECTRAL_ARROW = EntityDefinition.inherited(abstractArrowBase.factory(), abstractArrowBase)
.type(EntityType.SPECTRAL_ARROW)
@@ -452,8 +473,7 @@ public final class EntityDefinitions {
EntityDefinition livingEntityBase = EntityDefinition.inherited(LivingEntity::new, entityBase)
.addTranslator(MetadataType.BYTE, LivingEntity::setLivingEntityFlags)
.addTranslator(MetadataType.FLOAT, LivingEntity::setHealth)
- .addTranslator(MetadataType.INT,
- (livingEntity, entityMetadata) -> livingEntity.getDirtyMetadata().put(EntityDataTypes.EFFECT_COLOR, entityMetadata.getValue()))
+ .addTranslator(MetadataType.PARTICLES, LivingEntity::setParticles)
.addTranslator(MetadataType.BOOLEAN,
(livingEntity, entityMetadata) -> livingEntity.getDirtyMetadata().put(EntityDataTypes.EFFECT_AMBIENCE, (byte) (((BooleanEntityMetadata) entityMetadata).getPrimitiveValue() ? 1 : 0)))
.addTranslator(null) // Arrow count
@@ -501,11 +521,20 @@ public final class EntityDefinitions {
.height(0.9f).width(0.5f)
.addTranslator(MetadataType.BYTE, BatEntity::setBatFlags)
.build();
+ BOGGED = EntityDefinition.inherited(BoggedEntity::new, mobEntityBase)
+ .type(EntityType.BOGGED)
+ .height(1.99f).width(0.6f)
+ .addTranslator(MetadataType.BOOLEAN, BoggedEntity::setSheared)
+ .build();
BLAZE = EntityDefinition.inherited(BlazeEntity::new, mobEntityBase)
.type(EntityType.BLAZE)
.height(1.8f).width(0.6f)
.addTranslator(MetadataType.BYTE, BlazeEntity::setBlazeFlags)
.build();
+ BREEZE = EntityDefinition.inherited(BreezeEntity::new, mobEntityBase)
+ .type(EntityType.BREEZE)
+ .height(1.77f).width(0.6f)
+ .build();
CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase)
.type(EntityType.CREEPER)
.height(1.7f).width(0.6f)
@@ -672,7 +701,7 @@ public final class EntityDefinitions {
SLIME = EntityDefinition.inherited(SlimeEntity::new, mobEntityBase)
.type(EntityType.SLIME)
.heightAndWidth(0.51f)
- .addTranslator(MetadataType.INT, SlimeEntity::setScale)
+ .addTranslator(MetadataType.INT, SlimeEntity::setSlimeScale)
.build();
MAGMA_CUBE = EntityDefinition.inherited(MagmaCubeEntity::new, SLIME)
.type(EntityType.MAGMA_CUBE)
@@ -745,9 +774,9 @@ public final class EntityDefinitions {
.type(EntityType.PILLAGER)
.height(1.8f).width(0.6f)
.offset(1.62f)
- .addTranslator(null) // Charging; doesn't have an equivalent on Bedrock //TODO check
+ .addTranslator(MetadataType.BOOLEAN, PillagerEntity::setChargingCrossbow)
.build();
- RAVAGER = EntityDefinition.inherited(raidParticipantEntityBase.factory(), raidParticipantEntityBase)
+ RAVAGER = EntityDefinition.inherited(RavagerEntity::new, raidParticipantEntityBase)
.type(EntityType.RAVAGER)
.height(1.9f).width(1.2f)
.build();
@@ -770,6 +799,20 @@ public final class EntityDefinitions {
// Extends ageable
{
+ ARMADILLO = EntityDefinition.inherited(ArmadilloEntity::new, ageableEntityBase)
+ .type(EntityType.ARMADILLO)
+ .height(0.65f).width(0.7f)
+ .properties(new GeyserEntityProperties.Builder()
+ .addEnum(
+ "minecraft:armadillo_state",
+ "unrolled",
+ "rolled_up",
+ "rolled_up_peeking",
+ "rolled_up_relaxing",
+ "rolled_up_unrolling")
+ .build())
+ .addTranslator(MetadataType.ARMADILLO_STATE, ArmadilloEntity::setArmadilloState)
+ .build();
AXOLOTL = EntityDefinition.inherited(AxolotlEntity::new, ageableEntityBase)
.type(EntityType.AXOLOTL)
.height(0.42f).width(0.7f)
@@ -780,6 +823,9 @@ public final class EntityDefinitions {
BEE = EntityDefinition.inherited(BeeEntity::new, ageableEntityBase)
.type(EntityType.BEE)
.heightAndWidth(0.6f)
+ .properties(new GeyserEntityProperties.Builder()
+ .addBoolean("minecraft:has_nectar")
+ .build())
.addTranslator(MetadataType.BYTE, BeeEntity::setBeeFlags)
.addTranslator(MetadataType.INT, BeeEntity::setAngerTime)
.build();
@@ -937,8 +983,7 @@ public final class EntityDefinitions {
LLAMA = EntityDefinition.inherited(LlamaEntity::new, chestedHorseEntityBase)
.type(EntityType.LLAMA)
.height(1.87f).width(0.9f)
- .addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.STRENGTH, entityMetadata.getValue()))
- .addTranslator(MetadataType.INT, LlamaEntity::setCarpetedColor)
+ .addTranslator(MetadataType.INT, LlamaEntity::setStrength)
.addTranslator(MetadataType.INT, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityDataTypes.VARIANT, entityMetadata.getValue()))
.build();
TRADER_LLAMA = EntityDefinition.inherited(TraderLlamaEntity::new, LLAMA)
@@ -947,7 +992,7 @@ public final class EntityDefinitions {
.build();
}
- EntityDefinition tameableEntityBase = EntityDefinition.inherited(TameableEntity::new, ageableEntityBase)
+ EntityDefinition tameableEntityBase = EntityDefinition.inherited(null, ageableEntityBase) // No factory, is abstract
.addTranslator(MetadataType.BYTE, TameableEntity::setTameableFlags)
.addTranslator(MetadataType.OPTIONAL_UUID, TameableEntity::setOwner)
.build();
@@ -971,6 +1016,7 @@ public final class EntityDefinitions {
.addTranslator(MetadataType.BOOLEAN, (wolfEntity, entityMetadata) -> wolfEntity.setFlag(EntityFlag.INTERESTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue()))
.addTranslator(MetadataType.INT, WolfEntity::setCollarColor)
.addTranslator(MetadataType.INT, WolfEntity::setWolfAngerTime)
+ .addTranslator(MetadataType.WOLF_VARIANT, WolfEntity::setWolfVariant)
.build();
// As of 1.18 these don't track entity data at all
diff --git a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java
index 234c1afe9..f19912a8c 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java
@@ -49,9 +49,10 @@ public enum GeyserAttributeType {
ATTACK_KNOCKBACK("minecraft:generic.attack_knockback", null, 1.5f, Float.MAX_VALUE, 0f),
ATTACK_SPEED("minecraft:generic.attack_speed", null, 0f, 1024f, 4f),
MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f),
+ SCALE("minecraft:generic.scale", null, 0.0625f, 16f, 1f), // Unused. Do we need this?
// Bedrock Attributes
- ABSORPTION(null, "minecraft:absorption", 0f, Float.MAX_VALUE, 0f),
+ ABSORPTION(null, "minecraft:absorption", 0f, 1024f, 0f),
EXHAUSTION(null, "minecraft:player.exhaustion", 0f, 5f, 0f),
EXPERIENCE(null, "minecraft:player.experience", 0f, 1f, 0f),
EXPERIENCE_LEVEL(null, "minecraft:player.level", 0f, 24791.00f, 0f),
@@ -66,6 +67,10 @@ public enum GeyserAttributeType {
private final float maximum;
private final float defaultValue;
+ public AttributeData getAttribute() {
+ return getAttribute(defaultValue);
+ }
+
public AttributeData getAttribute(float value) {
return getAttribute(value, maximum);
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java b/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java
new file mode 100644
index 000000000..1729b0583
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.entity.properties;
+
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.cloudburstmc.nbt.NbtMap;
+import org.cloudburstmc.nbt.NbtMapBuilder;
+import org.cloudburstmc.nbt.NbtType;
+import org.geysermc.geyser.entity.properties.type.BooleanProperty;
+import org.geysermc.geyser.entity.properties.type.EnumProperty;
+import org.geysermc.geyser.entity.properties.type.FloatProperty;
+import org.geysermc.geyser.entity.properties.type.IntProperty;
+import org.geysermc.geyser.entity.properties.type.PropertyType;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@EqualsAndHashCode
+@ToString
+public class GeyserEntityProperties {
+ private final ObjectArrayList properties;
+ private final Object2IntMap propertyIndices;
+
+ private GeyserEntityProperties(ObjectArrayList properties,
+ Object2IntMap propertyIndices) {
+ this.properties = properties;
+ this.propertyIndices = propertyIndices;
+ }
+
+ public NbtMap toNbtMap(String entityType) {
+ NbtMapBuilder mapBuilder = NbtMap.builder();
+ List nbtProperties = new ArrayList<>();
+
+ for (PropertyType property : properties) {
+ nbtProperties.add(property.nbtMap());
+ }
+ mapBuilder.putList("properties", NbtType.COMPOUND, nbtProperties);
+
+ return mapBuilder.putString("type", entityType).build();
+ }
+
+ public @NonNull List getProperties() {
+ return properties;
+ }
+
+ public int getPropertyIndex(String name) {
+ return propertyIndices.getOrDefault(name, -1);
+ }
+
+ public static class Builder {
+ private final ObjectArrayList properties = new ObjectArrayList<>();
+ private final Object2IntMap propertyIndices = new Object2IntOpenHashMap<>();
+
+ public Builder addInt(@NonNull String name, int min, int max) {
+ if (propertyIndices.containsKey(name)) {
+ throw new IllegalArgumentException(
+ "Property with name " + name + " already exists on builder!");
+ }
+ PropertyType property = new IntProperty(name, min, max);
+ this.properties.add(property);
+ propertyIndices.put(name, properties.size() - 1);
+ return this;
+ }
+
+ public Builder addInt(@NonNull String name) {
+ if (propertyIndices.containsKey(name)) {
+ throw new IllegalArgumentException(
+ "Property with name " + name + " already exists on builder!");
+ }
+ PropertyType property = new IntProperty(name, Integer.MIN_VALUE, Integer.MAX_VALUE);
+ this.properties.add(property);
+ propertyIndices.put(name, properties.size() - 1);
+ return this;
+ }
+
+ public Builder addFloat(@NonNull String name, float min, float max) {
+ if (propertyIndices.containsKey(name)) {
+ throw new IllegalArgumentException(
+ "Property with name " + name + " already exists on builder!");
+ }
+ PropertyType property = new FloatProperty(name, min, max);
+ this.properties.add(property);
+ propertyIndices.put(name, properties.size() - 1);
+ return this;
+ }
+
+ public Builder addFloat(@NonNull String name) {
+ if (propertyIndices.containsKey(name)) {
+ throw new IllegalArgumentException(
+ "Property with name " + name + " already exists on builder!");
+ }
+ PropertyType property = new FloatProperty(name, Float.MIN_NORMAL, Float.MAX_VALUE);
+ this.properties.add(property);
+ propertyIndices.put(name, properties.size() - 1);
+ return this;
+ }
+
+ public Builder addBoolean(@NonNull String name) {
+ if (propertyIndices.containsKey(name)) {
+ throw new IllegalArgumentException(
+ "Property with name " + name + " already exists on builder!");
+ }
+ PropertyType property = new BooleanProperty(name);
+ this.properties.add(property);
+ propertyIndices.put(name, properties.size() - 1);
+ return this;
+ }
+
+ public Builder addEnum(@NonNull String name, List values) {
+ if (propertyIndices.containsKey(name)) {
+ throw new IllegalArgumentException(
+ "Property with name " + name + " already exists on builder!");
+ }
+ PropertyType property = new EnumProperty(name, values);
+ this.properties.add(property);
+ propertyIndices.put(name, properties.size() - 1);
+ return this;
+ }
+
+ public Builder addEnum(@NonNull String name, String... values) {
+ if (propertyIndices.containsKey(name)) {
+ throw new IllegalArgumentException(
+ "Property with name " + name + " already exists on builder!");
+ }
+ List valuesList = Arrays.asList(values); // Convert array to list
+ PropertyType property = new EnumProperty(name, valuesList);
+ this.properties.add(property);
+ propertyIndices.put(name, properties.size() - 1);
+ return this;
+ }
+
+ public GeyserEntityProperties build() {
+ return new GeyserEntityProperties(properties, propertyIndices);
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityPropertyManager.java b/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityPropertyManager.java
new file mode 100644
index 000000000..29026b172
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityPropertyManager.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.entity.properties;
+
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
+import org.cloudburstmc.protocol.bedrock.data.entity.FloatEntityProperty;
+import org.cloudburstmc.protocol.bedrock.data.entity.IntEntityProperty;
+import org.geysermc.geyser.entity.properties.type.EnumProperty;
+import org.geysermc.geyser.entity.properties.type.PropertyType;
+
+import java.util.List;
+
+public class GeyserEntityPropertyManager {
+
+ private final GeyserEntityProperties properties;
+
+ private final ObjectArrayList intEntityProperties = new ObjectArrayList<>();
+ private final ObjectArrayList floatEntityProperties = new ObjectArrayList<>();
+
+ public GeyserEntityPropertyManager(GeyserEntityProperties properties) {
+ this.properties = properties;
+ }
+
+ public void add(String propertyName, int value) {
+ int index = properties.getPropertyIndex(propertyName);
+ intEntityProperties.add(new IntEntityProperty(index, value));
+ }
+
+ public void add(String propertyName, boolean value) {
+ int index = properties.getPropertyIndex(propertyName);
+ intEntityProperties.add(new IntEntityProperty(index, value ? 1 : 0));
+ }
+
+ public void add(String propertyName, String value) {
+ int index = properties.getPropertyIndex(propertyName);
+ PropertyType property = properties.getProperties().get(index);
+ int enumIndex = ((EnumProperty) property).getIndex(value);
+ intEntityProperties.add(new IntEntityProperty(index, enumIndex));
+ }
+
+ public void add(String propertyName, float value) {
+ int index = properties.getPropertyIndex(propertyName);
+ floatEntityProperties.add(new FloatEntityProperty(index, value));
+ }
+
+ public boolean hasFloatProperties() {
+ return !this.floatEntityProperties.isEmpty();
+ }
+
+ public boolean hasIntProperties() {
+ return !this.intEntityProperties.isEmpty();
+ }
+
+ public boolean hasProperties() {
+ return hasFloatProperties() || hasIntProperties();
+ }
+
+ public ObjectArrayList intProperties() {
+ return this.intEntityProperties;
+ }
+
+ public void applyIntProperties(List properties) {
+ properties.addAll(intEntityProperties);
+ intEntityProperties.clear();
+ }
+
+ public ObjectArrayList floatProperties() {
+ return this.floatEntityProperties;
+ }
+
+ public void applyFloatProperties(List properties) {
+ properties.addAll(floatEntityProperties);
+ floatEntityProperties.clear();
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion630_649.java b/core/src/main/java/org/geysermc/geyser/entity/properties/type/BooleanProperty.java
similarity index 71%
rename from core/src/main/java/org/geysermc/geyser/registry/populator/Conversion630_649.java
rename to core/src/main/java/org/geysermc/geyser/entity/properties/type/BooleanProperty.java
index ed66322ff..6fc64ad4b 100644
--- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion630_649.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/properties/type/BooleanProperty.java
@@ -23,18 +23,22 @@
* @link https://github.com/GeyserMC/Geyser
*/
-package org.geysermc.geyser.registry.populator;
+package org.geysermc.geyser.entity.properties.type;
-import org.geysermc.geyser.item.type.Item;
-import org.geysermc.geyser.registry.type.GeyserMappingItem;
+import org.cloudburstmc.nbt.NbtMap;
+public class BooleanProperty implements PropertyType {
+ private final String name;
-public class Conversion630_649 {
-
- static GeyserMappingItem remapItem(@SuppressWarnings("unused") Item item, GeyserMappingItem mapping) {
- if (mapping.getBedrockIdentifier().equalsIgnoreCase("minecraft:scute")) {
- return mapping.withBedrockIdentifier("minecraft:turtle_scute");
- }
- return mapping;
+ public BooleanProperty(String name) {
+ this.name = name;
}
-}
+
+ @Override
+ public NbtMap nbtMap() {
+ return NbtMap.builder()
+ .putString("name", name)
+ .putInt("type", 2)
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/type/EnumProperty.java b/core/src/main/java/org/geysermc/geyser/entity/properties/type/EnumProperty.java
new file mode 100644
index 000000000..05e12ba61
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/entity/properties/type/EnumProperty.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.entity.properties.type;
+
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
+import org.cloudburstmc.nbt.NbtMap;
+import org.cloudburstmc.nbt.NbtType;
+
+import java.util.List;
+
+public class EnumProperty implements PropertyType {
+ private final String name;
+ private final List values;
+ private final Object2IntMap valueIndexMap;
+
+ public EnumProperty(String name, List values) {
+ this.name = name;
+ this.values = values;
+ this.valueIndexMap = new Object2IntOpenHashMap<>(values.size());
+ for (int i = 0; i < values.size(); i++) {
+ valueIndexMap.put(values.get(i), i);
+ }
+ }
+
+ @Override
+ public NbtMap nbtMap() {
+ return NbtMap.builder()
+ .putString("name", name)
+ .putList("enum", NbtType.STRING, values)
+ .putInt("type", 3)
+ .build();
+ }
+
+ public int getIndex(String value) {
+ return valueIndexMap.getOrDefault(value, -1);
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/type/FloatProperty.java b/core/src/main/java/org/geysermc/geyser/entity/properties/type/FloatProperty.java
new file mode 100644
index 000000000..8b808ebc3
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/entity/properties/type/FloatProperty.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.entity.properties.type;
+
+import org.cloudburstmc.nbt.NbtMap;
+
+public class FloatProperty implements PropertyType {
+ private final String name;
+ private final float max;
+ private final float min;
+
+ public FloatProperty(String name, float min, float max) {
+ this.name = name;
+ this.max = max;
+ this.min = min;
+ }
+
+ @Override
+ public NbtMap nbtMap() {
+ return NbtMap.builder()
+ .putString("name", name)
+ .putFloat("max", max)
+ .putFloat("min", min)
+ .putInt("type", 1)
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/geysermc/geyser/level/block/DoubleChestValue.java b/core/src/main/java/org/geysermc/geyser/entity/properties/type/IntProperty.java
similarity index 63%
rename from core/src/main/java/org/geysermc/geyser/level/block/DoubleChestValue.java
rename to core/src/main/java/org/geysermc/geyser/entity/properties/type/IntProperty.java
index 97c861df7..9e38db7c7 100644
--- a/core/src/main/java/org/geysermc/geyser/level/block/DoubleChestValue.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/properties/type/IntProperty.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -23,18 +23,28 @@
* @link https://github.com/GeyserMC/Geyser
*/
-package org.geysermc.geyser.level.block;
+package org.geysermc.geyser.entity.properties.type;
-/**
- * This stores all values of double chests that are part of the Java block state.
- *
- * @param isFacingEast If true, then chest is facing east/west; if false, south/north
- * @param isDirectionPositive If true, direction is positive (east/south); if false, direction is negative (west/north)
- * @param isLeft If true, chest is the left of a pair; if false, chest is the right of a pair.
- */
-public record DoubleChestValue(
- boolean isFacingEast,
- boolean isDirectionPositive,
- boolean isLeft) {
+import org.cloudburstmc.nbt.NbtMap;
-}
+public class IntProperty implements PropertyType {
+ private final String name;
+ private final int max;
+ private final int min;
+
+ public IntProperty(String name, int min, int max) {
+ this.name = name;
+ this.max = max;
+ this.min = min;
+ }
+
+ @Override
+ public NbtMap nbtMap() {
+ return NbtMap.builder()
+ .putString("name", name)
+ .putInt("max", max)
+ .putInt("min", min)
+ .putInt("type", 0)
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/type/PropertyType.java b/core/src/main/java/org/geysermc/geyser/entity/properties/type/PropertyType.java
new file mode 100644
index 000000000..a64d7246a
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/entity/properties/type/PropertyType.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.entity.properties.type;
+
+import org.cloudburstmc.nbt.NbtMap;
+
+public interface PropertyType {
+ NbtMap nbtMap();
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/AbstractArrowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/AbstractArrowEntity.java
index 6828d1020..1cc746d7a 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/AbstractArrowEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/AbstractArrowEntity.java
@@ -25,8 +25,8 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/AbstractWindChargeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/AbstractWindChargeEntity.java
new file mode 100644
index 000000000..5678c3af4
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/AbstractWindChargeEntity.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.entity.type;
+
+import org.cloudburstmc.math.vector.Vector3f;
+import org.geysermc.geyser.entity.EntityDefinition;
+import org.geysermc.geyser.session.GeyserSession;
+
+import java.util.UUID;
+
+/**
+ * Note that, as of 1.21, a wind charge entity does not actually implement the thrown item. We're just reusing
+ * the "hide until far away" aspect.
+ */
+public class AbstractWindChargeEntity extends ThrowableItemEntity {
+ public AbstractWindChargeEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
+ super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
+ }
+
+ @Override
+ public void tick() {
+ super.tick();
+ }
+
+ @Override
+ protected float getDrag() {
+ // Always, even in water. As of 1.21.
+ return 1f;
+ }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java
index 84dfae468..165495506 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java
@@ -25,9 +25,6 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.level.particle.Particle;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.ParticleType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
@@ -35,6 +32,11 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.util.MathUtils;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffectParticleData;
+import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle;
import java.util.UUID;
@@ -51,7 +53,7 @@ public class AreaEffectCloudEntity extends Entity {
dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_DURATION, Integer.MAX_VALUE);
// This disabled client side shrink of the cloud
- dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_RADIUS, 0.0f);
+ dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_RADIUS, 3.0f);
dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_CHANGE_RATE, Float.MIN_VALUE);
dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_CHANGE_ON_PICKUP, Float.MIN_VALUE);
@@ -60,7 +62,7 @@ public class AreaEffectCloudEntity extends Entity {
public void setRadius(FloatEntityMetadata entityMetadata) {
// Anything less than 0.5 will cause the cloud to despawn
- float value = Math.max(entityMetadata.getPrimitiveValue(), 0.5f);
+ float value = MathUtils.clamp(entityMetadata.getPrimitiveValue(), 0.5f, 32.0f);
dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_RADIUS, value);
dirtyMetadata.put(EntityDataTypes.WIDTH, 2.0f * value);
}
@@ -69,5 +71,9 @@ public class AreaEffectCloudEntity extends Entity {
Particle particle = entityMetadata.getValue();
Registries.PARTICLES.map(particle.getType(), p -> p.levelEventType() instanceof ParticleType particleType ? particleType : null).ifPresent(type ->
dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_PARTICLE, type));
+
+ if (particle.getData() instanceof EntityEffectParticleData effectParticleData) {
+ dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, effectParticleData.getColor());
+ }
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TippedArrowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ArrowEntity.java
similarity index 68%
rename from core/src/main/java/org/geysermc/geyser/entity/type/TippedArrowEntity.java
rename to core/src/main/java/org/geysermc/geyser/entity/type/ArrowEntity.java
index 856c4cc66..ba1241434 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/TippedArrowEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/ArrowEntity.java
@@ -25,21 +25,18 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
-import org.geysermc.geyser.inventory.item.TippedArrowPotion;
+import org.geysermc.geyser.inventory.item.Potion;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
-/**
- * Internally this is known as TippedArrowEntity but is used with tipped arrows and normal arrows
- */
-public class TippedArrowEntity extends AbstractArrowEntity {
+public class ArrowEntity extends AbstractArrowEntity {
- public TippedArrowEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
+ public ArrowEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
@@ -49,12 +46,7 @@ public class TippedArrowEntity extends AbstractArrowEntity {
if (potionColor == -1) {
dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, (byte) 0);
} else {
- TippedArrowPotion potion = TippedArrowPotion.getByJavaColor(potionColor);
- if (potion != null && potion.getJavaColor() != -1) {
- dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, (byte) potion.getBedrockId());
- } else {
- dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, (byte) 0);
- }
+ dirtyMetadata.put(EntityDataTypes.CUSTOM_DISPLAY, Potion.toTippedArrowId(potionColor));
}
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java
index 5527e773a..47ae6777a 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java
@@ -25,24 +25,23 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
+import lombok.Getter;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket;
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
-import lombok.Getter;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
-import java.util.concurrent.TimeUnit;
-public class BoatEntity extends Entity {
+public class BoatEntity extends Entity implements Leashable, Tickable {
/**
* Required when IS_BUOYANT is sent in order for boats to work in the water.
@@ -58,6 +57,7 @@ public class BoatEntity extends Entity {
private float paddleTimeLeft;
private boolean isPaddlingRight;
private float paddleTimeRight;
+ private boolean doTick;
/**
* Saved for using the "pick" functionality on a boat.
@@ -65,6 +65,8 @@ public class BoatEntity extends Entity {
@Getter
private int variant;
+ private long leashHolderBedrockId = -1;
+
// Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it
private final float ROWING_SPEED = 0.1f;
@@ -133,40 +135,32 @@ public class BoatEntity extends Entity {
public void setPaddlingLeft(BooleanEntityMetadata entityMetadata) {
isPaddlingLeft = entityMetadata.getPrimitiveValue();
- if (isPaddlingLeft) {
- // Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing
- // This is an asynchronous method that emulates Bedrock rowing until "false" is sent.
- paddleTimeLeft = 0f;
- if (!this.passengers.isEmpty()) {
- // Get the entity by the first stored passenger and convey motion in this manner
- Entity entity = this.passengers.get(0);
- if (entity != null) {
- updateLeftPaddle(session, entity);
- }
- }
- } else {
- // Indicate that the row position should be reset
+ if (!isPaddlingLeft) {
+ paddleTimeLeft = 0.0f;
dirtyMetadata.put(EntityDataTypes.ROW_TIME_LEFT, 0.0f);
}
}
public void setPaddlingRight(BooleanEntityMetadata entityMetadata) {
isPaddlingRight = entityMetadata.getPrimitiveValue();
- if (isPaddlingRight) {
- paddleTimeRight = 0f;
- if (!this.passengers.isEmpty()) {
- Entity entity = this.passengers.get(0);
- if (entity != null) {
- updateRightPaddle(session, entity);
- }
- }
- } else {
+ if (!isPaddlingRight) {
+ paddleTimeRight = 0.0f;
dirtyMetadata.put(EntityDataTypes.ROW_TIME_RIGHT, 0.0f);
}
}
+ @Override
+ public void setLeashHolderBedrockId(long bedrockId) {
+ this.leashHolderBedrockId = bedrockId;
+ dirtyMetadata.put(EntityDataTypes.LEASH_HOLDER, bedrockId);
+ }
+
@Override
protected InteractiveTag testInteraction(Hand hand) {
+ InteractiveTag tag = super.testInteraction(hand);
+ if (tag != InteractiveTag.NONE) {
+ return tag;
+ }
if (session.isSneaking()) {
return InteractiveTag.NONE;
} else if (passengers.size() < 2) {
@@ -178,6 +172,10 @@ public class BoatEntity extends Entity {
@Override
public InteractionResult interact(Hand hand) {
+ InteractionResult result = super.interact(hand);
+ if (result != InteractionResult.PASS) {
+ return result;
+ }
if (session.isSneaking()) {
return InteractionResult.PASS;
} else {
@@ -186,32 +184,34 @@ public class BoatEntity extends Entity {
}
}
- private void updateLeftPaddle(GeyserSession session, Entity rower) {
+ @Override
+ public void tick() {
+ // Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing
+ doTick = !doTick; // Run every 100 ms
+ if (!doTick || passengers.isEmpty()) {
+ return;
+ }
+
+ Entity rower = passengers.get(0);
+ if (rower == null) {
+ return;
+ }
+
if (isPaddlingLeft) {
paddleTimeLeft += ROWING_SPEED;
sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_LEFT, paddleTimeLeft);
-
- session.scheduleInEventLoop(() ->
- updateLeftPaddle(session, rower),
- 100,
- TimeUnit.MILLISECONDS
- );
}
- }
-
- private void updateRightPaddle(GeyserSession session, Entity rower) {
if (isPaddlingRight) {
paddleTimeRight += ROWING_SPEED;
sendAnimationPacket(session, rower, AnimatePacket.Action.ROW_RIGHT, paddleTimeRight);
-
- session.scheduleInEventLoop(() ->
- updateRightPaddle(session, rower),
- 100,
- TimeUnit.MILLISECONDS
- );
}
}
+ @Override
+ public long leashHolderBedrockId() {
+ return leashHolderBedrockId;
+ }
+
private void sendAnimationPacket(GeyserSession session, Entity rower, AnimatePacket.Action action, float rowTime) {
AnimatePacket packet = new AnimatePacket();
packet.setRuntimeEntityId(rower.getGeyserId());
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ChestBoatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ChestBoatEntity.java
index 675e9517d..479b4d80d 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/ChestBoatEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/ChestBoatEntity.java
@@ -25,12 +25,12 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/CommandBlockMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/CommandBlockMinecartEntity.java
index 9c7a28f6e..2d0835286 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/CommandBlockMinecartEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/CommandBlockMinecartEntity.java
@@ -25,7 +25,7 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java
index 63b5ff2ab..fd6f17eb8 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java
@@ -25,8 +25,8 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/EnderCrystalEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/EnderCrystalEntity.java
index 86436f82b..932864bf7 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/EnderCrystalEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/EnderCrystalEntity.java
@@ -25,7 +25,7 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java
index a2b7cc6ec..08e87dc03 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java
@@ -25,13 +25,6 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
-import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
@@ -42,31 +35,34 @@ import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
-import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket;
-import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
-import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
-import org.cloudburstmc.protocol.bedrock.packet.MoveEntityDeltaPacket;
-import org.cloudburstmc.protocol.bedrock.packet.RemoveEntityPacket;
-import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket;
+import org.cloudburstmc.protocol.bedrock.packet.*;
import org.geysermc.geyser.api.entity.type.GeyserEntity;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.GeyserDirtyMetadata;
+import org.geysermc.geyser.entity.properties.GeyserEntityPropertyManager;
+import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.geyser.util.MathUtils;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.UUID;
+import java.util.*;
@Getter
@Setter
public class Entity implements GeyserEntity {
+
+ private static final boolean PRINT_ENTITY_SPAWN_DEBUG = Boolean.parseBoolean(System.getProperty("Geyser.PrintEntitySpawnDebug", "false"));
+
protected final GeyserSession session;
protected int entityId;
@@ -126,6 +122,8 @@ public class Entity implements GeyserEntity {
@Setter(AccessLevel.PROTECTED) // For players
private boolean flagsDirty = false;
+ protected final GeyserEntityPropertyManager propertyManager;
+
public Entity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
this.session = session;
@@ -140,6 +138,8 @@ public class Entity implements GeyserEntity {
this.valid = false;
+ this.propertyManager = definition.registeredProperties() == null ? null : new GeyserEntityPropertyManager(definition.registeredProperties());
+
setPosition(position);
setAirSupply(getMaxAir());
@@ -185,7 +185,7 @@ public class Entity implements GeyserEntity {
flagsDirty = false;
- if (session.getGeyser().getConfig().isDebugMode()) {
+ if (session.getGeyser().getConfig().isDebugMode() && PRINT_ENTITY_SPAWN_DEBUG) {
EntityType type = definition.entityType();
String name = type != null ? type.name() : getClass().getSimpleName();
session.getGeyser().getLogger().debug("Spawned entity " + name + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")");
@@ -200,11 +200,9 @@ public class Entity implements GeyserEntity {
/**
* Despawns the entity
- *
- * @return can be deleted
*/
- public boolean despawnEntity() {
- if (!valid) return true;
+ public void despawnEntity() {
+ if (!valid) return;
for (Entity passenger : passengers) { // Make sure all passengers on the despawned entity are updated
if (passenger == null) continue;
@@ -218,7 +216,6 @@ public class Entity implements GeyserEntity {
session.sendUpstreamPacket(removeEntityPacket);
valid = false;
- return true;
}
public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, boolean isOnGround) {
@@ -360,6 +357,23 @@ public class Entity implements GeyserEntity {
}
}
+ /**
+ * Sends the Bedrock entity properties to the client
+ */
+ public void updateBedrockEntityProperties() {
+ if (!valid) {
+ return;
+ }
+
+ if (propertyManager != null && propertyManager.hasProperties()) {
+ SetEntityDataPacket entityDataPacket = new SetEntityDataPacket();
+ entityDataPacket.setRuntimeEntityId(geyserId);
+ propertyManager.applyIntProperties(entityDataPacket.getProperties().getIntProperties());
+ propertyManager.applyFloatProperties(entityDataPacket.getProperties().getFloatProperties());
+ session.sendUpstreamPacket(entityDataPacket);
+ }
+ }
+
public void setFlags(ByteEntityMetadata entityMetadata) {
byte xd = entityMetadata.getPrimitiveValue();
setFlag(EntityFlag.ON_FIRE, ((xd & 0x01) == 0x01) && !getFlag(EntityFlag.FIRE_IMMUNE)); // Otherwise immune entities sometimes flicker onfire
@@ -544,6 +558,17 @@ public class Entity implements GeyserEntity {
* Should usually mirror {@link #interact(Hand)} without any side effects.
*/
protected InteractiveTag testInteraction(Hand hand) {
+ if (isAlive() && this instanceof Leashable leashable) {
+ if (leashable.leashHolderBedrockId() == session.getPlayerEntity().getGeyserId()) {
+ // Note this might be client side. Has yet to be an issue though, as of Java 1.21.
+ return InteractiveTag.REMOVE_LEASH;
+ }
+ if (session.getPlayerInventory().getItemInHand(hand).asItem() == Items.LEAD && leashable.canBeLeashed()) {
+ // We shall leash
+ return InteractiveTag.LEASH;
+ }
+ }
+
return InteractiveTag.NONE;
}
@@ -552,6 +577,18 @@ public class Entity implements GeyserEntity {
* to ensure packet parity as well as functionality parity (such as sound effect responses).
*/
public InteractionResult interact(Hand hand) {
+ if (isAlive() && this instanceof Leashable leashable) {
+ if (leashable.leashHolderBedrockId() == session.getPlayerEntity().getGeyserId()) {
+ // Note this might also update client side (a theoretical Geyser/client desync and Java parity issue).
+ // Has yet to be an issue though, as of Java 1.21.
+ return InteractionResult.SUCCESS;
+ }
+ if (session.getPlayerInventory().getItemInHand(hand).asItem() == Items.LEAD && leashable.canBeLeashed()) {
+ // We shall leash
+ return InteractionResult.SUCCESS;
+ }
+ }
+
return InteractionResult.PASS;
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ExpOrbEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ExpOrbEntity.java
index 5a79a98b3..9f61bc961 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/ExpOrbEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/ExpOrbEntity.java
@@ -27,11 +27,18 @@ package org.geysermc.geyser.entity.type;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
+import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.session.GeyserSession;
+import java.util.UUID;
+
public class ExpOrbEntity extends Entity {
+ public ExpOrbEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> entityDefinition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
+ this(session, 1, entityId, geyserId, position);
+ }
+
public ExpOrbEntity(GeyserSession session, int amount, int entityId, long geyserId, Vector3f position) {
super(session, entityId, geyserId, null, EntityDefinitions.EXPERIENCE_ORB, position, Vector3f.ZERO, 0, 0, 0);
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FallingBlockEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FallingBlockEntity.java
index e6d3a5783..4fcec7a63 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/FallingBlockEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/FallingBlockEntity.java
@@ -25,12 +25,12 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FireballEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FireballEntity.java
index 3db032f0f..904596b3a 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/FireballEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/FireballEntity.java
@@ -72,6 +72,9 @@ public class FireballEntity extends ThrowableEntity {
@Override
public void tick() {
+ if (removedInVoid()) {
+ return;
+ }
moveAbsoluteImmediate(tickMovement(position), getYaw(), getPitch(), getHeadYaw(), false, false);
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java
index 7a544f23c..f0739abb3 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java
@@ -25,26 +25,18 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
-import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
-import com.github.steveice10.opennbt.tag.builtin.ListTag;
-import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.math.vector.Vector3f;
-import org.cloudburstmc.nbt.NbtMap;
-import org.cloudburstmc.nbt.NbtMapBuilder;
-import org.cloudburstmc.nbt.NbtType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket;
-import org.geysermc.floodgate.util.DeviceOs;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
-import org.geysermc.geyser.level.FireworkColor;
+import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
-import org.geysermc.geyser.util.MathUtils;
+import org.geysermc.geyser.translator.item.BedrockItemBuilder;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
-import java.util.ArrayList;
-import java.util.List;
import java.util.OptionalInt;
import java.util.UUID;
@@ -59,80 +51,16 @@ public class FireworkEntity extends Entity {
if (item == null) {
return;
}
- CompoundTag tag = item.getNbt();
-
- if (tag == null) {
+ DataComponents components = item.getDataComponents();
+ if (components == null) {
return;
}
- // TODO: Remove once Mojang fixes bugs with fireworks crashing clients on these specific devices.
- // https://bugs.mojang.com/browse/MCPE-89115
- if (session.getClientData().getDeviceOs() == DeviceOs.XBOX
- || session.getClientData().getDeviceOs() == DeviceOs.PS4) {
- return;
- }
-
- CompoundTag fireworks = tag.get("Fireworks");
- if (fireworks == null) {
- // Thank you Mineplex very cool
- return;
- }
-
- NbtMapBuilder fireworksBuilder = NbtMap.builder();
- if (fireworks.get("Flight") != null) {
- fireworksBuilder.putByte("Flight", MathUtils.getNbtByte(fireworks.get("Flight").getValue()));
- }
-
- List explosions = new ArrayList<>();
- if (fireworks.get("Explosions") != null) {
- for (Tag effect : ((ListTag) fireworks.get("Explosions")).getValue()) {
- CompoundTag effectData = (CompoundTag) effect;
- NbtMapBuilder effectBuilder = NbtMap.builder();
-
- if (effectData.get("Type") != null) {
- effectBuilder.putByte("FireworkType", MathUtils.getNbtByte(effectData.get("Type").getValue()));
- }
-
- if (effectData.get("Colors") != null) {
- int[] oldColors = (int[]) effectData.get("Colors").getValue();
- byte[] colors = new byte[oldColors.length];
-
- int i = 0;
- for (int color : oldColors) {
- colors[i++] = FireworkColor.fromJavaRGB(color);
- }
-
- effectBuilder.putByteArray("FireworkColor", colors);
- }
-
- if (effectData.get("FadeColors") != null) {
- int[] oldColors = (int[]) effectData.get("FadeColors").getValue();
- byte[] colors = new byte[oldColors.length];
-
- int i = 0;
- for (int color : oldColors) {
- colors[i++] = FireworkColor.fromJavaRGB(color);
- }
-
- effectBuilder.putByteArray("FireworkFade", colors);
- }
-
- if (effectData.get("Trail") != null) {
- effectBuilder.putByte("FireworkTrail", MathUtils.getNbtByte(effectData.get("Trail").getValue()));
- }
-
- if (effectData.get("Flicker") != null) {
- effectBuilder.putByte("FireworkFlicker", MathUtils.getNbtByte(effectData.get("Flicker").getValue()));
- }
-
- explosions.add(effectBuilder.build());
- }
- }
-
- fireworksBuilder.putList("Explosions", NbtType.COMPOUND, explosions);
-
- NbtMapBuilder builder = NbtMap.builder();
- builder.put("Fireworks", fireworksBuilder.build());
+ // TODO this looked the same, so I'm going to assume it is and (keep below comment if true)
+ // Translate using item methods to get firework NBT for Bedrock
+ BedrockItemBuilder builder = new BedrockItemBuilder();
+ Items.FIREWORK_ROCKET.translateComponentsToBedrock(session, components, builder);
+
dirtyMetadata.put(EntityDataTypes.DISPLAY_FIREWORK, builder.build());
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java
index bcbff16ce..26a64bcae 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java
@@ -25,19 +25,20 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import lombok.Getter;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket;
-import lombok.Getter;
import org.geysermc.erosion.util.BlockPositionIterator;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.level.block.BlockStateValues;
+import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.level.physics.BoundingBox;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.collision.BlockCollision;
import org.geysermc.geyser.util.BlockUtils;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
@@ -133,6 +134,9 @@ public class FishingHookEntity extends ThrowableEntity {
@Override
public void tick() {
+ if (removedInVoid()) {
+ return;
+ }
if (hooked || !isInAir() && !isInWater() || isOnGround()) {
motion = Vector3f.ZERO;
return;
@@ -159,7 +163,7 @@ public class FishingHookEntity extends ThrowableEntity {
*/
protected boolean isInAir() {
int block = session.getGeyser().getWorldManager().getBlockAt(session, position.toInt());
- return block == BlockStateValues.JAVA_AIR_ID;
+ return block == Block.JAVA_AIR_ID;
}
@Override
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java
index a7a117fff..e33e6d7b6 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java
@@ -25,14 +25,16 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
-import org.geysermc.geyser.level.block.BlockStateValues;
+import org.geysermc.geyser.level.block.Blocks;
+import org.geysermc.geyser.level.block.property.Properties;
+import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@@ -51,7 +53,8 @@ public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity {
@Override
public void updateDefaultBlockMetadata() {
- dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(hasFuel ? BlockStateValues.JAVA_FURNACE_LIT_ID : BlockStateValues.JAVA_FURNACE_ID));
+ BlockState furnace = Blocks.FURNACE.defaultBlockState().withValue(Properties.LIT, hasFuel);
+ dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(furnace));
dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6);
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java
index 0917465d4..06035a47c 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/InteractionEntity.java
@@ -25,16 +25,16 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
-import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
+import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundSwingPacket;
import java.util.UUID;
@@ -80,7 +80,10 @@ public class InteractionEntity extends Entity {
}
public void setHeight(FloatEntityMetadata height) {
- setBoundingBoxHeight(height.getPrimitiveValue());
+ // Bedrock does *not* like high values being placed here
+ // https://gist.github.com/Owen1212055/f5d59169d3a6a5c32f0c173d57eb199d recommend(s/ed) using the tactic
+ // https://github.com/GeyserMC/Geyser/issues/4688
+ setBoundingBoxHeight(Math.min(height.getPrimitiveValue(), 64f));
}
public void setResponse(BooleanEntityMetadata response) {
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java
index bb67a60f6..49eb9ddc4 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java
@@ -25,8 +25,6 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
@@ -36,8 +34,11 @@ import org.cloudburstmc.protocol.bedrock.packet.AddItemEntityPacket;
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.level.block.BlockStateValues;
+import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
-import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
+import org.geysermc.geyser.translator.item.ItemTranslator;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
@@ -74,7 +75,7 @@ public class ItemEntity extends ThrowableEntity {
@Override
public void tick() {
- if (isInWater()) {
+ if (removedInVoid() || isInWater()) {
return;
}
if (!isOnGround() || (motion.getX() * motion.getX() + motion.getZ() * motion.getZ()) > 0.00001) {
@@ -137,7 +138,7 @@ public class ItemEntity extends ThrowableEntity {
protected float getDrag() {
if (isOnGround()) {
Vector3i groundBlockPos = position.toInt().down(1);
- int blockState = session.getGeyser().getWorldManager().getBlockAt(session, groundBlockPos);
+ BlockState blockState = session.getGeyser().getWorldManager().blockAt(session, groundBlockPos);
return BlockStateValues.getSlipperiness(blockState) * 0.98f;
}
return 0.98f;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java
index 295972200..f38e727c0 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java
@@ -25,12 +25,7 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
-import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
+import lombok.Getter;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap;
@@ -39,12 +34,17 @@ import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
-import lombok.Getter;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
-import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
+import org.geysermc.geyser.translator.item.ItemTranslator;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InventoryUtils;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import java.util.UUID;
@@ -148,7 +148,7 @@ public class ItemFrameEntity extends Entity {
}
@Override
- public boolean despawnEntity() {
+ public void despawnEntity() {
UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket();
updateBlockPacket.setDataLayer(0);
updateBlockPacket.setBlockPosition(bedrockPosition);
@@ -161,7 +161,6 @@ public class ItemFrameEntity extends Entity {
session.getItemFrameCache().remove(bedrockPosition, this);
valid = false;
- return true;
}
private NbtMap getDefaultTag() {
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/LeashKnotEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/LeashKnotEntity.java
index 3f0d2ee68..af739297c 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/LeashKnotEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/LeashKnotEntity.java
@@ -25,11 +25,11 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/Leashable.java b/core/src/main/java/org/geysermc/geyser/entity/type/Leashable.java
new file mode 100644
index 000000000..64d95ba3c
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/Leashable.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.entity.type;
+
+/**
+ * I can haz lead
+ * (The item, not the mineral)
+ */
+public interface Leashable {
+ void setLeashHolderBedrockId(long bedrockId);
+
+ long leashHolderBedrockId();
+
+ default boolean canBeLeashed() {
+ return isNotLeashed();
+ }
+
+ default boolean isNotLeashed() {
+ return leashHolderBedrockId() == -1L;
+ }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java
index 245b99cef..499084555 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java
@@ -25,16 +25,6 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute;
-import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
-import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
-import com.github.steveice10.opennbt.tag.builtin.StringTag;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
@@ -55,8 +45,23 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.translator.item.ItemTranslator;
import org.geysermc.geyser.util.AttributeUtils;
import org.geysermc.geyser.util.InteractionResult;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.Attribute;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
+import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffectParticleData;
+import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle;
+import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType;
import java.util.*;
@@ -69,7 +74,7 @@ public class LivingEntity extends Entity {
protected ItemData leggings = ItemData.AIR;
protected ItemData boots = ItemData.AIR;
protected ItemData hand = ItemData.AIR;
- protected ItemData offHand = ItemData.AIR;
+ protected ItemData offhand = ItemData.AIR;
@Getter(value = AccessLevel.NONE)
protected float health = 1f; // The default value in Java Edition before any entity metadata is sent
@@ -81,12 +86,58 @@ public class LivingEntity extends Entity {
*/
private boolean isMaxFrozenState = false;
+ /**
+ * The base scale entity data, without attributes applied. Used for such cases as baby variants.
+ */
+ @Getter(AccessLevel.NONE)
+ @Setter(AccessLevel.NONE)
+ private float scale;
+ /**
+ * The scale sent through the Java attributes packet
+ */
+ @Getter(AccessLevel.NONE)
+ @Setter(AccessLevel.NONE)
+ private float attributeScale;
+
public LivingEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
+ public void setHelmet(ItemStack stack) {
+ this.helmet = ItemTranslator.translateToBedrock(session, stack);
+ }
+
+ public void setChestplate(ItemStack stack) {
+ this.chestplate = ItemTranslator.translateToBedrock(session, stack);
+ }
+
+ public void setLeggings(ItemStack stack) {
+ this.leggings = ItemTranslator.translateToBedrock(session, stack);
+ }
+
+ public void setBoots(ItemStack stack) {
+ this.boots = ItemTranslator.translateToBedrock(session, stack);
+ }
+
+ public void setHand(ItemStack stack) {
+ this.hand = ItemTranslator.translateToBedrock(session, stack);
+ }
+
+ public void setOffhand(ItemStack stack) {
+ this.offhand = ItemTranslator.translateToBedrock(session, stack);
+ }
+
+ public void switchHands() {
+ ItemData offhand = this.offhand;
+ this.offhand = this.hand;
+ this.hand = offhand;
+ }
+
@Override
protected void initializeMetadata() {
+ // Initialize here so overriding classes don't have 0 values
+ this.scale = 1f;
+ this.attributeScale = 1f;
super.initializeMetadata();
// Matches Bedrock behavior; is always set to this
dirtyMetadata.put(EntityDataTypes.STRUCTURAL_INTEGRITY, 1);
@@ -121,6 +172,37 @@ public class LivingEntity extends Entity {
session.sendUpstreamPacket(attributesPacket);
}
+ // TODO: support all particle types
+ public void setParticles(ObjectEntityMetadata> entityMetadata) {
+ List particles = entityMetadata.getValue();
+ float r = 0f;
+ float g = 0f;
+ float b = 0f;
+
+ int count = 0;
+ for (Particle particle : particles) {
+ if (particle.getType() != ParticleType.ENTITY_EFFECT) {
+ continue;
+ }
+
+ int color = ((EntityEffectParticleData) particle.getData()).getColor();
+ r += ((color >> 16) & 0xFF) / 255f;
+ g += ((color >> 8) & 0xFF) / 255f;
+ b += ((color) & 0xFF) / 255f;
+ count++;
+ }
+
+ int result = 0;
+ if (count > 0) {
+ r = r / count * 255f;
+ g = g / count * 255f;
+ b = b / count * 255f;
+ result = (int) r << 16 | (int) g << 8 | (int) b;
+ }
+
+ dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, result);
+ }
+
public @Nullable Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) {
Optional optionalPos = entityMetadata.getValue();
if (optionalPos.isPresent()) {
@@ -135,7 +217,7 @@ public class LivingEntity extends Entity {
protected boolean hasShield(boolean offhand) {
ItemMapping shieldMapping = session.getItemMappings().getStoredItems().shield();
if (offhand) {
- return offHand.getDefinition().equals(shieldMapping.getBedrockDefinition());
+ return this.offhand.getDefinition().equals(shieldMapping.getBedrockDefinition());
} else {
return hand.getDefinition().equals(shieldMapping.getBedrockDefinition());
}
@@ -164,6 +246,21 @@ public class LivingEntity extends Entity {
return freezingPercentage;
}
+ protected void setScale(float scale) {
+ this.scale = scale;
+ applyScale();
+ }
+
+ private void setAttributeScale(float scale) {
+ this.attributeScale = scale;
+ applyScale();
+ }
+
+ private void applyScale() {
+ // Take any adjustments Bedrock requires, and compute it alongside the attribute's additional changes
+ this.dirtyMetadata.put(EntityDataTypes.SCALE, scale * attributeScale);
+ }
+
/**
* @return a Bedrock health attribute constructed from the data sent from the server
*/
@@ -194,9 +291,9 @@ public class LivingEntity extends Entity {
/**
* Checks to see if a nametag interaction would go through.
*/
+ // Implementation note for 1.20.5: this code was moved to the NameTag item.
protected final InteractionResult checkInteractWithNameTag(GeyserItemStack itemStack) {
- CompoundTag nbt = itemStack.getNbt();
- if (nbt != null && nbt.get("display") instanceof CompoundTag displayTag && displayTag.get("Name") instanceof StringTag) {
+ if (itemStack.getComponent(DataComponentType.CUSTOM_NAME) != null) {
// The mob shall be named
return InteractionResult.SUCCESS;
}
@@ -247,7 +344,7 @@ public class LivingEntity extends Entity {
MobEquipmentPacket offHandPacket = new MobEquipmentPacket();
offHandPacket.setRuntimeEntityId(geyserId);
- offHandPacket.setItem(offHand);
+ offHandPacket.setItem(offhand);
offHandPacket.setHotbarSlot(-1);
offHandPacket.setInventorySlot(0);
offHandPacket.setContainerId(ContainerId.OFFHAND);
@@ -255,6 +352,15 @@ public class LivingEntity extends Entity {
session.sendUpstreamPacket(offHandPacket);
}
+ /**
+ * Called when a SWING_ARM animation packet is received
+ *
+ * @return true if an ATTACK_START event should be used instead
+ */
+ public boolean useArmSwingAttack() {
+ return false;
+ }
+
/**
* Attributes are properties of an entity that are generally more runtime-based instead of permanent properties.
* Movement speed, current attack damage with a weapon, current knockback resistance.
@@ -299,7 +405,12 @@ public class LivingEntity extends Entity {
case GENERIC_MOVEMENT_SPEED -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.MOVEMENT_SPEED));
case GENERIC_FOLLOW_RANGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.FOLLOW_RANGE));
case GENERIC_KNOCKBACK_RESISTANCE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.KNOCKBACK_RESISTANCE));
- case HORSE_JUMP_STRENGTH -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.HORSE_JUMP_STRENGTH));
+ case GENERIC_JUMP_STRENGTH -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.HORSE_JUMP_STRENGTH));
+ case GENERIC_SCALE -> {
+ // Attribute on Java, entity data on Bedrock
+ setAttributeScale((float) AttributeUtils.calculateValue(javaAttribute));
+ updateBedrockMetadata();
+ }
}
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java
index ecf67052b..9096d8bd6 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java
@@ -25,9 +25,6 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
@@ -35,6 +32,9 @@ import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java
index 4e5fe9d59..6d0294783 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java
@@ -25,13 +25,15 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.packet.AddPaintingPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.level.PaintingType;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.Holder;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.PaintingVariant;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
import java.util.UUID;
@@ -49,8 +51,14 @@ public class PaintingEntity extends Entity {
// Wait until we get the metadata needed
}
- public void setPaintingType(ObjectEntityMetadata entityMetadata) {
- PaintingType type = PaintingType.getByPaintingType(entityMetadata.getValue());
+ public void setPaintingType(ObjectEntityMetadata> entityMetadata) {
+ if (!entityMetadata.getValue().isId()) {
+ return;
+ }
+ PaintingType type = session.getRegistryCache().paintings().byId(entityMetadata.getValue().id());
+ if (type == null) {
+ return;
+ }
AddPaintingPacket addPaintingPacket = new AddPaintingPacket();
addPaintingPacket.setUniqueEntityId(geyserId);
addPaintingPacket.setRuntimeEntityId(geyserId);
@@ -79,7 +87,7 @@ public class PaintingEntity extends Entity {
private Vector3f fixOffset(PaintingType paintingName) {
Vector3f position = super.position;
position = position.add(0.5, 0.5, 0.5);
- double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0;
+ double widthOffset = paintingName.getWidth() > 1 && paintingName.getWidth() != 3 ? 0.5 : 0;
double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0;
return switch (direction) {
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java
index 49cfc0081..4d69c8a1e 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java
@@ -28,7 +28,7 @@ package org.geysermc.geyser.entity.type;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
-import org.geysermc.geyser.level.block.BlockStateValues;
+import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.session.GeyserSession;
import java.util.UUID;
@@ -41,7 +41,7 @@ public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity {
@Override
public void updateDefaultBlockMetadata() {
- dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(BlockStateValues.JAVA_SPAWNER_ID));
+ dirtyMetadata.put(EntityDataTypes.DISPLAY_BLOCK_STATE, session.getBlockMappings().getBedrockBlock(Blocks.SPAWNER.defaultBlockState()));
dirtyMetadata.put(EntityDataTypes.DISPLAY_OFFSET, 6);
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java
index 98c2edd00..47d97b8f7 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java
@@ -25,13 +25,13 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
@@ -39,7 +39,17 @@ public class TNTEntity extends Entity implements Tickable {
private int currentTick;
public TNTEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
- super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
+ super(session, entityId, geyserId, uuid, definition, position.add(0, definition.offset(), 0), motion, yaw, pitch, headYaw);
+ }
+
+ @Override
+ public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, boolean isOnGround) {
+ super.moveRelative(relX, relY + definition.offset(), relZ, yaw, pitch, isOnGround);
+ }
+
+ @Override
+ public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) {
+ super.moveAbsolute(position.add(Vector3f.from(0, definition.offset(), 0)), yaw, pitch, headYaw, isOnGround, teleported);
}
public void setFuseLength(IntEntityMetadata entityMetadata) {
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java
index 0b6160401..28f38f919 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java
@@ -25,14 +25,14 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import net.kyori.adventure.text.Component;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.text.MessageTranslator;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.Optional;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java
index 60840e65b..25bbdbd3c 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java
@@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@@ -34,6 +33,7 @@ import org.cloudburstmc.protocol.bedrock.packet.MoveEntityDeltaPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.level.block.BlockStateValues;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import java.util.UUID;
@@ -55,6 +55,9 @@ public class ThrowableEntity extends Entity implements Tickable {
*/
@Override
public void tick() {
+ if (removedInVoid()) {
+ return;
+ }
moveAbsoluteImmediate(position.add(motion), getYaw(), getPitch(), getHeadYaw(), isOnGround(), false);
float drag = getDrag();
float gravity = getGravity();
@@ -170,14 +173,14 @@ public class ThrowableEntity extends Entity implements Tickable {
}
@Override
- public boolean despawnEntity() {
+ public void despawnEntity() {
if (definition.entityType() == EntityType.ENDER_PEARL) {
LevelEventPacket particlePacket = new LevelEventPacket();
particlePacket.setType(LevelEvent.PARTICLE_TELEPORT);
particlePacket.setPosition(position);
session.sendUpstreamPacket(particlePacket);
}
- return super.despawnEntity();
+ super.despawnEntity();
}
@Override
@@ -191,4 +194,17 @@ public class ThrowableEntity extends Entity implements Tickable {
moveAbsoluteImmediate(position, yaw, pitch, headYaw, isOnGround, teleported);
lastJavaPosition = position;
}
+
+ /**
+ * Removes the entity if it is 64 blocks below the world.
+ *
+ * @return true if the entity was removed
+ */
+ public boolean removedInVoid() {
+ if (position.getY() < session.getDimensionType().minY() - 64) {
+ session.getEntityCache().removeEntity(this);
+ return true;
+ }
+ return false;
+ }
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java
index 39c8386bd..55334010f 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java
@@ -25,8 +25,8 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java
index 1b5c1d2d0..88cf4f8b9 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java
@@ -25,10 +25,6 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
-import com.github.steveice10.opennbt.tag.builtin.StringTag;
-import com.github.steveice10.opennbt.tag.builtin.Tag;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@@ -38,6 +34,11 @@ import org.geysermc.geyser.inventory.item.Potion;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents;
import java.util.EnumSet;
import java.util.UUID;
@@ -53,21 +54,22 @@ public class ThrownPotionEntity extends ThrowableItemEntity {
public void setItem(EntityMetadata entityMetadata) {
ItemStack itemStack = entityMetadata.getValue();
if (itemStack == null) {
- dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, 0);
+ dirtyMetadata.put(EntityDataTypes.AUX_VALUE_DATA, (short) 0);
setFlag(EntityFlag.ENCHANTED, false);
setFlag(EntityFlag.LINGERING, false);
} else {
// As of Java 1.19.3, the server/client doesn't seem to care of the item is actually a potion?
- if (itemStack.getNbt() != null) {
- Tag potionTag = itemStack.getNbt().get("Potion");
- if (potionTag instanceof StringTag) {
- Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue());
+ DataComponents components = itemStack.getDataComponents();
+ if (components != null) {
+ PotionContents potionContents = components.get(DataComponentType.POTION_CONTENTS);
+ if (potionContents != null) {
+ Potion potion = Potion.getByJavaId(potionContents.getPotionId());
if (potion != null) {
- dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, (int) potion.getBedrockId());
+ dirtyMetadata.put(EntityDataTypes.AUX_VALUE_DATA, potion.getBedrockId());
setFlag(EntityFlag.ENCHANTED, !NON_ENCHANTED_POTIONS.contains(potion));
} else {
- dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, 0);
- GeyserImpl.getInstance().getLogger().debug("Unknown java potion: " + potionTag.getValue());
+ dirtyMetadata.put(EntityDataTypes.AUX_VALUE_DATA, (short) 0);
+ GeyserImpl.getInstance().getLogger().debug("Unknown java potion: " + potionContents.getPotionId());
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/WitherSkullEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/WitherSkullEntity.java
index 637ca4139..8427a8e10 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/WitherSkullEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/WitherSkullEntity.java
@@ -25,7 +25,7 @@
package org.geysermc.geyser.entity.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.EntityDefinitions;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/AbstractFishEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AbstractFishEntity.java
index 9cc3a006e..6ecfa4978 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/AbstractFishEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AbstractFishEntity.java
@@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type.living;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@@ -34,6 +33,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.InteractionResult;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java
index 6e2e7a407..8f84e051b 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java
@@ -25,12 +25,11 @@
package org.geysermc.geyser.entity.type.living;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
-import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.UUID;
@@ -44,12 +43,12 @@ public class AgeableEntity extends CreatureEntity {
protected void initializeMetadata() {
super.initializeMetadata();
// Required as of 1.19.3 Java
- dirtyMetadata.put(EntityDataTypes.SCALE, getAdultSize());
+ setScale(getAdultSize());
}
public void setBaby(BooleanEntityMetadata entityMetadata) {
boolean isBaby = entityMetadata.getPrimitiveValue();
- dirtyMetadata.put(EntityDataTypes.SCALE, isBaby ? getBabySize() : getAdultSize());
+ setScale(isBaby ? getBabySize() : getAdultSize());
setFlag(EntityFlag.BABY, isBaby);
setBoundingBoxHeight(definition.height() * (isBaby ? getBabySize() : getAdultSize()));
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java
index 48d633e5d..01a42e527 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java
@@ -25,8 +25,6 @@
package org.geysermc.geyser.entity.type.living;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@@ -36,6 +34,8 @@ import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/AmbientEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AmbientEntity.java
index 8f81125d0..f4b80edf1 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/AmbientEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AmbientEntity.java
@@ -38,7 +38,7 @@ public class AmbientEntity extends MobEntity {
}
@Override
- protected boolean canBeLeashed() {
+ public boolean canBeLeashed() {
return false;
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java
index c64776f18..d057f09c7 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java
@@ -25,10 +25,6 @@
package org.geysermc.geyser.entity.type.living;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import lombok.Getter;
import net.kyori.adventure.text.Component;
import org.cloudburstmc.math.vector.Vector3f;
@@ -43,6 +39,11 @@ import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.MathUtils;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import java.util.Optional;
import java.util.UUID;
@@ -99,11 +100,11 @@ public class ArmorStandEntity extends LivingEntity {
}
@Override
- public boolean despawnEntity() {
+ public void despawnEntity() {
if (secondEntity != null) {
secondEntity.despawnEntity();
}
- return super.despawnEntity();
+ super.despawnEntity();
}
@Override
@@ -257,38 +258,38 @@ public class ArmorStandEntity extends LivingEntity {
}
@Override
- public void setHelmet(ItemData helmet) {
+ public void setHelmet(ItemStack helmet) {
super.setHelmet(helmet);
updateSecondEntityStatus(true);
}
@Override
- public void setChestplate(ItemData chestplate) {
+ public void setChestplate(ItemStack chestplate) {
super.setChestplate(chestplate);
updateSecondEntityStatus(true);
}
@Override
- public void setLeggings(ItemData leggings) {
+ public void setLeggings(ItemStack leggings) {
super.setLeggings(leggings);
updateSecondEntityStatus(true);
}
@Override
- public void setBoots(ItemData boots) {
+ public void setBoots(ItemStack boots) {
super.setBoots(boots);
updateSecondEntityStatus(true);
}
@Override
- public void setHand(ItemData hand) {
+ public void setHand(ItemStack hand) {
super.setHand(hand);
updateSecondEntityStatus(true);
}
@Override
- public void setOffHand(ItemData offHand) {
- super.setOffHand(offHand);
+ public void setOffhand(ItemStack offHand) {
+ super.setOffhand(offHand);
updateSecondEntityStatus(true);
}
@@ -310,7 +311,7 @@ public class ArmorStandEntity extends LivingEntity {
if (!isInvisible) {
// The armor stand isn't invisible. We good.
setFlag(EntityFlag.INVISIBLE, false);
- dirtyMetadata.put(EntityDataTypes.SCALE, getScale());
+ setScale(getScale());
updateOffsetRequirement(false);
if (secondEntity != null) {
@@ -324,9 +325,9 @@ public class ArmorStandEntity extends LivingEntity {
}
boolean isNametagEmpty = nametag.isEmpty();
if (!isNametagEmpty && (!helmet.equals(ItemData.AIR) || !chestplate.equals(ItemData.AIR) || !leggings.equals(ItemData.AIR)
- || !boots.equals(ItemData.AIR) || !hand.equals(ItemData.AIR) || !offHand.equals(ItemData.AIR))) {
+ || !boots.equals(ItemData.AIR) || !hand.equals(ItemData.AIR) || !offhand.equals(ItemData.AIR))) {
// Reset scale of the proper armor stand
- this.dirtyMetadata.put(EntityDataTypes.SCALE, getScale());
+ setScale(getScale());
// Set the proper armor stand to invisible to show armor
setFlag(EntityFlag.INVISIBLE, true);
// Update the position of the armor stand
@@ -349,7 +350,7 @@ public class ArmorStandEntity extends LivingEntity {
// Guarantee this copy is NOT invisible
secondEntity.setFlag(EntityFlag.INVISIBLE, false);
// Scale to 0 to show nametag
- secondEntity.getDirtyMetadata().put(EntityDataTypes.SCALE, 0.0f);
+ secondEntity.setScale(0f);
// No bounding box as we don't want to interact with this entity
secondEntity.getDirtyMetadata().put(EntityDataTypes.WIDTH, 0.0f);
secondEntity.getDirtyMetadata().put(EntityDataTypes.HEIGHT, 0.0f);
@@ -359,7 +360,7 @@ public class ArmorStandEntity extends LivingEntity {
} else if (isNametagEmpty) {
// We can just make an invisible entity
// Reset scale of the proper armor stand
- dirtyMetadata.put(EntityDataTypes.SCALE, getScale());
+ setScale(getScale());
// Set the proper armor stand to invisible to show armor
setFlag(EntityFlag.INVISIBLE, true);
// Update offset
@@ -373,7 +374,7 @@ public class ArmorStandEntity extends LivingEntity {
// Nametag is not empty and there is no armor
// We don't need to make a new entity
setFlag(EntityFlag.INVISIBLE, false);
- dirtyMetadata.put(EntityDataTypes.SCALE, 0.0f);
+ setScale(0f);
// As the above is applied, we need an offset
updateOffsetRequirement(!isMarker);
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/BatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/BatEntity.java
index 644054e72..bdfc20c88 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/BatEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/BatEntity.java
@@ -25,11 +25,11 @@
package org.geysermc.geyser.entity.type.living;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/DolphinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/DolphinEntity.java
index f0348bcaf..a0ea79d67 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/DolphinEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/DolphinEntity.java
@@ -25,14 +25,15 @@
package org.geysermc.geyser.entity.type.living;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@@ -42,14 +43,14 @@ public class DolphinEntity extends WaterEntity {
}
@Override
- protected boolean canBeLeashed() {
+ public boolean canBeLeashed() {
return true;
}
@NonNull
@Override
protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
- if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) {
+ if (!itemInHand.isEmpty() && session.getTagCache().is(ItemTag.FISHES, itemInHand)) {
return InteractiveTag.FEED;
}
return super.testMobInteraction(hand, itemInHand);
@@ -58,7 +59,7 @@ public class DolphinEntity extends WaterEntity {
@NonNull
@Override
protected InteractionResult mobInteract(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
- if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) {
+ if (!itemInHand.isEmpty() && session.getTagCache().is(ItemTag.FISHES, itemInHand)) {
// Feed
return InteractionResult.SUCCESS;
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/IronGolemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/IronGolemEntity.java
index 7afa4b436..58a349cc9 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/IronGolemEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/IronGolemEntity.java
@@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type.living;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
@@ -35,6 +34,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java
index 0ac81c957..9accf178f 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java
@@ -25,14 +25,12 @@
package org.geysermc.geyser.entity.type.living;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
-import lombok.Getter;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
+import org.geysermc.geyser.entity.type.Leashable;
import org.geysermc.geyser.entity.type.LivingEntity;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
@@ -40,14 +38,15 @@ import org.geysermc.geyser.item.type.SpawnEggItem;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
-public class MobEntity extends LivingEntity {
+public class MobEntity extends LivingEntity implements Leashable {
/**
* If another mob is holding this mob by a leash, this variable tracks their Bedrock entity ID.
*/
- @Getter
private long leashHolderBedrockId;
public MobEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
@@ -65,6 +64,7 @@ public class MobEntity extends LivingEntity {
setFlag(EntityFlag.NO_AI, (xd & 0x01) == 0x01);
}
+ @Override
public void setLeashHolderBedrockId(long bedrockId) {
this.leashHolderBedrockId = bedrockId;
dirtyMetadata.put(EntityDataTypes.LEASH_HOLDER, bedrockId);
@@ -79,10 +79,7 @@ public class MobEntity extends LivingEntity {
return InteractiveTag.REMOVE_LEASH;
} else {
GeyserItemStack itemStack = session.getPlayerInventory().getItemInHand(hand);
- if (itemStack.asItem() == Items.LEAD && canBeLeashed()) {
- // We shall leash
- return InteractiveTag.LEASH;
- } else if (itemStack.asItem() == Items.NAME_TAG) {
+ if (itemStack.asItem() == Items.NAME_TAG) {
InteractionResult result = checkInteractWithNameTag(itemStack);
if (result.consumesAction()) {
return InteractiveTag.NAME;
@@ -99,9 +96,6 @@ public class MobEntity extends LivingEntity {
if (!isAlive()) {
// dead lol
return InteractionResult.PASS;
- } else if (leashHolderBedrockId == session.getPlayerEntity().getGeyserId()) {
- // TODO looks like the client assumes it will go through and removes the attachment itself?
- return InteractionResult.SUCCESS;
} else {
GeyserItemStack itemInHand = session.getPlayerInventory().getItemInHand(hand);
InteractionResult result = checkPriorityInteractions(itemInHand);
@@ -115,10 +109,7 @@ public class MobEntity extends LivingEntity {
}
private InteractionResult checkPriorityInteractions(GeyserItemStack itemInHand) {
- if (itemInHand.asItem() == Items.LEAD && canBeLeashed()) {
- // We shall leash
- return InteractionResult.SUCCESS;
- } else if (itemInHand.asItem() == Items.NAME_TAG) {
+ if (itemInHand.asItem() == Items.NAME_TAG) {
InteractionResult result = checkInteractWithNameTag(itemInHand);
if (result.consumesAction()) {
return result;
@@ -143,12 +134,14 @@ public class MobEntity extends LivingEntity {
return InteractionResult.PASS;
}
- protected boolean canBeLeashed() {
+ @Override
+ public boolean canBeLeashed() {
return isNotLeashed() && !isEnemy();
}
- protected final boolean isNotLeashed() {
- return leashHolderBedrockId == -1L;
+ @Override
+ public long leashHolderBedrockId() {
+ return leashHolderBedrockId;
}
/**
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java
index 1d2eb95bc..3be2db1db 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java
@@ -25,11 +25,10 @@
package org.geysermc.geyser.entity.type.living;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
-import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
@@ -39,8 +38,8 @@ public class SlimeEntity extends MobEntity {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
- public void setScale(IntEntityMetadata entityMetadata) {
- dirtyMetadata.put(EntityDataTypes.SCALE, 0.10f + entityMetadata.getPrimitiveValue());
+ public void setSlimeScale(IntEntityMetadata entityMetadata) {
+ setScale(0.10f + entityMetadata.getPrimitiveValue());
}
@Override
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/SnowGolemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/SnowGolemEntity.java
index 7f0699415..50aa7b90e 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/SnowGolemEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/SnowGolemEntity.java
@@ -25,8 +25,6 @@
package org.geysermc.geyser.entity.type.living;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@@ -36,6 +34,8 @@ import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java
index 80a5af442..6285bd9a4 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java
@@ -122,7 +122,7 @@ public class SquidEntity extends WaterEntity implements Tickable {
}
@Override
- protected boolean canBeLeashed() {
+ public boolean canBeLeashed() {
return isNotLeashed();
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java
index 7094c431e..68cf763c3 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java
@@ -25,15 +25,15 @@
package org.geysermc.geyser.entity.type.living;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
-import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@@ -62,6 +62,6 @@ public class TadpoleEntity extends AbstractFishEntity {
}
private boolean isFood(GeyserItemStack itemStack) {
- return itemStack.asItem() == Items.SLIME_BALL;
+ return session.getTagCache().is(ItemTag.FROG_FOOD, itemStack);
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java
index a847c4cd7..ae9d0d659 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java
@@ -38,7 +38,7 @@ public class WaterEntity extends CreatureEntity {
}
@Override
- protected boolean canBeLeashed() {
+ public boolean canBeLeashed() {
return false;
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AnimalEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AnimalEntity.java
index 7278709ce..2e627b461 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AnimalEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AnimalEntity.java
@@ -25,39 +25,40 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.living.AgeableEntity;
import org.geysermc.geyser.inventory.GeyserItemStack;
-import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
-public class AnimalEntity extends AgeableEntity {
+public abstract class AnimalEntity extends AgeableEntity {
public AnimalEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
- public final boolean canEat(GeyserItemStack itemStack) {
- return canEat(itemStack.asItem());
+ protected final boolean canEat(GeyserItemStack itemStack) {
+ ItemTag tag = getFoodTag();
+ if (tag == null) {
+ return false;
+ }
+ return session.getTagCache().is(tag, itemStack);
}
/**
- * @return true if this is a valid item to breed with for this animal.
+ * @return the tag associated with this animal for eating food. Null for nothing or different behavior.
*/
- public boolean canEat(Item item) {
- // This is what it defaults to. OK.
- return item == Items.WHEAT;
- }
+ protected abstract @Nullable ItemTag getFoodTag();
@NonNull
@Override
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ArmadilloEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ArmadilloEntity.java
new file mode 100644
index 000000000..968520bb6
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ArmadilloEntity.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.entity.type.living.animal;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.cloudburstmc.math.vector.Vector3f;
+import org.geysermc.geyser.entity.EntityDefinition;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.ArmadilloState;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+public class ArmadilloEntity extends AnimalEntity {
+ private ArmadilloState armadilloState = ArmadilloState.IDLE;
+
+ public ArmadilloEntity(GeyserSession session, int entityId, long geyserId, UUID uuid,
+ EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
+ super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
+ }
+
+ public void setArmadilloState(ObjectEntityMetadata entityMetadata) {
+ armadilloState = entityMetadata.getValue();
+
+ switch (armadilloState) {
+ case IDLE -> propertyManager.add("minecraft:armadillo_state", "unrolled");
+ case ROLLING -> propertyManager.add("minecraft:armadillo_state", "rolled_up");
+ case SCARED -> propertyManager.add("minecraft:armadillo_state", "rolled_up_relaxing");
+ case UNROLLING -> propertyManager.add("minecraft:armadillo_state", "rolled_up_unrolling");
+ }
+
+ updateBedrockEntityProperties();
+ }
+
+ public void onPeeking() {
+ // Technically we should wait if not currently scared
+ if (armadilloState == ArmadilloState.SCARED) {
+ propertyManager.add("minecraft:armadillo_state", "rolled_up_peeking");
+ updateBedrockEntityProperties();
+
+ // Needed for consecutive peeks
+ session.scheduleInEventLoop(() -> {
+ if (armadilloState == ArmadilloState.SCARED) {
+ propertyManager.add("minecraft:armadillo_state", "rolled_up_relaxing");
+ updateBedrockEntityProperties();
+ }
+ }, 250, TimeUnit.MILLISECONDS);
+ }
+ }
+
+ @Override
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.ARMADILLO_FOOD;
+ }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AxolotlEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AxolotlEntity.java
index 85b2afc14..a0ab56ead 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AxolotlEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AxolotlEntity.java
@@ -25,19 +25,20 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.InteractionResult;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@@ -60,8 +61,9 @@ public class AxolotlEntity extends AnimalEntity {
}
@Override
- public boolean canEat(Item item) {
- return session.getTagCache().isAxolotlTemptItem(item);
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.AXOLOTL_FOOD;
}
@Override
@@ -70,7 +72,7 @@ public class AxolotlEntity extends AnimalEntity {
}
@Override
- protected boolean canBeLeashed() {
+ public boolean canBeLeashed() {
return true;
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/BeeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/BeeEntity.java
index e05b44cf0..4fcf0e178 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/BeeEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/BeeEntity.java
@@ -25,16 +25,17 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
import org.geysermc.geyser.entity.EntityDefinition;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
@@ -57,7 +58,8 @@ public class BeeEntity extends AnimalEntity {
// If the bee has stung
dirtyMetadata.put(EntityDataTypes.MARK_VARIANT, (xd & 0x04) == 0x04 ? 1 : 0);
// If the bee has nectar or not
- setFlag(EntityFlag.POWERED, (xd & 0x08) == 0x08);
+ propertyManager.add("minecraft:has_nectar", (xd & 0x08) == 0x08);
+ updateBedrockEntityProperties();
}
public void setAngerTime(IntEntityMetadata entityMetadata) {
@@ -66,7 +68,8 @@ public class BeeEntity extends AnimalEntity {
}
@Override
- public boolean canEat(Item item) {
- return session.getTagCache().isFlower(item);
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.BEE_FOOD;
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java
index 164fb1b6c..075a49923 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java
@@ -25,24 +25,23 @@
package org.geysermc.geyser.entity.type.living.animal;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
-import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
-import java.util.Set;
import java.util.UUID;
public class ChickenEntity extends AnimalEntity {
- private static final Set VALID_FOOD = Set.of(Items.WHEAT_SEEDS, Items.MELON_SEEDS, Items.PUMPKIN_SEEDS, Items.BEETROOT_SEEDS);
public ChickenEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
@Override
- public boolean canEat(Item item) {
- return VALID_FOOD.contains(item);
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.CHICKEN_FOOD;
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java
index cdcf534a3..64e7de193 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java
@@ -25,8 +25,8 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@@ -34,8 +34,10 @@ import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@@ -64,4 +66,10 @@ public class CowEntity extends AnimalEntity {
session.playSoundEvent(SoundEvent.MILK, position);
return InteractionResult.SUCCESS;
}
+
+ @Override
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.COW_FOOD;
+ }
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FoxEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FoxEntity.java
index 98c73cbce..e20031baa 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FoxEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FoxEntity.java
@@ -25,14 +25,15 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
@@ -55,7 +56,8 @@ public class FoxEntity extends AnimalEntity {
}
@Override
- public boolean canEat(Item item) {
- return session.getTagCache().isFoxFood(item);
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.FOX_FOOD;
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FrogEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FrogEntity.java
index 039ef5bf9..120bfcdd4 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FrogEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FrogEntity.java
@@ -25,17 +25,17 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Entity;
-import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import java.util.OptionalInt;
import java.util.UUID;
@@ -76,7 +76,8 @@ public class FrogEntity extends AnimalEntity {
}
@Override
- public boolean canEat(Item item) {
- return item == Items.SLIME_BALL;
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.FROG_FOOD;
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/GoatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/GoatEntity.java
index 9ed94f96f..4e919b81c 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/GoatEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/GoatEntity.java
@@ -25,10 +25,8 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
@@ -37,7 +35,11 @@ import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@@ -94,4 +96,10 @@ public class GoatEntity extends AnimalEntity {
private void setHornCount() {
dirtyMetadata.put(EntityDataTypes.GOAT_HORN_COUNT, (hasLeftHorn ? 1 : 0) + (hasRightHorn ? 1 : 0));
}
+
+ @Override
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.GOAT_FOOD;
+ }
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/HoglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/HoglinEntity.java
index 154c2f688..cc23fc607 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/HoglinEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/HoglinEntity.java
@@ -25,13 +25,14 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
+import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
-import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.UUID;
@@ -40,6 +41,8 @@ public class HoglinEntity extends AnimalEntity {
public HoglinEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
+ dirtyMetadata.put(EntityDataTypes.TARGET_EID, session.getPlayerEntity().getGeyserId());
+ setFlag(EntityFlag.SHAKING, isShaking());
}
public void setImmuneToZombification(BooleanEntityMetadata entityMetadata) {
@@ -54,12 +57,13 @@ public class HoglinEntity extends AnimalEntity {
}
@Override
- public boolean canEat(Item item) {
- return item == Items.CRIMSON_FUNGUS;
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.HOGLIN_FOOD;
}
@Override
- protected boolean canBeLeashed() {
+ public boolean canBeLeashed() {
return isNotLeashed();
}
@@ -67,4 +71,9 @@ public class HoglinEntity extends AnimalEntity {
protected boolean isEnemy() {
return true;
}
+
+ @Override
+ public boolean useArmSwingAttack() {
+ return true;
+ }
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java
index 1c347bf31..2c9040b53 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java
@@ -25,22 +25,22 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.FlowerItem;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
-public class MooshroomEntity extends AnimalEntity {
+public class MooshroomEntity extends CowEntity {
private boolean isBrown = false;
public MooshroomEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
@@ -77,7 +77,7 @@ public class MooshroomEntity extends AnimalEntity {
} else if (!isBaby && isAlive() && itemInHand.asItem() == Items.SHEARS) {
// Shear items
return InteractionResult.SUCCESS;
- } else if (isBrown && session.getTagCache().isSmallFlower(itemInHand) && itemInHand.asItem() instanceof FlowerItem) {
+ } else if (isBrown && session.getTagCache().is(ItemTag.SMALL_FLOWERS, itemInHand)) {
// ?
return InteractionResult.SUCCESS;
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/OcelotEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/OcelotEntity.java
index c115ebcdc..9d6d33227 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/OcelotEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/OcelotEntity.java
@@ -25,17 +25,17 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
-import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@@ -46,8 +46,9 @@ public class OcelotEntity extends AnimalEntity {
}
@Override
- public boolean canEat(Item item) {
- return item == Items.COD || item == Items.SALMON;
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.OCELOT_FOOD;
}
@NonNull
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PandaEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PandaEntity.java
index d2ef36932..aaa7c2d7e 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PandaEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PandaEntity.java
@@ -25,9 +25,6 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
@@ -37,11 +34,13 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
-import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@@ -62,7 +61,8 @@ public class PandaEntity extends AnimalEntity {
EntityEventPacket packet = new EntityEventPacket();
packet.setRuntimeEntityId(geyserId);
packet.setType(EntityEventType.EATING_ITEM);
- packet.setData(session.getItemMappings().getStoredItems().bamboo().getBedrockDefinition().getRuntimeId() << 16);
+ // As of 1.20.5 - pandas can eat cake
+ packet.setData(this.hand.getDefinition().getRuntimeId() << 16);
session.sendUpstreamPacket(packet);
}
}
@@ -89,8 +89,9 @@ public class PandaEntity extends AnimalEntity {
}
@Override
- public boolean canEat(Item item) {
- return item == Items.BAMBOO;
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.PANDA_FOOD;
}
@NonNull
@@ -122,7 +123,7 @@ public class PandaEntity extends AnimalEntity {
}
@Override
- protected boolean canBeLeashed() {
+ public boolean canBeLeashed() {
return false;
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java
index 2bc02cd55..446e3e109 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java
@@ -25,18 +25,18 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
-import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@@ -47,8 +47,9 @@ public class PigEntity extends AnimalEntity {
}
@Override
- public boolean canEat(Item item) {
- return item == Items.CARROT || item == Items.POTATO || item == Items.BEETROOT;
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.PIG_FOOD;
}
@NonNull
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PolarBearEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PolarBearEntity.java
index 1d7777cdb..0e83615f7 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PolarBearEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PolarBearEntity.java
@@ -25,10 +25,11 @@
package org.geysermc.geyser.entity.type.living.animal;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import java.util.UUID;
@@ -39,7 +40,8 @@ public class PolarBearEntity extends AnimalEntity {
}
@Override
- public boolean canEat(Item item) {
- return false;
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return null;
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PufferFishEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PufferFishEntity.java
index d0d119593..6f0063474 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PufferFishEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PufferFishEntity.java
@@ -25,12 +25,12 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.living.AbstractFishEntity;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/RabbitEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/RabbitEntity.java
index 1efa87ec8..0a108be73 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/RabbitEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/RabbitEntity.java
@@ -25,14 +25,14 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
-import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
@@ -67,7 +67,8 @@ public class RabbitEntity extends AnimalEntity {
}
@Override
- public boolean canEat(Item item) {
- return item == Items.DANDELION || item == Items.CARROT || item == Items.GOLDEN_CARROT;
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.RABBIT_FOOD;
}
}
\ No newline at end of file
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SheepEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SheepEntity.java
index 13059244a..155ddf00c 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SheepEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SheepEntity.java
@@ -25,9 +25,8 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@@ -36,8 +35,11 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.DyeItem;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@@ -55,6 +57,12 @@ public class SheepEntity extends AnimalEntity {
dirtyMetadata.put(EntityDataTypes.COLOR, (byte) color);
}
+ @Override
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.SHEEP_FOOD;
+ }
+
@NonNull
@Override
protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SnifferEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SnifferEntity.java
index a97756e39..11fee5bbf 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SnifferEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SnifferEntity.java
@@ -25,9 +25,7 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.SnifferState;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
@@ -37,8 +35,11 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.Tickable;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.SnifferState;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
import java.util.UUID;
@@ -71,8 +72,9 @@ public class SnifferEntity extends AnimalEntity implements Tickable {
}
@Override
- public boolean canEat(Item item) {
- return session.getTagCache().isSnifferFood(item);
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.SNIFFER_FOOD;
}
public void setSnifferState(ObjectEntityMetadata entityMetadata) {
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/StriderEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/StriderEntity.java
index 39a55fa1e..0291f75d9 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/StriderEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/StriderEntity.java
@@ -25,20 +25,20 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.inventory.GeyserItemStack;
-import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.EntityUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@@ -94,8 +94,9 @@ public class StriderEntity extends AnimalEntity {
}
@Override
- public boolean canEat(Item item) {
- return item == Items.WARPED_FUNGUS;
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.STRIDER_FOOD;
}
@NonNull
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java
index b18e55a48..b6751bc3f 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java
@@ -25,14 +25,14 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import com.google.common.collect.ImmutableList;
+import it.unimi.dsi.fastutil.ints.IntList;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
-import it.unimi.dsi.fastutil.ints.IntList;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.living.AbstractFishEntity;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.List;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TurtleEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TurtleEntity.java
index 870ded193..16901a844 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TurtleEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TurtleEntity.java
@@ -25,13 +25,13 @@
package org.geysermc.geyser.entity.type.living.animal;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
-import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.UUID;
@@ -50,12 +50,13 @@ public class TurtleEntity extends AnimalEntity {
}
@Override
- public boolean canEat(Item item) {
- return item == Items.SEAGRASS;
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.TURTLE_FOOD;
}
@Override
- protected boolean canBeLeashed() {
+ public boolean canBeLeashed() {
return false;
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/AbstractHorseEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/AbstractHorseEntity.java
index faa495487..ddc212053 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/AbstractHorseEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/AbstractHorseEntity.java
@@ -25,9 +25,8 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
@@ -40,21 +39,16 @@ import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
import org.geysermc.geyser.entity.type.living.animal.AnimalEntity;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
-import java.util.Set;
import java.util.UUID;
public class AbstractHorseEntity extends AnimalEntity {
- /**
- * A list of all foods a horse/donkey can eat on Java Edition.
- * Used to display interactive tag if needed.
- */
- private static final Set DONKEY_AND_HORSE_FOODS = Set.of(Items.GOLDEN_APPLE, Items.ENCHANTED_GOLDEN_APPLE,
- Items.GOLDEN_CARROT, Items.SUGAR, Items.APPLE, Items.WHEAT, Items.HAY_BLOCK);
public AbstractHorseEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
@@ -124,8 +118,9 @@ public class AbstractHorseEntity extends AnimalEntity {
}
@Override
- public boolean canEat(Item item) {
- return DONKEY_AND_HORSE_FOODS.contains(item);
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.HORSE_FOOD;
}
@NonNull
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/CamelEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/CamelEntity.java
index 8106b096d..ee3b2be70 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/CamelEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/CamelEntity.java
@@ -25,9 +25,7 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
@@ -35,9 +33,11 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
import org.geysermc.geyser.entity.EntityDefinition;
-import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import java.util.UUID;
@@ -90,8 +90,8 @@ public class CamelEntity extends AbstractHorseEntity {
}
@Override
- public boolean canEat(Item item) {
- return item == Items.CACTUS;
+ protected @Nullable ItemTag getFoodTag() {
+ return ItemTag.CAMEL_FOOD;
}
@Override
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/HorseEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/HorseEntity.java
index dfa6ef30a..b8a9a8f28 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/HorseEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/HorseEntity.java
@@ -25,11 +25,11 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/LlamaEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/LlamaEntity.java
index a32d7b1b5..76939ceb9 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/LlamaEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/LlamaEntity.java
@@ -25,19 +25,24 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import lombok.Getter;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
-import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
-import org.cloudburstmc.protocol.bedrock.packet.MobArmorEquipmentPacket;
import org.geysermc.geyser.entity.EntityDefinition;
-import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
+import org.geysermc.geyser.util.MathUtils;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
public class LlamaEntity extends ChestedHorseEntity {
+ /**
+ * Used to calculate inventory size
+ */
+ @Getter
+ private int strength = 1;
public LlamaEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
@@ -45,32 +50,13 @@ public class LlamaEntity extends ChestedHorseEntity {
dirtyMetadata.put(EntityDataTypes.CONTAINER_STRENGTH_MODIFIER, 3); // Presumably 3 slots for every 1 strength
}
- /**
- * Color equipped on the llama
- */
- public void setCarpetedColor(IntEntityMetadata entityMetadata) {
- // Bedrock treats llama decoration as armor
- MobArmorEquipmentPacket equipmentPacket = new MobArmorEquipmentPacket();
- equipmentPacket.setRuntimeEntityId(geyserId);
- // -1 means no armor
- int carpetIndex = entityMetadata.getPrimitiveValue();
- if (carpetIndex > -1 && carpetIndex <= 15) {
- // The damage value is the dye color that Java sends us, for pre-1.16.220
- // The item is always going to be a carpet
- equipmentPacket.setChestplate(session.getItemMappings().getCarpets().get(carpetIndex));
- } else {
- equipmentPacket.setChestplate(ItemData.AIR);
- }
- // Required to fill out the rest of the equipment or Bedrock ignores it, including above else statement if removing armor
- equipmentPacket.setBoots(ItemData.AIR);
- equipmentPacket.setHelmet(ItemData.AIR);
- equipmentPacket.setLeggings(ItemData.AIR);
-
- session.sendUpstreamPacket(equipmentPacket);
+ public void setStrength(IntEntityMetadata entityMetadata) {
+ strength = MathUtils.constrain(entityMetadata.getPrimitiveValue(), 1, 5);
+ this.dirtyMetadata.put(EntityDataTypes.STRENGTH, strength);
}
@Override
- public boolean canEat(Item item) {
- return item == Items.WHEAT || item == Items.HAY_BLOCK;
+ protected @Nullable ItemTag getFoodTag() {
+ return ItemTag.LLAMA_FOOD;
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/SkeletonHorseEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/SkeletonHorseEntity.java
index 7080f9f75..d74913c31 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/SkeletonHorseEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/SkeletonHorseEntity.java
@@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
@@ -33,6 +32,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ZombieHorseEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ZombieHorseEntity.java
index 3275712fc..9e77daebc 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ZombieHorseEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ZombieHorseEntity.java
@@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type.living.animal.horse;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition;
@@ -33,6 +32,7 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/CatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/CatEntity.java
index 412157b5d..bf1555e9d 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/CatEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/CatEntity.java
@@ -25,27 +25,27 @@
package org.geysermc.geyser.entity.type.living.animal.tameable;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
-import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
public class CatEntity extends TameableEntity {
- private byte collarColor;
+ private byte collarColor = 14; // Red - default
public CatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
@@ -76,10 +76,7 @@ public class CatEntity extends TameableEntity {
@Override
public void setTameableFlags(ByteEntityMetadata entityMetadata) {
super.setTameableFlags(entityMetadata);
- // Update collar color if tamed
- if (getFlag(EntityFlag.TAMED)) {
- dirtyMetadata.put(EntityDataTypes.COLOR, collarColor);
- }
+ updateCollarColor();
}
public void setCatVariant(IntEntityMetadata entityMetadata) {
@@ -101,6 +98,10 @@ public class CatEntity extends TameableEntity {
public void setCollarColor(IntEntityMetadata entityMetadata) {
collarColor = (byte) entityMetadata.getPrimitiveValue();
+ updateCollarColor();
+ }
+
+ private void updateCollarColor() {
// Needed or else wild cats are a red color
if (getFlag(EntityFlag.TAMED)) {
dirtyMetadata.put(EntityDataTypes.COLOR, collarColor);
@@ -108,8 +109,8 @@ public class CatEntity extends TameableEntity {
}
@Override
- public boolean canEat(Item item) {
- return item == Items.COD || item == Items.SALMON;
+ protected @Nullable ItemTag getFoodTag() {
+ return ItemTag.CAT_FOOD;
}
@NonNull
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/ParrotEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/ParrotEntity.java
index 4c4b6a222..8baba6f00 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/ParrotEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/ParrotEntity.java
@@ -25,8 +25,8 @@
package org.geysermc.geyser.entity.type.living.animal.tameable;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
@@ -34,8 +34,10 @@ import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.Set;
import java.util.UUID;
@@ -49,16 +51,17 @@ public class ParrotEntity extends TameableEntity {
}
@Override
- public boolean canEat(Item item) {
- return false;
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return null;
}
private boolean isTameFood(Item item) {
- return TAMING_FOOD.contains(item);
+ return session.getTagCache().is(ItemTag.PARROT_FOOD, item);
}
private boolean isPoisonousFood(Item item) {
- return item == Items.COOKIE;
+ return session.getTagCache().is(ItemTag.PARROT_POISONOUS_FOOD, item);
}
@NonNull
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java
index 5fc8c459d..ea347d193 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java
@@ -25,21 +25,21 @@
package org.geysermc.geyser.entity.type.living.animal.tameable;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import lombok.Getter;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
-import lombok.Getter;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.living.animal.AnimalEntity;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import java.util.Optional;
import java.util.UUID;
-public class TameableEntity extends AnimalEntity {
+public abstract class TameableEntity extends AnimalEntity {
/**
* Used in the interactive tag manager to track if the session player owns this entity
*/
@@ -84,7 +84,7 @@ public class TameableEntity extends AnimalEntity {
}
@Override
- protected boolean canBeLeashed() {
+ public boolean canBeLeashed() {
return isNotLeashed();
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java
index 0f5b36ec3..e7fde2be8 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java
@@ -25,36 +25,39 @@
package org.geysermc.geyser.entity.type.living.animal.tameable;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
+import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
+import org.geysermc.geyser.item.enchantment.EnchantmentComponent;
import org.geysermc.geyser.item.type.DyeItem;
-import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.geyser.util.ItemUtils;
+import org.geysermc.mcprotocollib.protocol.data.game.Holder;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.WolfVariant;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
-import java.util.Set;
+import java.util.Collections;
+import java.util.Locale;
import java.util.UUID;
public class WolfEntity extends TameableEntity {
- /**
- * A list of all foods a wolf can eat on Java Edition.
- * Used to display interactive tag or particles if needed.
- * TODO generate
- */
- private static final Set WOLF_FOODS = Set.of(Items.PUFFERFISH, Items.TROPICAL_FISH, Items.CHICKEN, Items.COOKED_CHICKEN,
- Items.PORKCHOP, Items.BEEF, Items.RABBIT, Items.COOKED_PORKCHOP, Items.COOKED_BEEF, Items.ROTTEN_FLESH, Items.MUTTON, Items.COOKED_MUTTON,
- Items.COOKED_RABBIT);
+ private byte collarColor = 14; // Red - default
- private byte collarColor;
+ private boolean isCurseOfBinding = false;
public WolfEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
@@ -64,19 +67,27 @@ public class WolfEntity extends TameableEntity {
public void setTameableFlags(ByteEntityMetadata entityMetadata) {
super.setTameableFlags(entityMetadata);
// Reset wolf color
- byte xd = entityMetadata.getPrimitiveValue();
- boolean angry = (xd & 0x02) == 0x02;
- if (angry) {
+ if (getFlag(EntityFlag.ANGRY)) {
dirtyMetadata.put(EntityDataTypes.COLOR, (byte) 0);
+ } else if (getFlag(EntityFlag.TAMED)) {
+ updateCollarColor();
+
+ // This fixes tail angle when taming
+ UpdateAttributesPacket packet = new UpdateAttributesPacket();
+ packet.setRuntimeEntityId(geyserId);
+ packet.setAttributes(Collections.singletonList(createHealthAttribute()));
+ session.sendUpstreamPacket(packet);
}
}
public void setCollarColor(IntEntityMetadata entityMetadata) {
collarColor = (byte) entityMetadata.getPrimitiveValue();
- if (getFlag(EntityFlag.ANGRY)) {
- return;
+ if (!getFlag(EntityFlag.ANGRY) && getFlag(EntityFlag.TAMED)) {
+ updateCollarColor();
}
+ }
+ private void updateCollarColor() {
dirtyMetadata.put(EntityDataTypes.COLOR, collarColor);
if (ownerBedrockId == 0) {
// If a color is set and there is no owner entity ID, set one.
@@ -92,14 +103,31 @@ public class WolfEntity extends TameableEntity {
dirtyMetadata.put(EntityDataTypes.COLOR, time != 0 ? (byte) 0 : collarColor);
}
- @Override
- public boolean canEat(Item item) {
- // Cannot be a baby to eat these foods
- return WOLF_FOODS.contains(item) && !isBaby();
+ // 1.20.5+
+ public void setWolfVariant(ObjectEntityMetadata> entityMetadata) {
+ entityMetadata.getValue().ifId(id -> {
+ BuiltInWolfVariant wolfVariant = session.getRegistryCache().wolfVariants().byId(id);
+ if (wolfVariant == null) {
+ wolfVariant = BuiltInWolfVariant.PALE;
+ }
+ dirtyMetadata.put(EntityDataTypes.VARIANT, wolfVariant.ordinal());
+ });
}
@Override
- protected boolean canBeLeashed() {
+ @Nullable
+ protected ItemTag getFoodTag() {
+ return ItemTag.WOLF_FOOD;
+ }
+
+ @Override
+ public void setChestplate(ItemStack stack) {
+ super.setChestplate(stack);
+ isCurseOfBinding = ItemUtils.hasEffect(session, stack, EnchantmentComponent.PREVENT_ARMOR_CHANGE); // TODO test
+ }
+
+ @Override
+ public boolean canBeLeashed() {
return !getFlag(EntityFlag.ANGRY) && super.canBeLeashed();
}
@@ -112,16 +140,30 @@ public class WolfEntity extends TameableEntity {
if (itemInHand.asItem() == Items.BONE && !getFlag(EntityFlag.TAMED)) {
// Bone and untamed - can tame
return InteractiveTag.TAME;
- } else {
- if (itemInHand.asItem() instanceof DyeItem item) {
+ }
+ if (getFlag(EntityFlag.TAMED) && ownerBedrockId == session.getPlayerEntity().getGeyserId()) {
+ if (itemInHand.asItem() instanceof DyeItem dyeItem) {
// If this fails, as of Java Edition 1.18.1, you cannot toggle sit/stand
- if (item.dyeColor() != this.collarColor) {
+ if (dyeItem.dyeColor() != this.collarColor) {
return InteractiveTag.DYE;
+ } else {
+ return super.testMobInteraction(hand, itemInHand);
}
- } else if (getFlag(EntityFlag.TAMED) && ownerBedrockId == session.getPlayerEntity().getGeyserId()) {
- // Tamed and owned by player - can sit/stand
- return getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
}
+ if (itemInHand.asItem() == Items.WOLF_ARMOR && !this.chestplate.isValid() && !getFlag(EntityFlag.BABY)) {
+ return InteractiveTag.EQUIP_WOLF_ARMOR;
+ }
+ if (itemInHand.asItem() == Items.SHEARS && this.chestplate.isValid()
+ && (!isCurseOfBinding || session.getGameMode().equals(GameMode.CREATIVE))) {
+ return InteractiveTag.REMOVE_WOLF_ARMOR;
+ }
+ if (Items.WOLF_ARMOR.isValidRepairItem(itemInHand.asItem()) && getFlag(EntityFlag.SITTING) &&
+ this.chestplate.isValid() && this.chestplate.getTag() != null &&
+ this.chestplate.getTag().getInt("Damage") > 0) {
+ return InteractiveTag.REPAIR_WOLF_ARMOR;
+ }
+ // Tamed and owned by player - can sit/stand
+ return getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT;
}
return super.testMobInteraction(hand, itemInHand);
}
@@ -137,4 +179,34 @@ public class WolfEntity extends TameableEntity {
return InteractionResult.PASS;
}
}
+
+ // Ordered by bedrock id
+ public enum BuiltInWolfVariant {
+ PALE,
+ ASHEN,
+ BLACK,
+ CHESTNUT,
+ RUSTY,
+ SNOWY,
+ SPOTTED,
+ STRIPED,
+ WOODS;
+
+ private static final BuiltInWolfVariant[] VALUES = values();
+
+ private final String javaIdentifier;
+
+ BuiltInWolfVariant() {
+ this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT);
+ }
+
+ public static @Nullable BuiltInWolfVariant getByJavaIdentifier(String javaIdentifier) {
+ for (BuiltInWolfVariant wolfVariant : VALUES) {
+ if (wolfVariant.javaIdentifier.equals(javaIdentifier)) {
+ return wolfVariant;
+ }
+ }
+ return null;
+ }
+ }
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java
index c7b29130f..2492aabd7 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java
@@ -25,7 +25,6 @@
package org.geysermc.geyser.entity.type.living.merchant;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
@@ -37,6 +36,7 @@ import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@@ -47,7 +47,7 @@ public class AbstractMerchantEntity extends AgeableEntity {
}
@Override
- protected boolean canBeLeashed() {
+ public boolean canBeLeashed() {
return false;
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java
index 9b0f50050..d7efa9f1d 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java
@@ -25,8 +25,6 @@
package org.geysermc.geyser.entity.type.living.merchant;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
import lombok.Getter;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
@@ -35,9 +33,12 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
import org.geysermc.geyser.entity.EntityDefinition;
-import org.geysermc.geyser.registry.BlockRegistries;
-import org.geysermc.geyser.registry.type.BlockMapping;
+import org.geysermc.geyser.level.block.property.Properties;
+import org.geysermc.geyser.level.block.type.BedBlock;
+import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.VillagerData;
import java.util.Optional;
import java.util.UUID;
@@ -119,28 +120,31 @@ public class VillagerEntity extends AbstractMerchantEntity {
}
// The bed block
- int blockId = session.getGeyser().getWorldManager().getBlockAt(session, bedPosition);
- String fullIdentifier = BlockRegistries.JAVA_BLOCKS.getOrDefault(blockId, BlockMapping.DEFAULT).getJavaIdentifier();
+ BlockState state = session.getGeyser().getWorldManager().blockAt(session, bedPosition);
// Set the correct position offset and rotation when sleeping
int bedRotation = 0;
float xOffset = 0;
float zOffset = 0;
- if (fullIdentifier.contains("facing=south")) {
- // bed is facing south
- bedRotation = 180;
- zOffset = -.5f;
- } else if (fullIdentifier.contains("facing=east")) {
- // bed is facing east
- bedRotation = 90;
- xOffset = -.5f;
- } else if (fullIdentifier.contains("facing=west")) {
- // bed is facing west
- bedRotation = 270;
- xOffset = .5f;
- } else if (fullIdentifier.contains("facing=north")) {
- // rotation does not change because north is 0
- zOffset = .5f;
+ if (state.block() instanceof BedBlock) {
+ switch (state.getValue(Properties.HORIZONTAL_FACING)) {
+ case SOUTH -> {
+ bedRotation = 180;
+ zOffset = -.5f;
+ }
+ case EAST -> {
+ bedRotation = 90;
+ xOffset = -.5f;
+ }
+ case WEST -> {
+ bedRotation = 270;
+ xOffset = .5f;
+ }
+ case NORTH -> {
+ // rotation does not change because north is 0
+ zOffset = .5f;
+ }
+ }
}
setYaw(yaw);
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java
index 04b3bba1b..d08fff06a 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java
@@ -25,11 +25,13 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
+import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
+import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import java.util.UUID;
@@ -45,5 +47,17 @@ public class AbstractSkeletonEntity extends MonsterEntity {
byte xd = entityMetadata.getPrimitiveValue();
// A bit of a loophole so the hands get raised - set the target ID to its own ID
dirtyMetadata.put(EntityDataTypes.TARGET_EID, ((xd & 4) == 4) ? geyserId : 0);
+
+ if ((xd & 4) == 4) {
+ ItemDefinition bow = session.getItemMappings().getStoredItems().bow().getBedrockDefinition();
+ setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, this.hand.getDefinition() == bow || this.offhand.getDefinition() == bow);
+ } else {
+ setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, false);
+ }
+ }
+
+ @Override
+ public boolean useArmSwingAttack() {
+ return true;
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java
index 5f2647b7a..9258cd3b8 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java
@@ -25,11 +25,14 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
+import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import java.util.UUID;
@@ -38,6 +41,16 @@ public class BasePiglinEntity extends MonsterEntity {
public BasePiglinEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
+ // Both TARGET_EID and BLOCK are needed for melee attack animation
+ dirtyMetadata.put(EntityDataTypes.BLOCK, session.getBlockMappings().getDefinition(1));
+ setFlag(EntityFlag.SHAKING, isShaking());
+ }
+
+ @Override
+ public void setMobFlags(ByteEntityMetadata entityMetadata) {
+ super.setMobFlags(entityMetadata);
+ byte xd = entityMetadata.getPrimitiveValue();
+ dirtyMetadata.put(EntityDataTypes.TARGET_EID, (xd & 4) == 4 ? session.getPlayerEntity().getGeyserId() : 0);
}
public void setImmuneToZombification(BooleanEntityMetadata entityMetadata) {
@@ -50,4 +63,9 @@ public class BasePiglinEntity extends MonsterEntity {
protected boolean isShaking() {
return (!isImmuneToZombification && !session.getDimensionType().piglinSafe()) || super.isShaking();
}
+
+ @Override
+ public boolean useArmSwingAttack() {
+ return true;
+ }
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BlazeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BlazeEntity.java
index 43d78f468..5b26d7bd1 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BlazeEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BlazeEntity.java
@@ -25,11 +25,11 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BoggedEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BoggedEntity.java
new file mode 100644
index 000000000..806d58ed1
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BoggedEntity.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.entity.type.living.monster;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.cloudburstmc.math.vector.Vector3f;
+import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
+import org.geysermc.geyser.entity.EntityDefinition;
+import org.geysermc.geyser.inventory.GeyserItemStack;
+import org.geysermc.geyser.item.Items;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.util.InteractionResult;
+import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
+
+import java.util.UUID;
+
+public class BoggedEntity extends AbstractSkeletonEntity {
+ private boolean sheared = false;
+
+ public BoggedEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
+ super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
+ }
+
+ public void setSheared(BooleanEntityMetadata entityMetadata) {
+ this.sheared = entityMetadata.getPrimitiveValue();
+ setFlag(EntityFlag.SHEARED, this.sheared);
+ }
+
+ @Override
+ protected @NonNull InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
+ if (itemInHand.asItem() == Items.SHEARS && readyForShearing()) {
+ return InteractiveTag.SHEAR;
+ }
+ return super.testMobInteraction(hand, itemInHand);
+ }
+
+ @Override
+ protected @NonNull InteractionResult mobInteract(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
+ if (itemInHand.asItem() == Items.SHEARS && readyForShearing()) {
+ return InteractionResult.SUCCESS;
+ }
+ return super.mobInteract(hand, itemInHand);
+ }
+
+ private boolean readyForShearing() {
+ return !this.sheared && this.isAlive();
+ }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BreezeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BreezeEntity.java
new file mode 100644
index 000000000..251a77fb9
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BreezeEntity.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.entity.type.living.monster;
+
+import org.cloudburstmc.math.vector.Vector3f;
+import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
+import org.geysermc.geyser.entity.EntityDefinition;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
+
+import java.util.UUID;
+
+public class BreezeEntity extends MonsterEntity {
+ public BreezeEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
+ super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
+ }
+
+ @Override
+ public void setPose(Pose pose) {
+ // TODO Test
+ setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, pose == Pose.SHOOTING);
+ setFlag(EntityFlag.JUMP_GOAL_JUMP, pose == Pose.INHALING);
+ super.setPose(pose);
+ }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java
index 33ea4e544..5f54d2942 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java
@@ -25,9 +25,6 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
@@ -35,8 +32,12 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
@@ -65,7 +66,7 @@ public class CreeperEntity extends MonsterEntity {
@NonNull
@Override
protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
- if (session.getTagCache().isCreeperIgniter(itemInHand.asItem())) {
+ if (session.getTagCache().is(ItemTag.CREEPER_IGNITERS, itemInHand)) {
return InteractiveTag.IGNITE_CREEPER;
} else {
return super.testMobInteraction(hand, itemInHand);
@@ -75,7 +76,7 @@ public class CreeperEntity extends MonsterEntity {
@NonNull
@Override
protected InteractionResult mobInteract(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) {
- if (session.getTagCache().isCreeperIgniter(itemInHand.asItem())) {
+ if (session.getTagCache().is(ItemTag.CREEPER_IGNITERS, itemInHand)) {
// Ignite creeper - as of 1.19.3
session.playSoundEvent(SoundEvent.IGNITE, position);
return InteractionResult.SUCCESS;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java
index bb09a23f4..0162d498e 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java
@@ -25,23 +25,19 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import lombok.Data;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.ParticleType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
-import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket;
-import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
-import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
-import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket;
-import org.cloudburstmc.protocol.bedrock.packet.SpawnParticleEffectPacket;
+import org.cloudburstmc.protocol.bedrock.packet.*;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Tickable;
import org.geysermc.geyser.entity.type.living.MobEntity;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.DimensionUtils;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.Optional;
import java.util.Random;
@@ -148,11 +144,11 @@ public class EnderDragonEntity extends MobEntity implements Tickable {
}
@Override
- public boolean despawnEntity() {
+ public void despawnEntity() {
for (EnderDragonPartEntity part : allParts) {
part.despawnEntity();
}
- return super.despawnEntity();
+ super.despawnEntity();
}
@Override
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java
index 5b8e23f8b..586ba5cd9 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java
@@ -25,8 +25,6 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
@@ -35,6 +33,8 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GhastEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GhastEntity.java
index f7b9d17b8..984aab642 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GhastEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GhastEntity.java
@@ -25,12 +25,12 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.living.FlyingEntity;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GiantEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GiantEntity.java
index e98c8f120..6bef3ae3e 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GiantEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GiantEntity.java
@@ -26,7 +26,6 @@
package org.geysermc.geyser.entity.type.living.monster;
import org.cloudburstmc.math.vector.Vector3f;
-import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
@@ -36,7 +35,11 @@ public class GiantEntity extends MonsterEntity {
public GiantEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
+ }
- dirtyMetadata.put(EntityDataTypes.SCALE, 6f);
+ @Override
+ protected void initializeMetadata() {
+ super.initializeMetadata();
+ setScale(6f);
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GuardianEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GuardianEntity.java
index 92e50d207..40793522e 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GuardianEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GuardianEntity.java
@@ -25,12 +25,12 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java
index 915e34e79..18b7f6ae1 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java
@@ -25,12 +25,11 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
-import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.living.FlyingEntity;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
@@ -46,7 +45,7 @@ public class PhantomEntity extends FlyingEntity {
setBoundingBoxWidth(boundsScale * definition.width());
setBoundingBoxHeight(boundsScale * definition.height());
- dirtyMetadata.put(EntityDataTypes.SCALE, modelScale);
+ setScale(modelScale);
}
@Override
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java
index 450c546ec..19b6d8e69 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java
@@ -25,18 +25,24 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
+import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
+import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
+import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
+import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import java.util.UUID;
@@ -48,24 +54,72 @@ public class PiglinEntity extends BasePiglinEntity {
public void setBaby(BooleanEntityMetadata entityMetadata) {
boolean isBaby = entityMetadata.getPrimitiveValue();
- dirtyMetadata.put(EntityDataTypes.SCALE, isBaby? .55f : 1f);
+ setScale(isBaby? .55f : 1f);
setFlag(EntityFlag.BABY, isBaby);
updateMountOffset();
}
public void setChargingCrossbow(BooleanEntityMetadata entityMetadata) {
- setFlag(EntityFlag.CHARGING, entityMetadata.getPrimitiveValue());
+ boolean charging = entityMetadata.getPrimitiveValue();
+ setFlag(EntityFlag.CHARGING, charging);
+ dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, charging ? (byte) 64 : (byte) 0); // TODO: gradually increase
}
public void setDancing(BooleanEntityMetadata entityMetadata) {
setFlag(EntityFlag.DANCING, entityMetadata.getPrimitiveValue());
}
+ @Override
+ public void setHand(ItemStack stack) {
+ ItemMapping crossbow = session.getItemMappings().getStoredItems().crossbow();
+ boolean toCrossbow = stack != null && stack.getId() == crossbow.getJavaItem().javaId();
+
+ if (toCrossbow ^ this.hand.getDefinition() == crossbow.getBedrockDefinition()) { // If switching to/from crossbow
+ dirtyMetadata.put(EntityDataTypes.BLOCK, session.getBlockMappings().getDefinition(toCrossbow ? 0 : 1));
+ dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, (byte) 0);
+ setFlag(EntityFlag.CHARGED, false);
+ setFlag(EntityFlag.USING_ITEM, false);
+ updateBedrockMetadata();
+
+ if (this.hand.isValid()) {
+ MobEquipmentPacket mobEquipmentPacket = new MobEquipmentPacket();
+ mobEquipmentPacket.setRuntimeEntityId(geyserId);
+ mobEquipmentPacket.setContainerId(ContainerId.INVENTORY);
+ mobEquipmentPacket.setInventorySlot(0);
+ mobEquipmentPacket.setHotbarSlot(-1);
+ mobEquipmentPacket.setItem(ItemData.AIR);
+ session.sendUpstreamPacket(mobEquipmentPacket);
+ }
+ }
+
+ super.setHand(stack);
+ }
+
+ @Override
+ public void updateMainHand(GeyserSession session) {
+ super.updateMainHand(session);
+
+ if (this.hand.getDefinition() == session.getItemMappings().getStoredItems().crossbow().getBedrockDefinition()) {
+ if (this.hand.getTag() != null && this.hand.getTag().containsKey("chargedItem")) {
+ dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, Byte.MAX_VALUE);
+ setFlag(EntityFlag.CHARGING, false);
+ setFlag(EntityFlag.CHARGED, true);
+ setFlag(EntityFlag.USING_ITEM, true);
+ } else if (getFlag(EntityFlag.CHARGED)) {
+ dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, (byte) 0);
+ setFlag(EntityFlag.CHARGED, false);
+ setFlag(EntityFlag.USING_ITEM, false);
+ }
+ }
+
+ updateBedrockMetadata();
+ }
+
@Override
public void updateOffHand(GeyserSession session) {
// Check if the Piglin is holding Gold and set the ADMIRING flag accordingly so its pose updates
- setFlag(EntityFlag.ADMIRING, session.getTagCache().shouldPiglinAdmire(session.getItemMappings().getMapping(this.offHand).getJavaItem()));
+ setFlag(EntityFlag.ADMIRING, session.getTagCache().is(ItemTag.PIGLIN_LOVED, session.getItemMappings().getMapping(this.offhand).getJavaItem()));
super.updateBedrockMetadata();
super.updateOffHand(session);
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java
index 27dd45f40..aecb4a915 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java
@@ -25,15 +25,15 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.object.Direction;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.living.GolemEntity;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SkeletonEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SkeletonEntity.java
index da11b2759..a6343e256 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SkeletonEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SkeletonEntity.java
@@ -25,11 +25,11 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SpiderEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SpiderEntity.java
index 03e234911..4a4527cef 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SpiderEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SpiderEntity.java
@@ -25,11 +25,11 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/VexEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/VexEntity.java
index 56a0975ae..840f5b3b4 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/VexEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/VexEntity.java
@@ -25,11 +25,11 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WardenEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WardenEntity.java
index 7a0c5e040..2341b8c32 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WardenEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WardenEntity.java
@@ -25,8 +25,6 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.GenericMath;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
@@ -36,6 +34,8 @@ import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Tickable;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.MathUtils;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WitherEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WitherEntity.java
index 3abb7f122..19c1a457b 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WitherEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WitherEntity.java
@@ -25,13 +25,13 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java
index 6e40573ba..3d6e381c7 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java
@@ -25,12 +25,12 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.UUID;
@@ -38,12 +38,13 @@ public class ZoglinEntity extends MonsterEntity {
public ZoglinEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
+ dirtyMetadata.put(EntityDataTypes.TARGET_EID, session.getPlayerEntity().getGeyserId());
}
public void setBaby(BooleanEntityMetadata entityMetadata) {
boolean isBaby = entityMetadata.getPrimitiveValue();
if (isBaby != getFlag(EntityFlag.BABY)) {
- dirtyMetadata.put(EntityDataTypes.SCALE, isBaby ? .55f : 1f);
+ setScale(isBaby ? .55f : 1f);
setFlag(EntityFlag.BABY, isBaby);
updatePassengerOffsets();
@@ -57,7 +58,7 @@ public class ZoglinEntity extends MonsterEntity {
}
@Override
- protected boolean canBeLeashed() {
+ public boolean canBeLeashed() {
return isNotLeashed();
}
@@ -65,4 +66,9 @@ public class ZoglinEntity extends MonsterEntity {
protected boolean isEnemy() {
return true;
}
+
+ @Override
+ public boolean useArmSwingAttack() {
+ return true;
+ }
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java
index af6a30a10..b07afd742 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java
@@ -25,12 +25,11 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
-import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.UUID;
@@ -43,7 +42,7 @@ public class ZombieEntity extends MonsterEntity {
public void setZombieBaby(BooleanEntityMetadata entityMetadata) {
boolean isBaby = entityMetadata.getPrimitiveValue();
- dirtyMetadata.put(EntityDataTypes.SCALE, isBaby ? .55f : 1.0f);
+ setScale(isBaby ? .55f : 1.0f);
setFlag(EntityFlag.BABY, isBaby);
updateMountOffset();
@@ -58,4 +57,9 @@ public class ZombieEntity extends MonsterEntity {
protected boolean isShaking() {
return convertingToDrowned || super.isShaking();
}
+
+ @Override
+ public boolean useArmSwingAttack() {
+ return true;
+ }
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieVillagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieVillagerEntity.java
index 32e45507a..6e03e4f98 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieVillagerEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieVillagerEntity.java
@@ -25,10 +25,6 @@
package org.geysermc.geyser.entity.type.living.monster;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
@@ -40,6 +36,10 @@ import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.VillagerData;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java
index d2f8377d3..fd7448e29 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java
@@ -26,10 +26,13 @@
package org.geysermc.geyser.entity.type.living.monster.raid;
import org.cloudburstmc.math.vector.Vector3f;
+import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
+import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import java.util.UUID;
@@ -39,16 +42,22 @@ public class PillagerEntity extends AbstractIllagerEntity {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}
+ public void setChargingCrossbow(BooleanEntityMetadata entityMetadata) {
+ boolean charging = entityMetadata.getPrimitiveValue();
+ setFlag(EntityFlag.CHARGING, charging);
+ dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, charging ? (byte) 64 : (byte) 0); // TODO: gradually increase
+ }
+
@Override
- public void updateMainHand(GeyserSession session) { //TODO
- checkForCrossbow();
+ public void updateMainHand(GeyserSession session) {
+ updateCrossbow();
super.updateMainHand(session);
}
@Override
public void updateOffHand(GeyserSession session) {
- checkForCrossbow();
+ updateCrossbow();
super.updateOffHand(session);
}
@@ -56,12 +65,27 @@ public class PillagerEntity extends AbstractIllagerEntity {
/**
* Check for a crossbow in either the mainhand or offhand. If one exists, indicate that the pillager should be posing
*/
- protected void checkForCrossbow() {
+ protected void updateCrossbow() {
ItemMapping crossbow = session.getItemMappings().getStoredItems().crossbow();
- boolean hasCrossbow = this.hand.getDefinition() == crossbow.getBedrockDefinition()
- || this.offHand.getDefinition() == crossbow.getBedrockDefinition();
- setFlag(EntityFlag.USING_ITEM, hasCrossbow);
- setFlag(EntityFlag.CHARGED, hasCrossbow);
+ ItemData activeCrossbow = null;
+ if (this.hand.getDefinition() == crossbow.getBedrockDefinition()) {
+ activeCrossbow = this.hand;
+ } else if (this.offhand.getDefinition() == crossbow.getBedrockDefinition()) {
+ activeCrossbow = this.offhand;
+ }
+
+ if (activeCrossbow != null) {
+ if (activeCrossbow.getTag() != null && activeCrossbow.getTag().containsKey("chargedItem")) {
+ dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, Byte.MAX_VALUE);
+ setFlag(EntityFlag.CHARGING, false);
+ setFlag(EntityFlag.CHARGED, true);
+ setFlag(EntityFlag.USING_ITEM, true);
+ } else if (getFlag(EntityFlag.CHARGED)) {
+ dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, (byte) 0);
+ setFlag(EntityFlag.CHARGED, false);
+ setFlag(EntityFlag.USING_ITEM, false);
+ }
+ }
updateBedrockMetadata();
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/RavagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/RavagerEntity.java
new file mode 100644
index 000000000..6190bae10
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/RavagerEntity.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.entity.type.living.monster.raid;
+
+import org.cloudburstmc.math.vector.Vector3f;
+import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
+import org.geysermc.geyser.entity.EntityDefinition;
+import org.geysermc.geyser.session.GeyserSession;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+public class RavagerEntity extends RaidParticipantEntity {
+
+ public RavagerEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
+ super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
+ }
+
+ @Override
+ public boolean useArmSwingAttack() {
+ setFlag(EntityFlag.DELAYED_ATTACK, false);
+ updateBedrockMetadata();
+
+ session.scheduleInEventLoop(() -> {
+ setFlag(EntityFlag.DELAYED_ATTACK, true);
+ updateBedrockMetadata();
+ }, 75, TimeUnit.MILLISECONDS);
+
+ return true;
+ }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/SpellcasterIllagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/SpellcasterIllagerEntity.java
index f083437ae..8d4b3c44e 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/SpellcasterIllagerEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/SpellcasterIllagerEntity.java
@@ -25,13 +25,13 @@
package org.geysermc.geyser.entity.type.living.monster.raid;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import java.util.UUID;
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java
index ad99dda50..a2557e75a 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java
@@ -25,11 +25,12 @@
package org.geysermc.geyser.entity.type.living.monster.raid;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.cloudburstmc.math.vector.Vector3f;
+import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import java.util.UUID;
@@ -37,6 +38,7 @@ public class VindicatorEntity extends AbstractIllagerEntity {
public VindicatorEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
+ dirtyMetadata.put(EntityDataTypes.TARGET_EID, session.getPlayerEntity().getGeyserId());
}
@Override
@@ -46,4 +48,9 @@ public class VindicatorEntity extends AbstractIllagerEntity {
byte xd = entityMetadata.getPrimitiveValue();
setFlag(EntityFlag.ANGRY, (xd & 4) == 4);
}
+
+ @Override
+ public boolean useArmSwingAttack() {
+ return true;
+ }
}
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java
index 9e3888138..4c67b882f 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java
@@ -25,36 +25,27 @@
package org.geysermc.geyser.entity.type.player;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition;
-import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor;
-import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import lombok.Getter;
import lombok.Setter;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
+import org.cloudburstmc.nbt.NbtMap;
+import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.Ability;
import org.cloudburstmc.protocol.bedrock.data.AbilityLayer;
-import org.cloudburstmc.protocol.bedrock.data.AttributeData;
import org.cloudburstmc.protocol.bedrock.data.GameType;
import org.cloudburstmc.protocol.bedrock.data.PlayerPermission;
import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData;
-import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket;
-import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
-import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket;
-import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket;
-import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
+import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
+import org.cloudburstmc.protocol.bedrock.packet.*;
import org.geysermc.geyser.api.entity.type.player.GeyserPlayerEntity;
import org.geysermc.geyser.entity.EntityDefinitions;
+import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.LivingEntity;
import org.geysermc.geyser.entity.type.living.animal.tameable.ParrotEntity;
@@ -63,8 +54,21 @@ import org.geysermc.geyser.scoreboard.Score;
import org.geysermc.geyser.scoreboard.Team;
import org.geysermc.geyser.scoreboard.UpdateType;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.ChunkUtils;
+import org.geysermc.mcprotocollib.protocol.codec.NbtComponentSerializer;
+import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.BlankFormat;
+import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.FixedFormat;
+import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.NumberFormat;
+import org.geysermc.mcprotocollib.protocol.data.game.chat.numbers.StyledFormat;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.ScoreboardPosition;
+import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor;
import java.util.Collections;
import java.util.List;
@@ -163,6 +167,31 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
session.sendUpstreamPacket(addPlayerPacket);
}
+ @Override
+ public void despawnEntity() {
+ super.despawnEntity();
+
+ // Since we re-use player entities: Clear flags, held item, etc
+ this.resetMetadata();
+ this.hand = ItemData.AIR;
+ this.offhand = ItemData.AIR;
+ this.boots = ItemData.AIR;
+ this.leggings = ItemData.AIR;
+ this.chestplate = ItemData.AIR;
+ this.helmet = ItemData.AIR;
+ }
+
+ public void resetMetadata() {
+ // Reset all metadata to their default values
+ // This is used when a player respawns
+ this.flags.clear();
+ this.initializeMetadata();
+
+ // Explicitly reset all metadata not handled by initializeMetadata
+ setParrot(null, true);
+ setParrot(null, false);
+ }
+
public void sendPlayer() {
if (session.getEntityCache().getPlayerEntity(uuid) == null)
return;
@@ -283,7 +312,7 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
attributesPacket.setRuntimeEntityId(geyserId);
// Setting to a higher maximum since plugins/datapacks can probably extend the Bedrock soft limit
attributesPacket.setAttributes(Collections.singletonList(
- new AttributeData("minecraft:absorption", 0.0f, 1024f, entityMetadata.getPrimitiveValue(), 0.0f)));
+ GeyserAttributeType.ABSORPTION.getAttribute(entityMetadata.getPrimitiveValue())));
session.sendUpstreamPacket(attributesPacket);
}
@@ -295,11 +324,11 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
dirtyMetadata.put(EntityDataTypes.MARK_VARIANT, ~entityMetadata.getPrimitiveValue() & 0xff);
}
- public void setLeftParrot(EntityMetadata entityMetadata) {
+ public void setLeftParrot(EntityMetadata entityMetadata) {
setParrot(entityMetadata.getValue(), true);
}
- public void setRightParrot(EntityMetadata entityMetadata) {
+ public void setRightParrot(EntityMetadata entityMetadata) {
setParrot(entityMetadata.getValue(), false);
}
@@ -307,7 +336,7 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
* Sets the parrot occupying the shoulder. Bedrock Edition requires a full entity whereas Java Edition just
* spawns it from the NBT data provided
*/
- private void setParrot(CompoundTag tag, boolean isLeft) {
+ protected void setParrot(NbtMap tag, boolean isLeft) {
if (tag != null && !tag.isEmpty()) {
if ((isLeft && leftParrot != null) || (!isLeft && rightParrot != null)) {
// No need to update a parrot's data when it already exists
@@ -317,7 +346,7 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
ParrotEntity parrot = new ParrotEntity(session, 0, session.getEntityCache().getNextEntityId().incrementAndGet(),
null, EntityDefinitions.PARROT, position, motion, getYaw(), getPitch(), getHeadYaw());
parrot.spawnEntity();
- parrot.getDirtyMetadata().put(EntityDataTypes.VARIANT, (Integer) tag.get("Variant").getValue());
+ parrot.getDirtyMetadata().put(EntityDataTypes.VARIANT, (Integer) tag.get("Variant"));
// Different position whether the parrot is left or right
float offset = isLeft ? 0.4f : -0.4f;
parrot.getDirtyMetadata().put(EntityDataTypes.SEAT_OFFSET, Vector3f.from(offset, -0.22, -0.1));
@@ -414,14 +443,36 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
public void setBelowNameText(Objective objective) {
if (objective != null && objective.getUpdateType() != UpdateType.REMOVE) {
- int amount;
Score score = objective.getScores().get(username);
+ String numberString;
+ NumberFormat numberFormat;
+ int amount;
if (score != null) {
- amount = score.getCurrentData().getScore();
+ amount = score.getScore();
+ numberFormat = score.getNumberFormat();
+ if (numberFormat == null) {
+ numberFormat = objective.getNumberFormat();
+ }
} else {
amount = 0;
+ numberFormat = objective.getNumberFormat();
}
- String displayString = amount + " " + objective.getDisplayName();
+
+ if (numberFormat instanceof BlankFormat) {
+ numberString = "";
+ } else if (numberFormat instanceof FixedFormat fixedFormat) {
+ numberString = MessageTranslator.convertMessage(fixedFormat.getValue());
+ } else if (numberFormat instanceof StyledFormat styledFormat) {
+ NbtMapBuilder styledAmount = styledFormat.getStyle().toBuilder();
+ styledAmount.putString("text", String.valueOf(amount));
+
+ numberString = MessageTranslator.convertJsonMessage(
+ NbtComponentSerializer.tagComponentToJson(styledAmount.build()).toString(), session.locale());
+ } else {
+ numberString = String.valueOf(amount);
+ }
+
+ String displayString = numberString + " " + ChatColor.RESET + objective.getDisplayName();
if (valid) {
// Already spawned - we still need to run the rest of this code because the spawn packet will be
@@ -430,13 +481,22 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
packet.setRuntimeEntityId(geyserId);
packet.getMetadata().put(EntityDataTypes.SCORE, displayString);
session.sendUpstreamPacket(packet);
+ } else {
+ // Not spawned yet, store score value in dirtyMetadata to be picked up by #spawnEntity
+ dirtyMetadata.put(EntityDataTypes.SCORE, displayString);
+ }
+ } else {
+ if (valid) {
+ SetEntityDataPacket packet = new SetEntityDataPacket();
+ packet.setRuntimeEntityId(geyserId);
+ packet.getMetadata().put(EntityDataTypes.SCORE, "");
+ session.sendUpstreamPacket(packet);
+ } else {
+ // Not spawned yet, store score value in dirtyMetadata to be picked up by #spawnEntity
+ dirtyMetadata.put(EntityDataTypes.SCORE, "");
}
- } else if (valid) {
- SetEntityDataPacket packet = new SetEntityDataPacket();
- packet.setRuntimeEntityId(geyserId);
- packet.getMetadata().put(EntityDataTypes.SCORE, "");
- session.sendUpstreamPacket(packet);
}
+
}
/**
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java
index 751a24871..31eb02984 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java
@@ -25,12 +25,6 @@
package org.geysermc.geyser.entity.type.player;
-import com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute;
-import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.GlobalPos;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
-import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
import lombok.Getter;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -41,9 +35,17 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
import org.geysermc.geyser.entity.attribute.GeyserAttributeType;
import org.geysermc.geyser.item.Items;
+import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.AttributeUtils;
import org.geysermc.geyser.util.DimensionUtils;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.Attribute;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.GlobalPos;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
import java.util.Collections;
import java.util.List;
@@ -59,16 +61,14 @@ public class SessionPlayerEntity extends PlayerEntity {
*/
@Getter
protected final Map attributes = new Object2ObjectOpenHashMap<>();
- /**
- * Whether to check for updated speed after all entity metadata has been processed
- */
- private boolean refreshSpeed = false;
/**
* Used in PlayerInputTranslator for movement checks.
*/
@Getter
private boolean isRidingInFront;
+ private int lastAirSupply = getMaxAir();
+
public SessionPlayerEntity(GeyserSession session) {
super(session, -1, 1, null, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, null, null);
@@ -119,9 +119,7 @@ public class SessionPlayerEntity extends PlayerEntity {
// TODO: proper fix, BDS somehow does it? https://paste.gg/p/anonymous/3adfb7612f1540be80fa03a2281f93dc (BDS 1.20.13)
if (!this.session.getGameMode().equals(GameMode.SPECTATOR)) {
super.setFlags(entityMetadata);
- session.setSwimmingInWater((entityMetadata.getPrimitiveValue() & 0x10) == 0x10 && getFlag(EntityFlag.SPRINTING));
}
- refreshSpeed = true;
}
/**
@@ -149,7 +147,6 @@ public class SessionPlayerEntity extends PlayerEntity {
public void setPose(Pose pose) {
super.setPose(pose);
session.setPose(pose);
- refreshSpeed = true;
}
public float getMaxHealth() {
@@ -166,7 +163,13 @@ public class SessionPlayerEntity extends PlayerEntity {
@Override
protected void setAirSupply(int amount) {
- if (amount == getMaxAir()) {
+ // Seemingly required to be sent as of Bedrock 1.21. Otherwise, bubbles will appear as empty
+ // Also, this changes how the air bubble graphics/sounds are presented. Breathing on means sound effects and
+ // the bubbles visually pop
+ setFlag(EntityFlag.BREATHING, amount >= this.lastAirSupply);
+ this.lastAirSupply = amount;
+
+ if (amount == getMaxAir() && GameProtocol.isPre1_21_0(session)) {
super.setAirSupply(0); // Hide the bubble counter from the UI for the player
} else {
super.setAirSupply(amount);
@@ -198,21 +201,6 @@ public class SessionPlayerEntity extends PlayerEntity {
}
}
- @Override
- public void updateBedrockMetadata() {
- super.updateBedrockMetadata();
- if (refreshSpeed) {
- AttributeData speedAttribute = session.adjustSpeed();
- if (speedAttribute != null) {
- UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
- attributesPacket.setRuntimeEntityId(geyserId);
- attributesPacket.setAttributes(Collections.singletonList(speedAttribute));
- session.sendUpstreamPacket(attributesPacket);
- }
- refreshSpeed = false;
- }
- }
-
@Override
protected void updateAttribute(Attribute javaAttribute, List newAttributes) {
if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_ATTACK_SPEED) {
@@ -225,17 +213,6 @@ public class SessionPlayerEntity extends PlayerEntity {
@Override
protected AttributeData calculateAttribute(Attribute javaAttribute, GeyserAttributeType type) {
AttributeData attributeData = super.calculateAttribute(javaAttribute, type);
-
- if (javaAttribute.getType() == AttributeType.Builtin.GENERIC_MOVEMENT_SPEED) {
- session.setOriginalSpeedAttribute(attributeData.getValue());
- AttributeData speedAttribute = session.adjustSpeed();
- if (speedAttribute != null) {
- // Overwrite the attribute with our own
- this.attributes.put(type, speedAttribute);
- return speedAttribute;
- }
- }
-
this.attributes.put(type, attributeData);
return attributeData;
}
@@ -243,7 +220,7 @@ public class SessionPlayerEntity extends PlayerEntity {
public void setLastDeathPosition(@Nullable GlobalPos pos) {
if (pos != null) {
dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_POS, pos.getPosition());
- dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(pos.getDimension()));
+ dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(pos.getDimension().asString()));
dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, true);
} else {
dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, false);
@@ -255,13 +232,45 @@ public class SessionPlayerEntity extends PlayerEntity {
return session.getAuthData().uuid();
}
+ @Override
+ public void setAbsorptionHearts(FloatEntityMetadata entityMetadata) {
+ // The bedrock client can glitch when sending a health and absorption attribute in the same tick
+ // This can happen when switching servers. Resending the absorption attribute fixes the issue
+ attributes.put(GeyserAttributeType.ABSORPTION, GeyserAttributeType.ABSORPTION.getAttribute(entityMetadata.getPrimitiveValue()));
+ super.setAbsorptionHearts(entityMetadata);
+ }
+
+ @Override
public void resetMetadata() {
- // Reset all metadata to their default values
- // This is used when a player respawns
- this.initializeMetadata();
+ super.resetMetadata();
// Reset air
this.resetAir();
+
+ // Absorption is metadata in java edition
+ attributes.remove(GeyserAttributeType.ABSORPTION);
+ UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
+ attributesPacket.setRuntimeEntityId(geyserId);
+ attributesPacket.setAttributes(Collections.singletonList(
+ GeyserAttributeType.ABSORPTION.getAttribute(0f)));
+ session.sendUpstreamPacket(attributesPacket);
+
+ dirtyMetadata.put(EntityDataTypes.EFFECT_COLOR, 0);
+ dirtyMetadata.put(EntityDataTypes.EFFECT_AMBIENCE, (byte) 0);
+ dirtyMetadata.put(EntityDataTypes.FREEZING_EFFECT_STRENGTH, 0f);
+
+ silent = false;
+ }
+
+ public void resetAttributes() {
+ attributes.clear();
+ maxHealth = GeyserAttributeType.MAX_HEALTH.getDefaultValue();
+
+ UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket();
+ attributesPacket.setRuntimeEntityId(geyserId);
+ attributesPacket.setAttributes(Collections.singletonList(
+ GeyserAttributeType.MOVEMENT_SPEED.getAttribute()));
+ session.sendUpstreamPacket(attributesPacket);
}
public void resetAir() {
diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java
index 939e4721d..f2f93b266 100644
--- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java
+++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java
@@ -25,6 +25,7 @@
package org.geysermc.geyser.entity.type.player;
+import lombok.Getter;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.GameType;
@@ -33,8 +34,10 @@ import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket;
-import lombok.Getter;
-import org.geysermc.geyser.level.block.BlockStateValues;
+import org.geysermc.geyser.level.block.property.Properties;
+import org.geysermc.geyser.level.block.type.BlockState;
+import org.geysermc.geyser.level.block.type.WallSkullBlock;
+import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.SkullCache;
import org.geysermc.geyser.skin.SkullSkinManager;
@@ -137,20 +140,19 @@ public class SkullPlayerEntity extends PlayerEntity {
float z = skull.getPosition().getZ() + .5f;
float rotation;
- int blockState = skull.getBlockState();
- byte floorRotation = BlockStateValues.getSkullRotation(blockState);
- if (floorRotation == -1) {
- // Wall skull
+ BlockState blockState = skull.getBlockState();
+ if (blockState.block() instanceof WallSkullBlock) {
y += 0.25f;
- rotation = BlockStateValues.getSkullWallDirections().get(blockState);
- switch ((int) rotation) {
- case 180 -> z += 0.24f; // North
- case 0 -> z -= 0.24f; // South
- case 90 -> x += 0.24f; // West
- case 270 -> x -= 0.24f; // East
+ Direction direction = blockState.getValue(Properties.HORIZONTAL_FACING);
+ rotation = WallSkullBlock.getDegrees(direction);
+ switch (direction) {
+ case NORTH -> z += 0.24f;
+ case SOUTH -> z -= 0.24f;
+ case WEST -> x += 0.24f;
+ case EAST -> x -= 0.24f;
}
} else {
- rotation = (180f + (floorRotation * 22.5f)) % 360;
+ rotation = (180f + (blockState.getValue(Properties.ROTATION_16) * 22.5f)) % 360;
}
moveAbsolute(Vector3f.from(x, y, z), rotation, 0, rotation, true, true);
diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java
index 3ae458f63..c8cbe384b 100644
--- a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java
+++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java
@@ -25,14 +25,13 @@
package org.geysermc.geyser.erosion;
-import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValueType;
-import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import io.netty.channel.Channel;
+import it.unimi.dsi.fastutil.Pair;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
-import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
-import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
+import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
import lombok.Getter;
import lombok.Setter;
import org.cloudburstmc.math.vector.Vector3i;
@@ -45,12 +44,16 @@ import org.geysermc.erosion.packet.backendbound.BackendboundInitializePacket;
import org.geysermc.erosion.packet.backendbound.BackendboundPacket;
import org.geysermc.erosion.packet.geyserbound.*;
import org.geysermc.geyser.level.block.BlockStateValues;
+import org.geysermc.geyser.level.block.property.Properties;
+import org.geysermc.geyser.level.block.type.Block;
+import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.network.GameProtocol;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.PistonCache;
import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity;
import org.geysermc.geyser.util.BlockEntityUtils;
+import org.geysermc.mcprotocollib.protocol.data.game.level.block.value.PistonValueType;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
@@ -64,7 +67,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke
@Setter
private CompletableFuture pendingBatchLookup = null;
@Setter
- private CompletableFuture pickBlockLookup = null;
+ private CompletableFuture> pickBlockLookup = null;
private final AtomicInteger nextTransactionId = new AtomicInteger(1);
@@ -120,7 +123,7 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke
}
CompletableFuture future = this.asyncPendingLookups.remove(transactionId);
if (future != null) {
- future.complete(BlockStateValues.JAVA_AIR_ID);
+ future.complete(Block.JAVA_AIR_ID);
}
}
@@ -134,28 +137,29 @@ public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacke
placeBlockSoundPacket.setIdentifier(":");
session.sendUpstreamPacket(placeBlockSoundPacket);
session.setLastBlockPlacePosition(null);
- session.setLastBlockPlacedId(null);
+ session.setLastBlockPlaced(null);
}
@Override
public void handlePickBlock(GeyserboundPickBlockPacket packet) {
if (this.pickBlockLookup != null) {
- this.pickBlockLookup.complete(packet.getTag());
+ this.pickBlockLookup.complete(packet.getComponents());
}
}
@Override
public void handlePistonEvent(GeyserboundPistonEventPacket packet) {
- Direction orientation = BlockStateValues.getPistonOrientation(packet.getBlockId());
+ Direction orientation = BlockState.of(packet.getBlockId()).getValue(Properties.FACING);
Vector3i position = packet.getPos();
boolean isExtend = packet.isExtend();
var stream = packet.getAttachedBlocks()
.object2IntEntrySet()
.stream()
- .filter(entry -> BlockStateValues.canPistonMoveBlock(entry.getIntValue(), isExtend));
- Object2IntMap attachedBlocks = new Object2IntArrayMap<>();
- stream.forEach(entry -> attachedBlocks.put(entry.getKey(), entry.getIntValue()));
+ .map(entry -> Pair.of(entry.getKey(), BlockState.of(entry.getIntValue())))
+ .filter(pair -> BlockStateValues.canPistonMoveBlock(pair.value(), isExtend));
+ Object2ObjectMap attachedBlocks = new Object2ObjectArrayMap<>();
+ stream.forEach(pair -> attachedBlocks.put(pair.key(), pair.value()));
session.executeInEventLoop(() -> {
PistonCache pistonCache = session.getPistonCache();
diff --git a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java
index 716b763f5..239ffc450 100644
--- a/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java
+++ b/core/src/main/java/org/geysermc/geyser/extension/GeyserExtensionDescription.java
@@ -31,6 +31,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.extension.ExtensionDescription;
import org.geysermc.geyser.api.extension.exception.InvalidDescriptionException;
import org.geysermc.geyser.text.GeyserLocale;
+import org.yaml.snakeyaml.LoaderOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.CustomClassLoaderConstructor;
@@ -48,7 +49,7 @@ public record GeyserExtensionDescription(@NonNull String id,
@NonNull String version,
@NonNull List authors) implements ExtensionDescription {
- private static final Yaml YAML = new Yaml(new CustomClassLoaderConstructor(Source.class.getClassLoader()));
+ private static final Yaml YAML = new Yaml(new CustomClassLoaderConstructor(Source.class.getClassLoader(), new LoaderOptions()));
public static final Pattern ID_PATTERN = Pattern.compile("[a-z][a-z0-9-_]{0,63}");
public static final Pattern NAME_PATTERN = Pattern.compile("^[A-Za-z_.-]+$");
diff --git a/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java b/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java
index 28c881eba..7582502b3 100644
--- a/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java
+++ b/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraData.java
@@ -32,19 +32,24 @@ import org.cloudburstmc.math.vector.Vector2f;
import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.CameraShakeAction;
import org.cloudburstmc.protocol.bedrock.data.CameraShakeType;
+import org.cloudburstmc.protocol.bedrock.data.HudElement;
+import org.cloudburstmc.protocol.bedrock.data.HudVisibility;
import org.cloudburstmc.protocol.bedrock.data.camera.CameraEase;
import org.cloudburstmc.protocol.bedrock.data.camera.CameraFadeInstruction;
import org.cloudburstmc.protocol.bedrock.data.camera.CameraSetInstruction;
import org.cloudburstmc.protocol.bedrock.packet.CameraInstructionPacket;
import org.cloudburstmc.protocol.bedrock.packet.CameraShakePacket;
import org.cloudburstmc.protocol.bedrock.packet.PlayerFogPacket;
-import org.geysermc.geyser.api.bedrock.camera.CameraEaseType;
+import org.cloudburstmc.protocol.bedrock.packet.SetHudPacket;
import org.geysermc.geyser.api.bedrock.camera.CameraData;
+import org.geysermc.geyser.api.bedrock.camera.CameraEaseType;
import org.geysermc.geyser.api.bedrock.camera.CameraFade;
import org.geysermc.geyser.api.bedrock.camera.CameraPerspective;
import org.geysermc.geyser.api.bedrock.camera.CameraPosition;
import org.geysermc.geyser.api.bedrock.camera.CameraShake;
+import org.geysermc.geyser.api.bedrock.camera.GuiElement;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
import java.util.Collections;
import java.util.HashSet;
@@ -53,12 +58,24 @@ import java.util.Set;
import java.util.UUID;
public class GeyserCameraData implements CameraData {
+ private static final HudElement[] HUD_ELEMENT_VALUES = HudElement.values();
+ private static final Set ALL_HUD_ELEMENTS = Set.of(HUD_ELEMENT_VALUES);
+
+ /**
+ * An array of elements to hide when the player is in spectator mode.
+ * Helps with tidying up the GUI; Java-style.
+ */
+ private static final GuiElement[] SPECTATOR_HIDDEN_ELEMENTS = {
+ GuiElement.AIR_BUBBLES_BAR,
+ GuiElement.ARMOR,
+ GuiElement.HEALTH,
+ GuiElement.FOOD_BAR,
+ GuiElement.PROGRESS_BAR,
+ GuiElement.TOOL_TIPS
+ };
private final GeyserSession session;
- @Getter
- private CameraPerspective cameraPerspective;
-
/**
* All fog effects that are currently applied to the client.
*/
@@ -66,6 +83,14 @@ public class GeyserCameraData implements CameraData {
private final Set cameraLockOwners = new HashSet<>();
+ /**
+ * All currently hidden HUD elements
+ */
+ private final Set hiddenHudElements = new HashSet<>();
+
+ @Getter
+ private CameraPerspective cameraPerspective;
+
public GeyserCameraData(GeyserSession session) {
this.session = session;
}
@@ -232,4 +257,67 @@ public class GeyserCameraData implements CameraData {
public boolean isCameraLocked() {
return !this.cameraLockOwners.isEmpty();
}
-}
\ No newline at end of file
+
+ @Override
+ public void hideElement(GuiElement... elements) {
+ Objects.requireNonNull(elements);
+ SetHudPacket packet = new SetHudPacket();
+ packet.setVisibility(HudVisibility.HIDE);
+ Set elementSet = packet.getElements();
+
+ for (GuiElement element : elements) {
+ this.hiddenHudElements.add(element);
+ elementSet.add(HUD_ELEMENT_VALUES[element.id()]);
+ }
+
+ session.sendUpstreamPacket(packet);
+ }
+
+ @Override
+ public void resetElement(GuiElement... elements) {
+ SetHudPacket packet = new SetHudPacket();
+ packet.setVisibility(HudVisibility.RESET);
+ Set elementSet = packet.getElements();
+
+ if (elements != null && elements.length != 0) {
+ for (GuiElement element : elements) {
+ this.hiddenHudElements.remove(element);
+ elementSet.add(HUD_ELEMENT_VALUES[element.id()]);
+ }
+ } else {
+ this.hiddenHudElements.clear();
+ elementSet.addAll(ALL_HUD_ELEMENTS);
+ }
+
+ session.sendUpstreamPacket(packet);
+ }
+
+ @Override
+ public boolean isHudElementHidden(@NonNull GuiElement element) {
+ Objects.requireNonNull(element);
+ return this.hiddenHudElements.contains(element);
+ }
+
+ @Override
+ public @NonNull Set hiddenElements() {
+ return Collections.unmodifiableSet(hiddenHudElements);
+ }
+
+ /**
+ * Deals with hiding hud elements while in spectator.
+ *
+ * @param currentlySpectator whether the player is currently in spectator mode
+ * @param newGameMode the new GameMode to switch to
+ */
+ public void handleGameModeChange(boolean currentlySpectator, GameMode newGameMode) {
+ if (newGameMode == GameMode.SPECTATOR) {
+ if (!currentlySpectator) {
+ hideElement(SPECTATOR_HIDDEN_ELEMENTS);
+ }
+ } else {
+ if (currentlySpectator) {
+ resetElement(SPECTATOR_HIDDEN_ELEMENTS);
+ }
+ }
+ }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraFade.java b/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraFade.java
index 648e70c81..f69504545 100644
--- a/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraFade.java
+++ b/core/src/main/java/org/geysermc/geyser/impl/camera/GeyserCameraFade.java
@@ -29,7 +29,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.common.value.qual.IntRange;
import org.geysermc.geyser.api.bedrock.camera.CameraFade;
-import java.awt.Color;
+import java.awt.*;
import java.util.Objects;
public record GeyserCameraFade(
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java
index 9e0b83768..45a062468 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java
@@ -25,8 +25,9 @@
package org.geysermc.geyser.inventory;
-import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
-import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket;
+import net.kyori.adventure.text.Component;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
+import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket;
import lombok.Getter;
import lombok.Setter;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -72,9 +73,9 @@ public class AnvilContainer extends Container {
String correctRename;
newName = rename;
- String originalName = ItemUtils.getCustomName(getInput().getNbt());
+ Component originalName = ItemUtils.getCustomName(getInput().getComponents());
- String plainOriginalName = MessageTranslator.convertToPlainTextLenient(originalName, session.locale());
+ String plainOriginalName = MessageTranslator.convertToPlainText(originalName, session.locale());
String plainNewName = MessageTranslator.convertToPlainText(rename);
if (!plainOriginalName.equals(plainNewName)) {
// Strip out formatting since Java Edition does not allow it
@@ -84,7 +85,7 @@ public class AnvilContainer extends Container {
session.sendDownstreamGamePacket(renameItemPacket);
} else {
// Restore formatting for item since we're not renaming
- correctRename = MessageTranslator.convertMessageLenient(originalName);
+ correctRename = originalName != null ? MessageTranslator.convertMessage(originalName, session.locale()) : "";
// Java Edition sends the original custom name when not renaming,
// if there isn't a custom name an empty string is sent
ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(plainOriginalName);
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/BeaconContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/BeaconContainer.java
index 7644ada73..1b59772fa 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/BeaconContainer.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/BeaconContainer.java
@@ -25,7 +25,7 @@
package org.geysermc.geyser.inventory;
-import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
import lombok.Getter;
import lombok.Setter;
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/CartographyContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/CartographyContainer.java
index 72f1088c3..ace3f93ad 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/CartographyContainer.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/CartographyContainer.java
@@ -25,7 +25,7 @@
package org.geysermc.geyser.inventory;
-import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
public class CartographyContainer extends Container {
public CartographyContainer(String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory) {
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Container.java b/core/src/main/java/org/geysermc/geyser/inventory/Container.java
index 79fa67da1..e78a4d2c6 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/Container.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/Container.java
@@ -25,7 +25,8 @@
package org.geysermc.geyser.inventory;
-import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
+import org.geysermc.geyser.level.block.type.Block;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
import lombok.Getter;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.session.GeyserSession;
@@ -37,7 +38,7 @@ import org.jetbrains.annotations.Range;
*/
@Getter
public class Container extends Inventory {
- private final PlayerInventory playerInventory;
+ protected final PlayerInventory playerInventory;
private final int containerSize;
/**
@@ -83,9 +84,9 @@ public class Container extends Inventory {
* Will be overwritten for droppers.
*
* @param usingRealBlock whether this container is using a real container or not
- * @param javaBlockId the Java block string of the block, if real
+ * @param block the Java block, if real
*/
- public void setUsingRealBlock(boolean usingRealBlock, String javaBlockId) {
+ public void setUsingRealBlock(boolean usingRealBlock, Block block) {
isUsingRealBlock = usingRealBlock;
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/CrafterContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/CrafterContainer.java
index bcacd3587..fb118252d 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/CrafterContainer.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/CrafterContainer.java
@@ -25,13 +25,19 @@
package org.geysermc.geyser.inventory;
-import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.translator.inventory.CrafterInventoryTranslator;
+import org.geysermc.geyser.translator.inventory.InventoryTranslator;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
import lombok.Getter;
import lombok.Setter;
import org.geysermc.geyser.GeyserImpl;
+import org.jetbrains.annotations.Range;
@Getter
public class CrafterContainer extends Container {
+ private GeyserItemStack resultItem = GeyserItemStack.EMPTY;
@Setter
private boolean triggered = false;
@@ -46,8 +52,36 @@ public class CrafterContainer extends Container {
super(title, id, size, containerType, playerInventory);
}
+ @Override
+ public GeyserItemStack getItem(int slot) {
+ if (slot == CrafterInventoryTranslator.JAVA_RESULT_SLOT) {
+ return this.resultItem;
+ } else if (isCraftingGrid(slot)) {
+ return super.getItem(slot);
+ } else {
+ return playerInventory.getItem(slot - CrafterInventoryTranslator.GRID_SIZE + InventoryTranslator.PLAYER_INVENTORY_OFFSET);
+ }
+ }
+
+ @Override
+ public int getOffsetForHotbar(@Range(from = 0, to = 8) int slot) {
+ return playerInventory.getOffsetForHotbar(slot) - InventoryTranslator.PLAYER_INVENTORY_OFFSET + CrafterInventoryTranslator.GRID_SIZE;
+ }
+
+ @Override
+ public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) {
+ if (slot == CrafterInventoryTranslator.JAVA_RESULT_SLOT) {
+ // Result item probably won't be an item that needs to worry about net ID or lodestone compasses
+ this.resultItem = newItem;
+ } else if (isCraftingGrid(slot)) {
+ super.setItem(slot, newItem, session);
+ } else {
+ playerInventory.setItem(slot - CrafterInventoryTranslator.GRID_SIZE + InventoryTranslator.PLAYER_INVENTORY_OFFSET, newItem, session);
+ }
+ }
+
public void setSlot(int slot, boolean enabled) {
- if (slot < 0 || slot > 8) {
+ if (!isCraftingGrid(slot)) {
GeyserImpl.getInstance().getLogger().warning("Crafter slot out of bounds: " + slot);
return;
}
@@ -58,4 +92,8 @@ public class CrafterContainer extends Container {
disabledSlotsMask = (short) (disabledSlotsMask | (1 << slot));
}
}
+
+ private static boolean isCraftingGrid(int slot) {
+ return slot >= 0 && slot <= 8;
+ }
}
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/EnchantingContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/EnchantingContainer.java
index ac55aae60..08397ab44 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/EnchantingContainer.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/EnchantingContainer.java
@@ -25,7 +25,7 @@
package org.geysermc.geyser.inventory;
-import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantOptionData;
import lombok.Getter;
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java b/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java
index 6518dce7c..0b14d1105 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java
@@ -25,10 +25,12 @@
package org.geysermc.geyser.inventory;
-import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
import lombok.Getter;
+import org.geysermc.geyser.level.block.Blocks;
+import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.Generic3X3InventoryTranslator;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
public class Generic3X3Container extends Container {
/**
@@ -44,10 +46,10 @@ public class Generic3X3Container extends Container {
}
@Override
- public void setUsingRealBlock(boolean usingRealBlock, String javaBlockId) {
- super.setUsingRealBlock(usingRealBlock, javaBlockId);
+ public void setUsingRealBlock(boolean usingRealBlock, Block block) {
+ super.setUsingRealBlock(usingRealBlock, block);
if (usingRealBlock) {
- isDropper = javaBlockId.startsWith("minecraft:dropper");
+ isDropper = block == Blocks.DROPPER;
}
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/GeyserEnchantOption.java b/core/src/main/java/org/geysermc/geyser/inventory/GeyserEnchantOption.java
index 23365e392..de0bd7300 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserEnchantOption.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserEnchantOption.java
@@ -25,12 +25,11 @@
package org.geysermc.geyser.inventory;
+import lombok.Getter;
import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantData;
import org.cloudburstmc.protocol.bedrock.data.inventory.EnchantOptionData;
-import lombok.Getter;
import org.geysermc.geyser.session.GeyserSession;
-import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -44,13 +43,13 @@ public class GeyserEnchantOption {
* is controlled by the server.
* So, of course, we have to throw in some easter eggs. ;)
*/
- private static final List ENCHANT_NAMES = Arrays.asList("tougher armor", "lukeeey", "fall better",
- "explode less", "camo toy", "breathe better", "rtm five one six", "armor stab", "water walk", "you are elsa",
- "tim two zero three", "fast walk nether", "davchoo", "oof ouch owie", "enemy on fire", "spider sad", "aj ferguson", "redned",
- "more items thx", "long sword reach", "fast tool", "give me block", "less breaky break", "cube craft",
- "strong arrow", "fist arrow", "spicy arrow", "many many arrows", "geyser", "come here fish", "i like this",
- "stabby stab", "supreme mortal", "avatar i guess", "more arrows", "fly finder seventeen", "in and out",
- "xp heals tools", "dragon proxy waz here");
+ private static final List ENCHANT_NAMES = List.of("tougher armor", "lukeeey", "fall better",
+ "explode less", "camo toy", "armor stab", "breathe better", "water walk", "rtm five one six", "oof ouch owie",
+ "enemy on fire", "spider sad", "aj ferguson", "redned", "more items thx", "fast tool", "give me block",
+ "less breaky break", "cube craft", "strong arrow", "fist arrow", "spicy arrow", "many many arrows", "geyser",
+ "come here fish", "you are elsa", "xp heals tools", "tim two zero three", "dragon proxy waz here",
+ "stabby stab", "supreme mortal", "i like this", "avatar i guess", "more arrows", "in and out",
+ "fly finder seventeen", "fast walk nether", "davchoo", "onechris", "death bringer thirteen", "kastle");
@Getter
private final int javaIndex;
@@ -62,7 +61,6 @@ public class GeyserEnchantOption {
private boolean hasChanged;
private int xpCost = 0;
- private int javaEnchantIndex = -1;
private int bedrockEnchantIndex = -1;
private int enchantLevel = -1;
@@ -74,7 +72,7 @@ public class GeyserEnchantOption {
this.hasChanged = false;
return new EnchantOptionData(xpCost, javaIndex + 16, EMPTY,
enchantLevel == -1 ? EMPTY : Collections.singletonList(new EnchantData(bedrockEnchantIndex, enchantLevel)), EMPTY,
- javaEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(javaEnchantIndex), enchantLevel == -1 ? 0 : session.getNextItemNetId());
+ bedrockEnchantIndex == -1 ? "unknown" : ENCHANT_NAMES.get(bedrockEnchantIndex), enchantLevel == -1 ? 0 : session.getNextItemNetId());
}
public boolean hasChanged() {
@@ -88,10 +86,9 @@ public class GeyserEnchantOption {
}
}
- public void setEnchantIndex(int javaEnchantIndex, int bedrockEnchantIndex) {
- if (this.javaEnchantIndex != javaEnchantIndex) {
+ public void setEnchantIndex(int bedrockEnchantIndex) {
+ if (this.bedrockEnchantIndex != bedrockEnchantIndex) {
hasChanged = true;
- this.javaEnchantIndex = javaEnchantIndex;
this.bedrockEnchantIndex = bedrockEnchantIndex;
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java
index 4ff8db9f0..744ad70b6 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java
@@ -25,12 +25,7 @@
package org.geysermc.geyser.inventory;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
-import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
-import lombok.AccessLevel;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
+import lombok.*;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
@@ -39,7 +34,12 @@ import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
-import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
+import org.geysermc.geyser.translator.item.ItemTranslator;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
+
+import java.util.HashMap;
@Data
public class GeyserItemStack {
@@ -47,26 +47,34 @@ public class GeyserItemStack {
private final int javaId;
private int amount;
- private CompoundTag nbt;
+ private DataComponents components;
private int netId;
- @Getter(AccessLevel.NONE)
+ @Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE)
@EqualsAndHashCode.Exclude
private Item item;
- private GeyserItemStack(int javaId, int amount, CompoundTag nbt) {
- this(javaId, amount, nbt, 1);
+ private GeyserItemStack(int javaId, int amount, DataComponents components) {
+ this(javaId, amount, components, 1);
}
- private GeyserItemStack(int javaId, int amount, CompoundTag nbt, int netId) {
+ private GeyserItemStack(int javaId, int amount, DataComponents components, int netId) {
this.javaId = javaId;
this.amount = amount;
- this.nbt = nbt;
+ this.components = components;
this.netId = netId;
}
+ public static @NonNull GeyserItemStack of(int javaId, int amount) {
+ return of(javaId, amount, null);
+ }
+
+ public static @NonNull GeyserItemStack of(int javaId, int amount, @Nullable DataComponents components) {
+ return new GeyserItemStack(javaId, amount, components);
+ }
+
public static @NonNull GeyserItemStack from(@Nullable ItemStack itemStack) {
- return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getNbt());
+ return itemStack == null ? EMPTY : new GeyserItemStack(itemStack.getId(), itemStack.getAmount(), itemStack.getDataComponents());
}
public int getJavaId() {
@@ -77,8 +85,48 @@ public class GeyserItemStack {
return isEmpty() ? 0 : amount;
}
- public @Nullable CompoundTag getNbt() {
- return isEmpty() ? null : nbt;
+ public @Nullable DataComponents getComponents() {
+ return isEmpty() ? null : components;
+ }
+
+ @NonNull
+ public DataComponents getOrCreateComponents() {
+ if (components == null) {
+ return components = new DataComponents(new HashMap<>());
+ }
+ return components;
+ }
+
+ @Nullable
+ public T getComponent(@NonNull DataComponentType type) {
+ if (components == null) {
+ return null;
+ }
+ return components.get(type);
+ }
+
+ public boolean getComponent(@NonNull DataComponentType type, boolean def) {
+ if (components == null) {
+ return def;
+ }
+
+ Boolean result = components.get(type);
+ if (result != null) {
+ return result;
+ }
+ return def;
+ }
+
+ public int getComponent(@NonNull DataComponentType type, int def) {
+ if (components == null) {
+ return def;
+ }
+
+ Integer result = components.get(type);
+ if (result != null) {
+ return result;
+ }
+ return def;
}
public int getNetId() {
@@ -98,14 +146,14 @@ public class GeyserItemStack {
}
public @Nullable ItemStack getItemStack(int newAmount) {
- return isEmpty() ? null : new ItemStack(javaId, newAmount, nbt);
+ return isEmpty() ? null : new ItemStack(javaId, newAmount, components);
}
public ItemData getItemData(GeyserSession session) {
if (isEmpty()) {
return ItemData.AIR;
}
- ItemData.Builder itemData = ItemTranslator.translateToBedrock(session, javaId, amount, nbt);
+ ItemData.Builder itemData = ItemTranslator.translateToBedrock(session, javaId, amount, components);
itemData.netId(getNetId());
itemData.usingNetId(true);
return itemData.build();
@@ -131,6 +179,6 @@ public class GeyserItemStack {
}
public GeyserItemStack copy(int newAmount) {
- return isEmpty() ? EMPTY : new GeyserItemStack(javaId, newAmount, nbt == null ? null : nbt.clone(), netId);
+ return isEmpty() ? EMPTY : new GeyserItemStack(javaId, newAmount, components == null ? null : components.clone(), netId);
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java
index 3376d6c26..09d04f17c 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java
@@ -25,20 +25,18 @@
package org.geysermc.geyser.inventory;
-import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
-import com.github.steveice10.opennbt.tag.builtin.ByteTag;
-import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
-import com.github.steveice10.opennbt.tag.builtin.Tag;
-import org.checkerframework.checker.nullness.qual.NonNull;
-import org.cloudburstmc.math.vector.Vector3i;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
-import org.geysermc.geyser.translator.inventory.item.ItemTranslator;
+import org.geysermc.geyser.translator.item.ItemTranslator;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
import org.jetbrains.annotations.Range;
import java.util.Arrays;
@@ -137,12 +135,9 @@ public abstract class Inventory {
// Lodestone caching
if (newItem.asItem() == Items.COMPASS) {
- CompoundTag nbt = newItem.getNbt();
- if (nbt != null) {
- Tag lodestoneTag = nbt.get("LodestoneTracked");
- if (lodestoneTag instanceof ByteTag) {
- session.getLodestoneCache().cacheInventoryItem(newItem);
- }
+ var tracker = newItem.getComponent(DataComponentType.LODESTONE_TRACKER);
+ if (tracker != null) {
+ session.getLodestoneCache().cacheInventoryItem(newItem, tracker);
}
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java
index f5aa7b0d6..389611c67 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java
@@ -25,11 +25,14 @@
package org.geysermc.geyser.inventory;
-import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
-import org.cloudburstmc.math.vector.Vector3i;
import lombok.Getter;
import lombok.Setter;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.translator.protocol.java.inventory.JavaOpenBookTranslator;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
public class LecternContainer extends Container {
@Getter @Setter
@@ -39,7 +42,34 @@ public class LecternContainer extends Container {
@Getter @Setter
private Vector3i position;
+ // Sigh. When the lectern container is created, we don't know (yet) if it's fake or not.
+ // So... time for a manual check :/
+ @Getter
+ private boolean isFakeLectern = false;
+
public LecternContainer(String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory) {
super(title, id, size, containerType, playerInventory);
}
+
+ /**
+ * When we are using a fake lectern, the Java server expects us to still be in a player inventory.
+ * We can't use {@link #isUsingRealBlock()} as that may not be determined yet.
+ */
+ @Override
+ public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) {
+ if (isFakeLectern) {
+ session.getPlayerInventory().setItem(slot, newItem, session);
+ } else {
+ super.setItem(slot, newItem, session);
+ }
+ }
+
+ /**
+ * This is used ONLY once to set the book of a fake lectern in {@link JavaOpenBookTranslator}.
+ * See {@link LecternContainer#setItem(int, GeyserItemStack, GeyserSession)} as for why this is separate.
+ */
+ public void setFakeLecternBook(GeyserItemStack book, GeyserSession session) {
+ this.isFakeLectern = true;
+ super.setItem(0, book, session);
+ }
}
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java
index 105b5ca5b..0bfa6d1a7 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java
@@ -25,14 +25,14 @@
package org.geysermc.geyser.inventory;
-import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
-import com.github.steveice10.mc.protocol.data.game.inventory.VillagerTrade;
-import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundMerchantOffersPacket;
import lombok.Getter;
import lombok.Setter;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.VillagerTrade;
+import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundMerchantOffersPacket;
public class MerchantContainer extends Container {
@Getter @Setter
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java b/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java
index bda09a4ed..9bef4b08e 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java
@@ -25,12 +25,12 @@
package org.geysermc.geyser.inventory;
-import com.github.steveice10.mc.protocol.data.game.entity.player.Hand;
import lombok.Getter;
import lombok.Setter;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.jetbrains.annotations.Range;
public class PlayerInventory extends Inventory {
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java
index f99a0c71e..269a4fb7d 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java
@@ -25,7 +25,7 @@
package org.geysermc.geyser.inventory;
-import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
import lombok.Getter;
import lombok.Setter;
import org.checkerframework.checker.nullness.qual.NonNull;
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java b/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java
index d7068920e..6897786c1 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java
@@ -25,7 +25,7 @@
package org.geysermc.geyser.inventory.click;
-import com.github.steveice10.mc.protocol.data.game.inventory.*;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.*;
import lombok.AllArgsConstructor;
@AllArgsConstructor
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java
index f31f6d82f..53b02ef88 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java
@@ -25,11 +25,11 @@
package org.geysermc.geyser.inventory.click;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
-import com.github.steveice10.mc.protocol.data.game.inventory.ContainerActionType;
-import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType;
-import com.github.steveice10.mc.protocol.data.game.inventory.MoveToHotbarAction;
-import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerActionType;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.ContainerType;
+import org.geysermc.mcprotocollib.protocol.data.game.inventory.MoveToHotbarAction;
+import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket;
import it.unimi.dsi.fastutil.ints.*;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.Inventory;
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java
index 135e1057f..cdda4fe4c 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java
@@ -32,13 +32,15 @@ import org.cloudburstmc.protocol.bedrock.packet.BlockEntityDataPacket;
import org.cloudburstmc.protocol.bedrock.packet.ContainerClosePacket;
import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
+import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.Container;
import org.geysermc.geyser.inventory.Inventory;
+import org.geysermc.geyser.inventory.LecternContainer;
+import org.geysermc.geyser.level.block.type.Block;
+import org.geysermc.geyser.level.block.type.BlockState;
import org.geysermc.geyser.registry.BlockRegistries;
-import org.geysermc.geyser.registry.type.BlockMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
-import org.geysermc.geyser.util.BlockUtils;
import org.geysermc.geyser.util.InventoryUtils;
import java.util.Collections;
@@ -53,20 +55,24 @@ public class BlockInventoryHolder extends InventoryHolder {
/**
* The default Java block ID to translate as a fake block
*/
- private final int defaultJavaBlockState;
+ private final BlockState defaultJavaBlockState;
private final ContainerType containerType;
- private final Set validBlocks;
+ private final Set validBlocks;
- public BlockInventoryHolder(String javaBlockIdentifier, ContainerType containerType, String... validBlocks) {
- this.defaultJavaBlockState = BlockRegistries.JAVA_IDENTIFIER_TO_ID.get().getInt(javaBlockIdentifier);
+ public BlockInventoryHolder(Block defaultJavaBlock, ContainerType containerType, Block... validBlocks) {
+ this(defaultJavaBlock.defaultBlockState(), containerType, validBlocks);
+ }
+
+ public BlockInventoryHolder(BlockState defaultJavaBlockState, ContainerType containerType, Block... validBlocks) {
+ this.defaultJavaBlockState = defaultJavaBlockState;
this.containerType = containerType;
if (validBlocks != null) {
- Set validBlocksTemp = new HashSet<>(validBlocks.length + 1);
+ Set validBlocksTemp = new HashSet<>(validBlocks.length + 1);
Collections.addAll(validBlocksTemp, validBlocks);
- validBlocksTemp.add(BlockUtils.getCleanIdentifier(javaBlockIdentifier));
+ validBlocksTemp.add(defaultJavaBlockState.block());
this.validBlocks = Set.copyOf(validBlocksTemp);
} else {
- this.validBlocks = Collections.singleton(BlockUtils.getCleanIdentifier(javaBlockIdentifier));
+ this.validBlocks = Collections.singleton(defaultJavaBlockState.block());
}
}
@@ -78,14 +84,13 @@ public class BlockInventoryHolder extends InventoryHolder {
if (checkInteractionPosition(session)) {
// Then, check to see if the interacted block is valid for this inventory by ensuring the block state identifier is valid
// and the bedrock block is vanilla
- int javaBlockId = session.getGeyser().getWorldManager().getBlockAt(session, session.getLastInteractionBlockPosition());
- if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(javaBlockId)) {
- String[] javaBlockString = BlockRegistries.JAVA_BLOCKS.getOrDefault(javaBlockId, BlockMapping.DEFAULT).getJavaIdentifier().split("\\[");
- if (isValidBlock(javaBlockString)) {
+ BlockState state = session.getGeyser().getWorldManager().blockAt(session, session.getLastInteractionBlockPosition());
+ if (!BlockRegistries.CUSTOM_BLOCK_STATE_OVERRIDES.get().containsKey(state.javaId())) {
+ if (isValidBlock(state)) {
// We can safely use this block
inventory.setHolderPosition(session.getLastInteractionBlockPosition());
- ((Container) inventory).setUsingRealBlock(true, javaBlockString[0]);
- setCustomName(session, session.getLastInteractionBlockPosition(), inventory, javaBlockId);
+ ((Container) inventory).setUsingRealBlock(true, state.block());
+ setCustomName(session, session.getLastInteractionBlockPosition(), inventory, state);
return true;
}
@@ -123,11 +128,11 @@ public class BlockInventoryHolder extends InventoryHolder {
/**
* @return true if this Java block ID can be used for player inventory.
*/
- protected boolean isValidBlock(String[] javaBlockString) {
- return this.validBlocks.contains(javaBlockString[0]);
+ protected boolean isValidBlock(BlockState blockState) {
+ return this.validBlocks.contains(blockState.block());
}
- protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, int javaBlockState) {
+ protected void setCustomName(GeyserSession session, Vector3i position, Inventory inventory, BlockState javaBlockState) {
NbtMap tag = NbtMap.builder()
.putInt("x", position.getX())
.putInt("y", position.getY())
@@ -151,13 +156,28 @@ public class BlockInventoryHolder extends InventoryHolder {
@Override
public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) {
- if (((Container) inventory).isUsingRealBlock()) {
- // No need to reset a block since we didn't change any blocks
- // But send a container close packet because we aren't destroying the original.
- ContainerClosePacket packet = new ContainerClosePacket();
- packet.setId((byte) inventory.getBedrockId());
- packet.setServerInitiated(true);
- session.sendUpstreamPacket(packet);
+ if (inventory instanceof Container container) {
+ if (container.isUsingRealBlock() && !(inventory instanceof LecternContainer)) {
+ // No need to reset a block since we didn't change any blocks
+ // But send a container close packet because we aren't destroying the original.
+ ContainerClosePacket packet = new ContainerClosePacket();
+ packet.setId((byte) inventory.getBedrockId());
+ packet.setServerInitiated(true);
+ packet.setType(ContainerType.CONTAINER);
+ session.sendUpstreamPacket(packet);
+ return;
+ }
+ } else {
+ GeyserImpl.getInstance().getLogger().warning("Tried to close a non-container inventory in a block inventory holder! ");
+ if (GeyserImpl.getInstance().getLogger().isDebug()) {
+ GeyserImpl.getInstance().getLogger().debug("Current inventory: " + inventory);
+ GeyserImpl.getInstance().getLogger().debug("Open inventory: " + session.getOpenInventory());
+ }
+ // Try to save ourselves? maybe?
+ // https://github.com/GeyserMC/Geyser/issues/4141
+ // TODO: improve once this issue is pinned down properly
+ session.setOpenInventory(null);
+ session.setInventoryTranslator(InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR);
return;
}
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java b/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java
new file mode 100644
index 000000000..743fbdc7e
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/inventory/item/BannerPattern.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.inventory.item;
+
+import lombok.Getter;
+import net.kyori.adventure.key.Key;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.geysermc.geyser.util.MinecraftKey;
+
+import java.util.Locale;
+
+@Getter
+public enum BannerPattern {
+ BASE("b"),
+ SQUARE_BOTTOM_LEFT("bl"),
+ SQUARE_BOTTOM_RIGHT("br"),
+ SQUARE_TOP_LEFT("tl"),
+ SQUARE_TOP_RIGHT("tr"),
+ STRIPE_BOTTOM("bs"),
+ STRIPE_TOP("ts"),
+ STRIPE_LEFT("ls"),
+ STRIPE_RIGHT("rs"),
+ STRIPE_CENTER("cs"),
+ STRIPE_MIDDLE("ms"),
+ STRIPE_DOWNRIGHT("drs"),
+ STRIPE_DOWNLEFT("dls"),
+ SMALL_STRIPES("ss"),
+ CROSS("cr"),
+ STRAIGHT_CROSS("sc"),
+ TRIANGLE_BOTTOM("bt"),
+ TRIANGLE_TOP("tt"),
+ TRIANGLES_BOTTOM("bts"),
+ TRIANGLES_TOP("tts"),
+ DIAGONAL_LEFT("ld"),
+ DIAGONAL_UP_RIGHT("rd"),
+ DIAGONAL_UP_LEFT("lud"),
+ DIAGONAL_RIGHT("rud"),
+ CIRCLE("mc"),
+ RHOMBUS("mr"),
+ HALF_VERTICAL("vh"),
+ HALF_HORIZONTAL("hh"),
+ HALF_VERTICAL_RIGHT("vhr"),
+ HALF_HORIZONTAL_BOTTOM("hhb"),
+ BORDER("bo"),
+ CURLY_BORDER("cbo"),
+ GRADIENT("gra"),
+ GRADIENT_UP("gru"),
+ BRICKS("bri"),
+ GLOBE("glb"),
+ CREEPER("cre"),
+ SKULL("sku"),
+ FLOWER("flo"),
+ MOJANG("moj"),
+ PIGLIN("pig"),
+ FLOW("flw"),
+ GUSTER("gus");
+
+ private static final BannerPattern[] VALUES = values();
+
+ private final Key javaIdentifier;
+ private final String bedrockIdentifier;
+
+ BannerPattern(String bedrockIdentifier) {
+ this.javaIdentifier = MinecraftKey.key(this.name().toLowerCase(Locale.ROOT));
+ this.bedrockIdentifier = bedrockIdentifier;
+ }
+
+ public static @Nullable BannerPattern getByJavaIdentifier(Key key) {
+ for (BannerPattern bannerPattern : VALUES) {
+ if (bannerPattern.javaIdentifier.equals(key)) {
+ return bannerPattern;
+ }
+ }
+ return null;
+ }
+
+ public static @Nullable BannerPattern getByBedrockIdentifier(String bedrockIdentifier) {
+ for (BannerPattern bannerPattern : VALUES) {
+ if (bannerPattern.bedrockIdentifier.equals(bedrockIdentifier)) {
+ return bannerPattern;
+ }
+ }
+ return null;
+ }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/Enchantment.java b/core/src/main/java/org/geysermc/geyser/inventory/item/BedrockEnchantment.java
similarity index 50%
rename from core/src/main/java/org/geysermc/geyser/inventory/item/Enchantment.java
rename to core/src/main/java/org/geysermc/geyser/inventory/item/BedrockEnchantment.java
index 5fa2a5784..6d3fdbc27 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/item/Enchantment.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/item/BedrockEnchantment.java
@@ -25,13 +25,11 @@
package org.geysermc.geyser.inventory.item;
-import lombok.Getter;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Locale;
-@Getter
-public enum Enchantment {
+public enum BedrockEnchantment {
PROTECTION,
FIRE_PROTECTION,
FEATHER_FALLING,
@@ -69,18 +67,21 @@ public enum Enchantment {
PIERCING,
QUICK_CHARGE,
SOUL_SPEED,
- SWIFT_SNEAK;
+ SWIFT_SNEAK,
+ WIND_BURST,
+ DENSITY,
+ BREACH;
- private static final Enchantment[] VALUES = values();
+ private static final BedrockEnchantment[] VALUES = values();
private final String javaIdentifier;
- Enchantment() {
+ BedrockEnchantment() {
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH);
}
- public static @Nullable Enchantment getByJavaIdentifier(String javaIdentifier) {
- for (Enchantment enchantment : VALUES) {
+ public static @Nullable BedrockEnchantment getByJavaIdentifier(String javaIdentifier) {
+ for (BedrockEnchantment enchantment : VALUES) {
if (enchantment.javaIdentifier.equals(javaIdentifier) || enchantment.name().toLowerCase(Locale.ENGLISH).equalsIgnoreCase(javaIdentifier)) {
return enchantment;
}
@@ -88,85 +89,10 @@ public enum Enchantment {
return null;
}
- public static @Nullable Enchantment getByBedrockId(int bedrockId) {
+ public static @Nullable BedrockEnchantment getByBedrockId(int bedrockId) {
if (bedrockId >= 0 && bedrockId < VALUES.length) {
return VALUES[bedrockId];
}
return null;
}
-
- /**
- * Enchantments classified by their Java index
- */
- public enum JavaEnchantment {
- PROTECTION,
- FIRE_PROTECTION,
- FEATHER_FALLING,
- BLAST_PROTECTION,
- PROJECTILE_PROTECTION,
- RESPIRATION,
- AQUA_AFFINITY,
- THORNS,
- DEPTH_STRIDER,
- FROST_WALKER,
- BINDING_CURSE,
- SOUL_SPEED,
- SWIFT_SNEAK,
- SHARPNESS,
- SMITE,
- BANE_OF_ARTHROPODS,
- KNOCKBACK,
- FIRE_ASPECT,
- LOOTING,
- SWEEPING,
- EFFICIENCY,
- SILK_TOUCH,
- UNBREAKING,
- FORTUNE,
- POWER,
- PUNCH,
- FLAME,
- INFINITY,
- LUCK_OF_THE_SEA,
- LURE,
- LOYALTY,
- IMPALING,
- RIPTIDE,
- CHANNELING,
- MULTISHOT,
- QUICK_CHARGE,
- PIERCING,
- MENDING,
- VANISHING_CURSE;
-
- private static final JavaEnchantment[] VALUES = JavaEnchantment.values();
-
- public static JavaEnchantment of(int index) {
- return VALUES[index];
- }
-
- /**
- * A list of all enchantment Java identifiers for use with command suggestions.
- */
- public static final String[] ALL_JAVA_IDENTIFIERS;
-
- public static @Nullable JavaEnchantment getByJavaIdentifier(String javaIdentifier) {
- if (!javaIdentifier.startsWith("minecraft:")) {
- javaIdentifier = "minecraft:" + javaIdentifier;
- }
- for (int i = 0; i < ALL_JAVA_IDENTIFIERS.length; i++) {
- if (ALL_JAVA_IDENTIFIERS[i].equalsIgnoreCase(javaIdentifier)) {
- return VALUES[i];
- }
- }
- return null;
- }
-
- static {
- ALL_JAVA_IDENTIFIERS = new String[VALUES.length];
- for (int i = 0; i < ALL_JAVA_IDENTIFIERS.length; i++) {
- ALL_JAVA_IDENTIFIERS[i] = "minecraft:" + VALUES[i].name().toLowerCase(Locale.ENGLISH);
- }
- }
- }
}
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/DyeColor.java b/core/src/main/java/org/geysermc/geyser/inventory/item/DyeColor.java
new file mode 100644
index 000000000..e2649a343
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/inventory/item/DyeColor.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.inventory.item;
+
+import lombok.Getter;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+import java.util.Locale;
+
+@Getter
+public enum DyeColor {
+ WHITE,
+ ORANGE,
+ MAGENTA,
+ LIGHT_BLUE,
+ YELLOW,
+ LIME,
+ PINK,
+ GRAY,
+ LIGHT_GRAY,
+ CYAN,
+ PURPLE,
+ BLUE,
+ BROWN,
+ GREEN,
+ RED,
+ BLACK;
+
+ private static final DyeColor[] VALUES = values();
+
+ private final String javaIdentifier;
+
+ DyeColor() {
+ this.javaIdentifier = this.name().toLowerCase(Locale.ROOT);
+ }
+
+ public static @Nullable DyeColor getById(int id) {
+ if (id >= 0 && id < VALUES.length) {
+ return VALUES[id];
+ }
+ return null;
+ }
+
+ public static @Nullable DyeColor getByJavaIdentifier(String javaIdentifier) {
+ for (DyeColor dyeColor : VALUES) {
+ if (dyeColor.javaIdentifier.equals(javaIdentifier)) {
+ return dyeColor;
+ }
+ }
+ return null;
+ }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/Potion.java b/core/src/main/java/org/geysermc/geyser/inventory/item/Potion.java
index 7ce0ee278..129c365a9 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/item/Potion.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/item/Potion.java
@@ -27,65 +27,82 @@ package org.geysermc.geyser.inventory.item;
import lombok.Getter;
import org.checkerframework.checker.nullness.qual.Nullable;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents;
+import java.util.Collections;
import java.util.Locale;
@Getter
public enum Potion {
- WATER(0),
- MUNDANE(1),
- THICK(3),
- AWKWARD(4),
- NIGHT_VISION(5),
- LONG_NIGHT_VISION(6),
- INVISIBILITY(7),
- LONG_INVISIBILITY(8),
- LEAPING(9),
- STRONG_LEAPING(11),
- LONG_LEAPING(10),
- FIRE_RESISTANCE(12),
- LONG_FIRE_RESISTANCE(13),
- SWIFTNESS(14),
- STRONG_SWIFTNESS(16),
- LONG_SWIFTNESS(15),
- SLOWNESS(17),
- STRONG_SLOWNESS(42),
- LONG_SLOWNESS(18),
- WATER_BREATHING(19),
- LONG_WATER_BREATHING(20),
- HEALING(21),
- STRONG_HEALING(22),
- HARMING(23),
- STRONG_HARMING(24),
- POISON(25),
- STRONG_POISON(27),
- LONG_POISON(26),
- REGENERATION(28),
- STRONG_REGENERATION(30),
- LONG_REGENERATION(29),
- STRENGTH(31),
- STRONG_STRENGTH(33),
- LONG_STRENGTH(32),
- WEAKNESS(34),
- LONG_WEAKNESS(35),
- LUCK(2), //does not exist
- TURTLE_MASTER(37),
- STRONG_TURTLE_MASTER(39),
- LONG_TURTLE_MASTER(38),
- SLOW_FALLING(40),
- LONG_SLOW_FALLING(41);
+ WATER(0, ArrowParticleColors.NONE),
+ MUNDANE(1, ArrowParticleColors.NONE), // 2 is extended?
+ THICK(3, ArrowParticleColors.NONE),
+ AWKWARD(4, ArrowParticleColors.NONE),
+ NIGHT_VISION(5, ArrowParticleColors.NIGHT_VISION),
+ LONG_NIGHT_VISION(6, ArrowParticleColors.NIGHT_VISION),
+ INVISIBILITY(7, ArrowParticleColors.INVISIBILITY),
+ LONG_INVISIBILITY(8, ArrowParticleColors.INVISIBILITY),
+ LEAPING(9, ArrowParticleColors.LEAPING),
+ LONG_LEAPING(10, ArrowParticleColors.LEAPING),
+ STRONG_LEAPING(11, ArrowParticleColors.LEAPING),
+ FIRE_RESISTANCE(12, ArrowParticleColors.FIRE_RESISTANCE),
+ LONG_FIRE_RESISTANCE(13, ArrowParticleColors.FIRE_RESISTANCE),
+ SWIFTNESS(14, ArrowParticleColors.SWIFTNESS),
+ LONG_SWIFTNESS(15, ArrowParticleColors.SWIFTNESS),
+ STRONG_SWIFTNESS(16, ArrowParticleColors.SWIFTNESS),
+ SLOWNESS(17, ArrowParticleColors.SLOWNESS),
+ LONG_SLOWNESS(18, ArrowParticleColors.SLOWNESS),
+ STRONG_SLOWNESS(42, ArrowParticleColors.SLOWNESS),
+ TURTLE_MASTER(37, ArrowParticleColors.TURTLE_MASTER),
+ LONG_TURTLE_MASTER(38, ArrowParticleColors.TURTLE_MASTER),
+ STRONG_TURTLE_MASTER(39, ArrowParticleColors.TURTLE_MASTER),
+ WATER_BREATHING(19, ArrowParticleColors.WATER_BREATHING),
+ LONG_WATER_BREATHING(20, ArrowParticleColors.WATER_BREATHING),
+ HEALING(21, ArrowParticleColors.HEALING),
+ STRONG_HEALING(22, ArrowParticleColors.HEALING),
+ HARMING(23, ArrowParticleColors.HARMING),
+ STRONG_HARMING(24, ArrowParticleColors.HARMING),
+ POISON(25, ArrowParticleColors.POISON),
+ LONG_POISON(26, ArrowParticleColors.POISON),
+ STRONG_POISON(27, ArrowParticleColors.POISON),
+ REGENERATION(28, ArrowParticleColors.REGENERATION),
+ LONG_REGENERATION(29, ArrowParticleColors.REGENERATION),
+ STRONG_REGENERATION(30, ArrowParticleColors.REGENERATION),
+ STRENGTH(31, ArrowParticleColors.STRENGTH),
+ LONG_STRENGTH(32, ArrowParticleColors.STRENGTH),
+ STRONG_STRENGTH(33, ArrowParticleColors.STRENGTH),
+ WEAKNESS(34, ArrowParticleColors.WEAKNESS),
+ LONG_WEAKNESS(35, ArrowParticleColors.WEAKNESS),
+ LUCK(2, ArrowParticleColors.NONE), // does not exist in Bedrock
+ SLOW_FALLING(40, ArrowParticleColors.SLOW_FALLING),
+ LONG_SLOW_FALLING(41, ArrowParticleColors.SLOW_FALLING),
+ WIND_CHARGING(43, ArrowParticleColors.WIND_CHARGING),
+ WEAVING(44, ArrowParticleColors.WEAVING),
+ OOZING(45, ArrowParticleColors.OOZING),
+ INFESTATION(46, ArrowParticleColors.INFESTATION);
public static final Potion[] VALUES = values();
private final String javaIdentifier;
private final short bedrockId;
+ private final int javaColor;
- Potion(int bedrockId) {
+ Potion(int bedrockId, int javaColor) {
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH);
this.bedrockId = (short) bedrockId;
+ this.javaColor = javaColor;
}
- public static @Nullable Potion getByJavaIdentifier(String javaIdentifier) {
+ public int tippedArrowId() {
+ // +1 likely to offset 0 as nothing?
+ return this.bedrockId + 1;
+ }
+
+ public PotionContents toComponent() {
+ return new PotionContents(this.ordinal(), -1, Collections.emptyList());
+ }
+
+ public static Potion getByJavaIdentifier(String javaIdentifier) {
for (Potion potion : VALUES) {
if (potion.javaIdentifier.equals(javaIdentifier)) {
return potion;
@@ -94,6 +111,13 @@ public enum Potion {
return null;
}
+ public static @Nullable Potion getByJavaId(int javaId) {
+ if (javaId >= 0 && javaId < VALUES.length) {
+ return VALUES[javaId];
+ }
+ return null;
+ }
+
public static @Nullable Potion getByBedrockId(int bedrockId) {
for (Potion potion : VALUES) {
if (potion.bedrockId == bedrockId) {
@@ -102,4 +126,44 @@ public enum Potion {
}
return null;
}
+
+ public static @Nullable Potion getByTippedArrowDamage(int bedrockId) {
+ return getByBedrockId(bedrockId - 1);
+ }
+
+ public static byte toTippedArrowId(int javaParticleColor) {
+ for (Potion potion : VALUES) {
+ if (potion.javaColor == javaParticleColor) {
+ return (byte) (potion.bedrockId + 1);
+ }
+ }
+ return (byte) 0;
+ }
+
+ /**
+ * For tipped arrow usage
+ */
+ private static final class ArrowParticleColors {
+ static final int NONE = 1;
+ static final int NIGHT_VISION = 2039713;
+ static final int INVISIBILITY = 8356754;
+ static final int LEAPING = 2293580;
+ static final int FIRE_RESISTANCE = 14981690;
+ static final int SWIFTNESS = 8171462;
+ static final int SLOWNESS = 5926017;
+ static final int TURTLE_MASTER = 7691106;
+ static final int WATER_BREATHING = 3035801;
+ static final int HEALING = 16262179;
+ static final int HARMING = 4393481;
+ static final int POISON = 5149489;
+ static final int REGENERATION = 13458603;
+ static final int STRENGTH = 9643043;
+ static final int WEAKNESS = 4738376;
+ static final int LUCK = 3381504;
+ static final int SLOW_FALLING = 16773073;
+ static final int WIND_CHARGING = 12438015;
+ static final int WEAVING = 7891290;
+ static final int OOZING = 10092451;
+ static final int INFESTATION = 9214860;
+ }
}
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java
index 6bb786896..05f6ba6cc 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java
@@ -40,9 +40,9 @@ import java.util.Map;
@Getter
@Accessors(fluent = true)
public class StoredItemMappings {
- private final ItemMapping bamboo;
private final ItemMapping banner;
private final ItemMapping barrier;
+ private final ItemMapping bow;
private final ItemMapping compass;
private final ItemMapping crossbow;
private final ItemMapping egg;
@@ -53,11 +53,12 @@ public class StoredItemMappings {
private final ItemMapping upgradeTemplate;
private final ItemMapping wheat;
private final ItemMapping writableBook;
+ private final ItemMapping writtenBook;
public StoredItemMappings(Map itemMappings) {
- this.bamboo = load(itemMappings, Items.BAMBOO);
this.banner = load(itemMappings, Items.WHITE_BANNER); // As of 1.17.10, all banners have the same Bedrock ID
this.barrier = load(itemMappings, Items.BARRIER);
+ this.bow = load(itemMappings, Items.BOW);
this.compass = load(itemMappings, Items.COMPASS);
this.crossbow = load(itemMappings, Items.CROSSBOW);
this.egg = load(itemMappings, Items.EGG);
@@ -68,6 +69,7 @@ public class StoredItemMappings {
this.upgradeTemplate = load(itemMappings, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE);
this.wheat = load(itemMappings, Items.WHEAT);
this.writableBook = load(itemMappings, Items.WRITABLE_BOOK);
+ this.writtenBook = load(itemMappings, Items.WRITTEN_BOOK);
}
@NonNull
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java b/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java
deleted file mode 100644
index 3ba0ad56f..000000000
--- a/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- * @author GeyserMC
- * @link https://github.com/GeyserMC/Geyser
- */
-
-package org.geysermc.geyser.inventory.item;
-
-import lombok.Getter;
-import org.checkerframework.checker.nullness.qual.Nullable;
-
-import java.util.Locale;
-
-/**
- * Potion identifiers and their respective Bedrock IDs used with arrows.
- * See here
- */
-@Getter
-public enum TippedArrowPotion {
- MUNDANE(2, ArrowParticleColors.NONE), // 3 is extended?
- THICK(4, ArrowParticleColors.NONE),
- AWKWARD(5, ArrowParticleColors.NONE),
- NIGHT_VISION(6, ArrowParticleColors.NIGHT_VISION),
- LONG_NIGHT_VISION(7, ArrowParticleColors.NIGHT_VISION),
- INVISIBILITY(8, ArrowParticleColors.INVISIBILITY),
- LONG_INVISIBILITY(9, ArrowParticleColors.INVISIBILITY),
- LEAPING(10, ArrowParticleColors.LEAPING),
- LONG_LEAPING(11, ArrowParticleColors.LEAPING),
- STRONG_LEAPING(12, ArrowParticleColors.LEAPING),
- FIRE_RESISTANCE(13, ArrowParticleColors.FIRE_RESISTANCE),
- LONG_FIRE_RESISTANCE(14, ArrowParticleColors.FIRE_RESISTANCE),
- SWIFTNESS(15, ArrowParticleColors.SWIFTNESS),
- LONG_SWIFTNESS(16, ArrowParticleColors.SWIFTNESS),
- STRONG_SWIFTNESS(17, ArrowParticleColors.SWIFTNESS),
- SLOWNESS(18, ArrowParticleColors.SLOWNESS),
- LONG_SLOWNESS(19, ArrowParticleColors.SLOWNESS),
- STRONG_SLOWNESS(43, ArrowParticleColors.SLOWNESS),
- WATER_BREATHING(20, ArrowParticleColors.WATER_BREATHING),
- LONG_WATER_BREATHING(21, ArrowParticleColors.WATER_BREATHING),
- HEALING(22, ArrowParticleColors.HEALING),
- STRONG_HEALING(23, ArrowParticleColors.HEALING),
- HARMING(24, ArrowParticleColors.HARMING),
- STRONG_HARMING(25, ArrowParticleColors.HARMING),
- POISON(26, ArrowParticleColors.POISON),
- LONG_POISON(27, ArrowParticleColors.POISON),
- STRONG_POISON(28, ArrowParticleColors.POISON),
- REGENERATION(29, ArrowParticleColors.REGENERATION),
- LONG_REGENERATION(30, ArrowParticleColors.REGENERATION),
- STRONG_REGENERATION(31, ArrowParticleColors.REGENERATION),
- STRENGTH(32, ArrowParticleColors.STRENGTH),
- LONG_STRENGTH(33, ArrowParticleColors.STRENGTH),
- STRONG_STRENGTH(34, ArrowParticleColors.STRENGTH),
- WEAKNESS(35, ArrowParticleColors.WEAKNESS),
- LONG_WEAKNESS(36, ArrowParticleColors.WEAKNESS),
- LUCK(2, ArrowParticleColors.NONE), // does not exist in Bedrock
- TURTLE_MASTER(38, ArrowParticleColors.TURTLE_MASTER),
- LONG_TURTLE_MASTER(39, ArrowParticleColors.TURTLE_MASTER),
- STRONG_TURTLE_MASTER(40, ArrowParticleColors.TURTLE_MASTER),
- SLOW_FALLING(41, ArrowParticleColors.SLOW_FALLING),
- LONG_SLOW_FALLING(42, ArrowParticleColors.SLOW_FALLING);
-
- private static final TippedArrowPotion[] VALUES = values();
-
- private final String javaIdentifier;
- private final short bedrockId;
- /**
- * The Java color associated with this ID.
- * Used for looking up Java arrow color entity metadata as Bedrock potion IDs, which is what is used for entities in Bedrock
- */
- private final int javaColor;
-
- TippedArrowPotion(int bedrockId, ArrowParticleColors arrowParticleColor) {
- this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH);
- this.bedrockId = (short) bedrockId;
- this.javaColor = arrowParticleColor.getColor();
- }
-
- public static @Nullable TippedArrowPotion getByJavaIdentifier(String javaIdentifier) {
- for (TippedArrowPotion potion : VALUES) {
- if (potion.javaIdentifier.equals(javaIdentifier)) {
- return potion;
- }
- }
- return null;
- }
-
- public static @Nullable TippedArrowPotion getByBedrockId(int bedrockId) {
- for (TippedArrowPotion potion : VALUES) {
- if (potion.bedrockId == bedrockId) {
- return potion;
- }
- }
- return null;
- }
-
- /**
- * @param color the potion color to look up
- * @return the tipped arrow potion that most closely resembles that color.
- */
- public static @Nullable TippedArrowPotion getByJavaColor(int color) {
- for (TippedArrowPotion potion : VALUES) {
- if (potion.javaColor == color) {
- return potion;
- }
- }
- return null;
- }
-
- private enum ArrowParticleColors {
- NONE(-1),
- NIGHT_VISION(2039713),
- INVISIBILITY(8356754),
- LEAPING(2293580),
- FIRE_RESISTANCE(14981690),
- SWIFTNESS(8171462),
- SLOWNESS(5926017),
- TURTLE_MASTER(7691106),
- WATER_BREATHING(3035801),
- HEALING(16262179),
- HARMING(4393481),
- POISON(5149489),
- REGENERATION(13458603),
- STRENGTH(9643043),
- WEAKNESS(4738376),
- LUCK(3381504),
- SLOW_FALLING(16773073);
-
- @Getter
- private final int color;
-
- ArrowParticleColors(int color) {
- this.color = color;
- }
- }
-}
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java
index 641d5ad94..8b7fa9522 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java
@@ -25,12 +25,18 @@
package org.geysermc.geyser.inventory.recipe;
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
+
/**
- * A more compact version of {@link com.github.steveice10.mc.protocol.data.game.recipe.Recipe}.
+ * A more compact version of {@link org.geysermc.mcprotocollib.protocol.data.game.recipe.Recipe}.
*/
public interface GeyserRecipe {
/**
* Whether the recipe is flexible or not in which items can be placed where.
*/
boolean isShaped();
+
+ @Nullable
+ ItemStack result();
}
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java
index 05c17cf9f..ac9fa3ab4 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java
@@ -25,10 +25,10 @@
package org.geysermc.geyser.inventory.recipe;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
-import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient;
-import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData;
import org.checkerframework.checker.nullness.qual.Nullable;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
+import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient;
+import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.ShapedRecipeData;
public record GeyserShapedRecipe(int width, int height, Ingredient[] ingredients, @Nullable ItemStack result) implements GeyserRecipe {
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java
index e300e3ec8..388831d4c 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java
@@ -25,9 +25,9 @@
package org.geysermc.geyser.inventory.recipe;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
-import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient;
-import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
+import org.geysermc.mcprotocollib.protocol.data.game.recipe.Ingredient;
+import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.ShapelessRecipeData;
import org.checkerframework.checker.nullness.qual.Nullable;
public record GeyserShapelessRecipe(Ingredient[] ingredients, @Nullable ItemStack result) implements GeyserRecipe {
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java
index 22163eced..7bd21ecfa 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java
@@ -25,7 +25,7 @@
package org.geysermc.geyser.inventory.recipe;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
+import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.checkerframework.checker.nullness.qual.Nullable;
/**
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java
index 584928e65..8289813a4 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/TrimRecipe.java
@@ -25,63 +25,57 @@
package org.geysermc.geyser.inventory.recipe;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.TextColor;
import org.cloudburstmc.protocol.bedrock.data.TrimMaterial;
import org.cloudburstmc.protocol.bedrock.data.TrimPattern;
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemTagDescriptor;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
+import org.geysermc.geyser.registry.type.ItemMapping;
+import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.translator.text.MessageTranslator;
+import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry;
/**
- * Hardcoded recipe information about armor trims until further improvements can be made. This information was scraped
- * from BDS 1.19.81 with a world with the next_major_update and sniffer features enabled, using ProxyPass.
+ * Stores information on trim materials and patterns, including smithing armor hacks for pre-1.20.
*/
-public class TrimRecipe {
-
- // For TrimDataPacket, which BDS sends just before the CraftingDataPacket
- public static final List PATTERNS;
- public static final List MATERIALS;
-
+public final class TrimRecipe {
// For CraftingDataPacket
public static final String ID = "minecraft:smithing_armor_trim";
public static final ItemDescriptorWithCount BASE = tagDescriptor("minecraft:trimmable_armors");
public static final ItemDescriptorWithCount ADDITION = tagDescriptor("minecraft:trim_materials");
public static final ItemDescriptorWithCount TEMPLATE = tagDescriptor("minecraft:trim_templates");
- static {
- List patterns = new ArrayList<>(16);
- patterns.add(new TrimPattern("minecraft:ward_armor_trim_smithing_template", "ward"));
- patterns.add(new TrimPattern("minecraft:sentry_armor_trim_smithing_template", "sentry"));
- patterns.add(new TrimPattern("minecraft:snout_armor_trim_smithing_template", "snout"));
- patterns.add(new TrimPattern("minecraft:dune_armor_trim_smithing_template", "dune"));
- patterns.add(new TrimPattern("minecraft:spire_armor_trim_smithing_template", "spire"));
- patterns.add(new TrimPattern("minecraft:tide_armor_trim_smithing_template", "tide"));
- patterns.add(new TrimPattern("minecraft:wild_armor_trim_smithing_template", "wild"));
- patterns.add(new TrimPattern("minecraft:rib_armor_trim_smithing_template", "rib"));
- patterns.add(new TrimPattern("minecraft:coast_armor_trim_smithing_template", "coast"));
- patterns.add(new TrimPattern("minecraft:shaper_armor_trim_smithing_template", "shaper"));
- patterns.add(new TrimPattern("minecraft:eye_armor_trim_smithing_template", "eye"));
- patterns.add(new TrimPattern("minecraft:vex_armor_trim_smithing_template", "vex"));
- patterns.add(new TrimPattern("minecraft:silence_armor_trim_smithing_template", "silence"));
- patterns.add(new TrimPattern("minecraft:wayfinder_armor_trim_smithing_template", "wayfinder"));
- patterns.add(new TrimPattern("minecraft:raiser_armor_trim_smithing_template", "raiser"));
- patterns.add(new TrimPattern("minecraft:host_armor_trim_smithing_template", "host"));
- PATTERNS = Collections.unmodifiableList(patterns);
+ public static TrimMaterial readTrimMaterial(GeyserSession session, RegistryEntry entry) {
+ String key = entry.getId().asMinimalString();
- List materials = new ArrayList<>(10);
- materials.add(new TrimMaterial("quartz", "§h", "minecraft:quartz"));
- materials.add(new TrimMaterial("iron", "§i", "minecraft:iron_ingot"));
- materials.add(new TrimMaterial("netherite", "§j", "minecraft:netherite_ingot"));
- materials.add(new TrimMaterial("redstone", "§m", "minecraft:redstone"));
- materials.add(new TrimMaterial("copper", "§n", "minecraft:copper_ingot"));
- materials.add(new TrimMaterial("gold", "§p", "minecraft:gold_ingot"));
- materials.add(new TrimMaterial("emerald", "§q", "minecraft:emerald"));
- materials.add(new TrimMaterial("diamond", "§s", "minecraft:diamond"));
- materials.add(new TrimMaterial("lapis", "§t", "minecraft:lapis_lazuli"));
- materials.add(new TrimMaterial("amethyst", "§u", "minecraft:amethyst_shard"));
- MATERIALS = Collections.unmodifiableList(materials);
+ // Color is used when hovering over the item
+ // Find the nearest legacy color from the RGB Java gives us to work with
+ // Also yes this is a COMPLETE hack but it works ok!!!!!
+ String colorTag = entry.getData().getCompound("description").getString("color");
+ TextColor color = TextColor.fromHexString(colorTag);
+ String legacy = MessageTranslator.convertMessage(Component.space().color(color));
+
+ String itemIdentifier = entry.getData().getString("ingredient");
+ ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier);
+ if (itemMapping == null) {
+ // This should never happen so not sure what to do here.
+ itemMapping = ItemMapping.AIR;
+ }
+ // Just pick out the resulting color code, without RESET in front.
+ return new TrimMaterial(key, legacy.substring(2).trim(), itemMapping.getBedrockIdentifier());
+ }
+
+ public static TrimPattern readTrimPattern(GeyserSession session, RegistryEntry entry) {
+ String key = entry.getId().asMinimalString();
+
+ String itemIdentifier = entry.getData().getString("template_item");
+ ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier);
+ if (itemMapping == null) {
+ // This should never happen so not sure what to do here.
+ itemMapping = ItemMapping.AIR;
+ }
+ return new TrimPattern(itemMapping.getBedrockIdentifier(), key);
}
private TrimRecipe() {
diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java
index 5adee0c20..c3ac73372 100644
--- a/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java
+++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java
@@ -25,15 +25,9 @@
package org.geysermc.geyser.inventory.updater;
-import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode;
-import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket;
-import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
-import com.github.steveice10.opennbt.tag.builtin.ListTag;
-import com.github.steveice10.opennbt.tag.builtin.StringTag;
-import com.github.steveice10.opennbt.tag.builtin.Tag;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
-import it.unimi.dsi.fastutil.objects.Object2IntMaps;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
+import net.kyori.adventure.text.Component;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
@@ -43,15 +37,19 @@ import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.AnvilContainer;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.Inventory;
-import org.geysermc.geyser.inventory.item.Enchantment.JavaEnchantment;
+import org.geysermc.geyser.inventory.item.BedrockEnchantment;
+import org.geysermc.geyser.item.enchantment.Enchantment;
import org.geysermc.geyser.item.Items;
-import org.geysermc.geyser.registry.Registries;
-import org.geysermc.geyser.registry.type.EnchantmentData;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.ItemUtils;
+import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemEnchantments;
+import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket;
+import java.util.Map;
import java.util.Objects;
public class AnvilInventoryUpdater extends InventoryUpdater {
@@ -118,7 +116,7 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
// Changing the item in the input slot resets the name field on Bedrock, but
// does not result in a FilterTextPacket
- String originalName = MessageTranslator.convertToPlainTextLenient(ItemUtils.getCustomName(input.getNbt()), session.locale());
+ String originalName = MessageTranslator.convertToPlainText(ItemUtils.getCustomName(input.getComponents()), session.locale());
ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(originalName);
session.sendDownstreamGamePacket(renameItemPacket);
@@ -307,22 +305,22 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
*/
private int calcMergeEnchantmentCost(GeyserSession session, GeyserItemStack input, GeyserItemStack material, boolean bedrock) {
boolean hasCompatible = false;
- Object2IntMap combinedEnchantments = getEnchantments(input, bedrock);
+ Object2IntMap combinedEnchantments = getEnchantments(session, input);
int cost = 0;
- for (Object2IntMap.Entry entry : getEnchantments(material, bedrock).object2IntEntrySet()) {
- JavaEnchantment enchantment = entry.getKey();
- EnchantmentData data = Registries.ENCHANTMENTS.get(enchantment);
- if (data == null) {
- GeyserImpl.getInstance().getLogger().debug("Java enchantment not in registry: " + enchantment);
- continue;
- }
+ for (Object2IntMap.Entry entry : getEnchantments(session, material).object2IntEntrySet()) {
+ Enchantment enchantment = entry.getKey();
- boolean canApply = isEnchantedBook(input) || data.validItems().contains(input.getJavaId());
- for (JavaEnchantment incompatible : data.incompatibleEnchantments()) {
- if (combinedEnchantments.containsKey(incompatible)) {
- canApply = false;
- if (!bedrock) {
- cost++;
+ boolean canApply = isEnchantedBook(input) || session.getTagCache().is(enchantment.supportedItems(), input);
+ var exclusiveSet = enchantment.exclusiveSet();
+ if (exclusiveSet != null) {
+ int[] incompatibleEnchantments = session.getTagCache().get(exclusiveSet);
+ for (int i : incompatibleEnchantments) {
+ Enchantment incompatible = session.getRegistryCache().enchantments().byId(i);
+ if (combinedEnchantments.containsKey(incompatible)) {
+ canApply = false;
+ if (!bedrock) {
+ cost++;
+ }
}
}
}
@@ -334,12 +332,12 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
newLevel++;
}
newLevel = Math.max(currentLevel, newLevel);
- if (newLevel > data.maxLevel()) {
- newLevel = data.maxLevel();
+ if (newLevel > enchantment.maxLevel()) {
+ newLevel = enchantment.maxLevel();
}
combinedEnchantments.put(enchantment, newLevel);
- int rarityMultiplier = data.rarityMultiplier();
+ int rarityMultiplier = enchantment.anvilCost();
if (isEnchantedBook(material) && rarityMultiplier > 1) {
rarityMultiplier /= 2;
}
@@ -347,11 +345,11 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
if (newLevel > currentLevel) {
hasCompatible = true;
}
- if (enchantment == JavaEnchantment.IMPALING) {
+ if (enchantment.bedrockEnchantment() == BedrockEnchantment.IMPALING) {
// Multiplier is halved on Bedrock for some reason
rarityMultiplier /= 2;
- } else if (enchantment == JavaEnchantment.SWEEPING) {
- // Doesn't exist on Bedrock
+ } else if (enchantment.bedrockEnchantment() == null) {
+ // Whatever this is, doesn't exist on Bedrock
rarityMultiplier = 0;
}
cost += rarityMultiplier * (newLevel - currentLevel);
@@ -368,42 +366,26 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
return cost;
}
- private Object2IntMap getEnchantments(GeyserItemStack itemStack, boolean bedrock) {
- if (itemStack.getNbt() == null) {
- return Object2IntMaps.emptyMap();
- }
- Object2IntMap enchantments = new Object2IntOpenHashMap<>();
- Tag enchantmentTag;
+ private Object2IntMap getEnchantments(GeyserSession session, GeyserItemStack itemStack) {
+ ItemEnchantments enchantmentComponent;
if (isEnchantedBook(itemStack)) {
- enchantmentTag = itemStack.getNbt().get("StoredEnchantments");
+ enchantmentComponent = itemStack.getComponent(DataComponentType.STORED_ENCHANTMENTS);
} else {
- enchantmentTag = itemStack.getNbt().get("Enchantments");
+ enchantmentComponent = itemStack.getComponent(DataComponentType.ENCHANTMENTS);
}
- if (enchantmentTag instanceof ListTag listTag) {
- for (Tag tag : listTag.getValue()) {
- if (tag instanceof CompoundTag enchantTag) {
- if (enchantTag.get("id") instanceof StringTag javaEnchId) {
- JavaEnchantment enchantment = JavaEnchantment.getByJavaIdentifier(javaEnchId.getValue());
- if (enchantment == null) {
- GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment in anvil: " + javaEnchId.getValue());
- continue;
- }
-
- Tag javaEnchLvl = enchantTag.get("lvl");
- if (javaEnchLvl == null || !(javaEnchLvl.getValue() instanceof Number number))
- continue;
-
- // Handle duplicate enchantments
- if (bedrock) {
- enchantments.putIfAbsent(enchantment, number.intValue());
- } else {
- enchantments.mergeInt(enchantment, number.intValue(), Math::max);
- }
- }
+ if (enchantmentComponent != null) {
+ Object2IntMap enchantments = new Object2IntOpenHashMap<>();
+ for (Map.Entry entry : enchantmentComponent.getEnchantments().entrySet()) {
+ Enchantment enchantment = session.getRegistryCache().enchantments().byId(entry.getKey());
+ if (enchantment == null) {
+ GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment in anvil: " + entry.getKey());
+ continue;
}
+ enchantments.put(enchantment, entry.getValue().intValue());
}
+ return enchantments;
}
- return enchantments;
+ return new Object2IntOpenHashMap<>();
}
private boolean isEnchantedBook(GeyserItemStack itemStack) {
@@ -424,38 +406,27 @@ public class AnvilInventoryUpdater extends InventoryUpdater {
}
// This should really check the name field in all cases, but that requires the localized name
// of the item which can change depending on NBT and Minecraft Edition
- String originalName = ItemUtils.getCustomName(anvilContainer.getInput().getNbt());
+ Component originalName = ItemUtils.getCustomName(anvilContainer.getInput().getComponents());
if (bedrock && originalName != null && anvilContainer.getNewName() != null) {
// Check text and formatting
- String legacyOriginalName = MessageTranslator.convertMessageLenient(originalName, session.locale());
+ String legacyOriginalName = MessageTranslator.convertMessage(originalName, session.locale());
return !legacyOriginalName.equals(anvilContainer.getNewName());
}
- return !Objects.equals(originalName, ItemUtils.getCustomName(anvilContainer.getResult().getNbt()));
- }
-
- @SuppressWarnings("SameParameterValue")
- private int getTagIntValueOr(GeyserItemStack itemStack, String tagName, int defaultValue) {
- if (itemStack.getNbt() != null) {
- Tag tag = itemStack.getNbt().get(tagName);
- if (tag != null && tag.getValue() instanceof Number value) {
- return value.intValue();
- }
- }
- return defaultValue;
+ return !Objects.equals(originalName, ItemUtils.getCustomName(anvilContainer.getResult().getComponents()));
}
private int getRepairCost(GeyserItemStack itemStack) {
- return getTagIntValueOr(itemStack, "RepairCost", 0);
+ return itemStack.getComponent(DataComponentType.REPAIR_COST, 0);
}
private boolean hasDurability(GeyserItemStack itemStack) {
if (itemStack.asItem().maxDamage() > 0) {
- return getTagIntValueOr(itemStack, "Unbreakable", 0) == 0;
+ return itemStack.getComponent(DataComponentType.UNBREAKABLE, false);
}
return false;
}
private int getDamage(GeyserItemStack itemStack) {
- return getTagIntValueOr(itemStack, "Damage", 0);
+ return itemStack.getComponent(DataComponentType.DAMAGE, 0);
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/item/ArmorMaterial.java b/core/src/main/java/org/geysermc/geyser/item/ArmorMaterial.java
index 315a8cd4d..348c0af8c 100644
--- a/core/src/main/java/org/geysermc/geyser/item/ArmorMaterial.java
+++ b/core/src/main/java/org/geysermc/geyser/item/ArmorMaterial.java
@@ -31,12 +31,13 @@ import java.util.function.Supplier;
public enum ArmorMaterial {
LEATHER(() -> Items.LEATHER),
- CHAIN(() -> Items.IRON_INGOT),
+ CHAINMAIL(() -> Items.IRON_INGOT),
IRON(() -> Items.IRON_INGOT),
GOLD(() -> Items.GOLD_INGOT),
DIAMOND(() -> Items.DIAMOND),
- TURTLE(() -> Items.SCUTE),
- NETHERITE(() -> Items.NETHERITE_INGOT);
+ TURTLE(() -> Items.TURTLE_SCUTE),
+ NETHERITE(() -> Items.NETHERITE_INGOT),
+ ARMADILLO(() -> Items.ARMADILLO_SCUTE);
private final Supplier repairIngredient;
diff --git a/core/src/main/java/org/geysermc/geyser/item/GeyserCustomItemData.java b/core/src/main/java/org/geysermc/geyser/item/GeyserCustomItemData.java
index 2906a9be3..a2054f78a 100644
--- a/core/src/main/java/org/geysermc/geyser/item/GeyserCustomItemData.java
+++ b/core/src/main/java/org/geysermc/geyser/item/GeyserCustomItemData.java
@@ -35,6 +35,7 @@ import org.geysermc.geyser.api.item.custom.CustomRenderOffsets;
import java.util.HashSet;
import java.util.Objects;
+import java.util.OptionalInt;
import java.util.Set;
@EqualsAndHashCode
@@ -46,6 +47,8 @@ public class GeyserCustomItemData implements CustomItemData {
private final String icon;
private final boolean allowOffhand;
private final boolean displayHandheld;
+ private final OptionalInt creativeCategory;
+ private final String creativeGroup;
private final int textureSize;
private final CustomRenderOffsets renderOffsets;
private final Set tags;
@@ -56,6 +59,8 @@ public class GeyserCustomItemData implements CustomItemData {
String icon,
boolean allowOffhand,
boolean displayHandheld,
+ OptionalInt creativeCategory,
+ String creativeGroup,
int textureSize,
CustomRenderOffsets renderOffsets,
Set tags) {
@@ -65,6 +70,8 @@ public class GeyserCustomItemData implements CustomItemData {
this.icon = icon;
this.allowOffhand = allowOffhand;
this.displayHandheld = displayHandheld;
+ this.creativeCategory = creativeCategory;
+ this.creativeGroup = creativeGroup;
this.textureSize = textureSize;
this.renderOffsets = renderOffsets;
this.tags = tags;
@@ -100,6 +107,16 @@ public class GeyserCustomItemData implements CustomItemData {
return this.displayHandheld;
}
+ @Override
+ public @NonNull OptionalInt creativeCategory() {
+ return this.creativeCategory;
+ }
+
+ @Override
+ public @Nullable String creativeGroup() {
+ return this.creativeGroup;
+ }
+
@Override
public int textureSize() {
return textureSize;
@@ -118,11 +135,12 @@ public class GeyserCustomItemData implements CustomItemData {
public static class Builder implements CustomItemData.Builder {
protected String name = null;
protected CustomItemOptions customItemOptions = null;
-
protected String displayName = null;
protected String icon = null;
protected boolean allowOffhand = true; // Bedrock doesn't give items offhand allowance unless they serve gameplay purpose, but we want to be friendly with Java
protected boolean displayHandheld = false;
+ protected OptionalInt creativeCategory = OptionalInt.empty();
+ protected String creativeGroup = null;
protected int textureSize = 16;
protected CustomRenderOffsets renderOffsets = null;
protected Set tags = new HashSet<>();
@@ -163,6 +181,18 @@ public class GeyserCustomItemData implements CustomItemData {
return this;
}
+ @Override
+ public Builder creativeCategory(int creativeCategory) {
+ this.creativeCategory = OptionalInt.of(creativeCategory);
+ return this;
+ }
+
+ @Override
+ public Builder creativeGroup(@Nullable String creativeGroup) {
+ this.creativeGroup = creativeGroup;
+ return this;
+ }
+
@Override
public Builder textureSize(int textureSize) {
this.textureSize = textureSize;
@@ -193,7 +223,8 @@ public class GeyserCustomItemData implements CustomItemData {
if (this.icon == null) {
this.icon = this.name;
}
- return new GeyserCustomItemData(this.name, this.customItemOptions, this.displayName, this.icon, this.allowOffhand, this.displayHandheld, this.textureSize, this.renderOffsets, this.tags);
+ return new GeyserCustomItemData(this.name, this.customItemOptions, this.displayName, this.icon, this.allowOffhand,
+ this.displayHandheld, this.creativeCategory, this.creativeGroup, this.textureSize, this.renderOffsets, this.tags);
}
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java b/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java
index bb4e60589..9c9269df3 100644
--- a/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java
+++ b/core/src/main/java/org/geysermc/geyser/item/GeyserNonVanillaCustomItemData.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org
+ * Copyright (c) 2019-2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -33,10 +33,8 @@ import org.geysermc.geyser.api.item.custom.CustomItemOptions;
import org.geysermc.geyser.api.item.custom.CustomRenderOffsets;
import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData;
-import java.util.OptionalInt;
import java.util.Set;
-@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@EqualsAndHashCode(callSuper = true)
@ToString
public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData implements NonVanillaCustomItemData {
@@ -44,43 +42,44 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
private final int javaId;
private final int stackSize;
private final int maxDamage;
+ private final int attackDamage;
private final String toolType;
private final String toolTier;
private final String armorType;
private final int protectionValue;
private final String translationString;
private final Set repairMaterials;
- private final OptionalInt creativeCategory;
- private final String creativeGroup;
private final boolean isHat;
private final boolean isFoil;
private final boolean isTool;
private final boolean isEdible;
private final boolean canAlwaysEat;
private final boolean isChargeable;
+ private final String block;
public GeyserNonVanillaCustomItemData(Builder builder) {
super(builder.name, builder.customItemOptions, builder.displayName, builder.icon, builder.allowOffhand,
- builder.displayHandheld, builder.textureSize, builder.renderOffsets, builder.tags);
+ builder.displayHandheld, builder.creativeCategory, builder.creativeGroup,
+ builder.textureSize, builder.renderOffsets, builder.tags);
this.identifier = builder.identifier;
this.javaId = builder.javaId;
this.stackSize = builder.stackSize;
this.maxDamage = builder.maxDamage;
+ this.attackDamage = builder.attackDamage;
this.toolType = builder.toolType;
this.toolTier = builder.toolTier;
this.armorType = builder.armorType;
this.protectionValue = builder.protectionValue;
this.translationString = builder.translationString;
this.repairMaterials = builder.repairMaterials;
- this.creativeCategory = builder.creativeCategory;
- this.creativeGroup = builder.creativeGroup;
this.isHat = builder.hat;
this.isFoil = builder.foil;
this.isTool = builder.tool;
this.isEdible = builder.edible;
this.canAlwaysEat = builder.canAlwaysEat;
this.isChargeable = builder.chargeable;
+ this.block = builder.block;
}
@Override
@@ -103,6 +102,11 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return maxDamage;
}
+ @Override
+ public int attackDamage() {
+ return attackDamage;
+ }
+
@Override
public String toolType() {
return toolType;
@@ -133,16 +137,6 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return repairMaterials;
}
- @Override
- public @NonNull OptionalInt creativeCategory() {
- return creativeCategory;
- }
-
- @Override
- public String creativeGroup() {
- return creativeGroup;
- }
-
@Override
public boolean isHat() {
return isHat;
@@ -168,6 +162,11 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
return isChargeable;
}
+ @Override
+ public String block() {
+ return block;
+ }
+
public static class Builder extends GeyserCustomItemData.Builder implements NonVanillaCustomItemData.Builder {
private String identifier = null;
private int javaId = -1;
@@ -176,6 +175,8 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
private int maxDamage = 0;
+ private int attackDamage = 0;
+
private String toolType = null;
private String toolTier = null;
@@ -186,15 +187,13 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
private Set repairMaterials;
- private OptionalInt creativeCategory = OptionalInt.empty();
- private String creativeGroup = null;
-
private boolean hat = false;
private boolean foil = false;
private boolean tool = false;
private boolean edible = false;
private boolean canAlwaysEat = false;
private boolean chargeable = false;
+ private String block = null;
@Override
public Builder name(@NonNull String name) {
@@ -243,107 +242,117 @@ public final class GeyserNonVanillaCustomItemData extends GeyserCustomItemData i
}
@Override
- public NonVanillaCustomItemData.Builder identifier(@NonNull String identifier) {
+ public Builder identifier(@NonNull String identifier) {
this.identifier = identifier;
return this;
}
@Override
- public NonVanillaCustomItemData.Builder javaId(int javaId) {
+ public Builder javaId(int javaId) {
this.javaId = javaId;
return this;
}
@Override
- public NonVanillaCustomItemData.Builder stackSize(int stackSize) {
+ public Builder stackSize(int stackSize) {
this.stackSize = stackSize;
return this;
}
@Override
- public NonVanillaCustomItemData.Builder maxDamage(int maxDamage) {
+ public Builder maxDamage(int maxDamage) {
this.maxDamage = maxDamage;
return this;
}
@Override
- public NonVanillaCustomItemData.Builder toolType(@Nullable String toolType) {
+ public NonVanillaCustomItemData.Builder attackDamage(int attackDamage) {
+ this.attackDamage = attackDamage;
+ return this;
+ }
+
+ @Override
+ public Builder toolType(@Nullable String toolType) {
this.toolType = toolType;
return this;
}
@Override
- public NonVanillaCustomItemData.Builder toolTier(@Nullable String toolTier) {
+ public Builder toolTier(@Nullable String toolTier) {
this.toolTier = toolTier;
return this;
}
@Override
- public NonVanillaCustomItemData.Builder armorType(@Nullable String armorType) {
+ public Builder armorType(@Nullable String armorType) {
this.armorType = armorType;
return this;
}
@Override
- public NonVanillaCustomItemData.Builder protectionValue(int protectionValue) {
+ public Builder protectionValue(int protectionValue) {
this.protectionValue = protectionValue;
return this;
}
@Override
- public NonVanillaCustomItemData.Builder translationString(@Nullable String translationString) {
+ public Builder translationString(@Nullable String translationString) {
this.translationString = translationString;
return this;
}
@Override
- public NonVanillaCustomItemData.Builder repairMaterials(@Nullable Set repairMaterials) {
+ public Builder repairMaterials(@Nullable Set repairMaterials) {
this.repairMaterials = repairMaterials;
return this;
}
@Override
- public NonVanillaCustomItemData.Builder creativeCategory(int creativeCategory) {
- this.creativeCategory = OptionalInt.of(creativeCategory);
- return this;
+ public Builder creativeCategory(int creativeCategory) {
+ return (Builder) super.creativeCategory(creativeCategory);
}
@Override
- public NonVanillaCustomItemData.Builder creativeGroup(@Nullable String creativeGroup) {
- this.creativeGroup = creativeGroup;
- return this;
+ public Builder creativeGroup(@Nullable String creativeGroup) {
+ return (Builder) super.creativeGroup(creativeGroup);
}
@Override
- public NonVanillaCustomItemData.Builder hat(boolean isHat) {
+ public Builder hat(boolean isHat) {
this.hat = isHat;
return this;
}
@Override
- public NonVanillaCustomItemData.Builder foil(boolean isFoil) {
+ public Builder foil(boolean isFoil) {
this.foil = isFoil;
return this;
}
@Override
- public NonVanillaCustomItemData.Builder edible(boolean isEdible) {
+ public Builder edible(boolean isEdible) {
this.edible = isEdible;
return this;
}
@Override
- public NonVanillaCustomItemData.Builder canAlwaysEat(boolean canAlwaysEat) {
+ public Builder canAlwaysEat(boolean canAlwaysEat) {
this.canAlwaysEat = canAlwaysEat;
return this;
}
@Override
- public NonVanillaCustomItemData.Builder chargeable(boolean isChargeable) {
+ public Builder chargeable(boolean isChargeable) {
this.chargeable = isChargeable;
return this;
}
+ @Override
+ public Builder block(String block) {
+ this.block = block;
+ return this;
+ }
+
@Override
public NonVanillaCustomItemData build() {
if (identifier == null || javaId == -1) {
diff --git a/core/src/main/java/org/geysermc/geyser/item/Items.java b/core/src/main/java/org/geysermc/geyser/item/Items.java
index e84315fd8..1ddd14982 100644
--- a/core/src/main/java/org/geysermc/geyser/item/Items.java
+++ b/core/src/main/java/org/geysermc/geyser/item/Items.java
@@ -27,10 +27,9 @@ package org.geysermc.geyser.item;
import org.geysermc.geyser.item.components.ToolTier;
import org.geysermc.geyser.item.type.*;
+import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.registry.Registries;
-import java.util.Collections;
-
import static org.geysermc.geyser.item.type.Item.builder;
/**
@@ -39,769 +38,770 @@ import static org.geysermc.geyser.item.type.Item.builder;
@SuppressWarnings("unused")
public final class Items {
public static final Item AIR = register(new Item("air", builder()));
- public static final Item STONE = register(new BlockItem("stone", builder()));
- public static final Item GRANITE = register(new BlockItem("granite", builder()));
- public static final Item POLISHED_GRANITE = register(new BlockItem("polished_granite", builder()));
- public static final Item DIORITE = register(new BlockItem("diorite", builder()));
- public static final Item POLISHED_DIORITE = register(new BlockItem("polished_diorite", builder()));
- public static final Item ANDESITE = register(new BlockItem("andesite", builder()));
- public static final Item POLISHED_ANDESITE = register(new BlockItem("polished_andesite", builder()));
- public static final Item DEEPSLATE = register(new BlockItem("deepslate", builder()));
- public static final Item COBBLED_DEEPSLATE = register(new BlockItem("cobbled_deepslate", builder()));
- public static final Item POLISHED_DEEPSLATE = register(new BlockItem("polished_deepslate", builder()));
- public static final Item CALCITE = register(new BlockItem("calcite", builder()));
- public static final Item TUFF = register(new BlockItem("tuff", builder()));
- public static final Item TUFF_SLAB = register(new BlockItem("tuff_slab", builder()));
- public static final Item TUFF_STAIRS = register(new BlockItem("tuff_stairs", builder()));
- public static final Item TUFF_WALL = register(new BlockItem("tuff_wall", builder()));
- public static final Item CHISELED_TUFF = register(new BlockItem("chiseled_tuff", builder()));
- public static final Item POLISHED_TUFF = register(new BlockItem("polished_tuff", builder()));
- public static final Item POLISHED_TUFF_SLAB = register(new BlockItem("polished_tuff_slab", builder()));
- public static final Item POLISHED_TUFF_STAIRS = register(new BlockItem("polished_tuff_stairs", builder()));
- public static final Item POLISHED_TUFF_WALL = register(new BlockItem("polished_tuff_wall", builder()));
- public static final Item TUFF_BRICKS = register(new BlockItem("tuff_bricks", builder()));
- public static final Item TUFF_BRICK_SLAB = register(new BlockItem("tuff_brick_slab", builder()));
- public static final Item TUFF_BRICK_STAIRS = register(new BlockItem("tuff_brick_stairs", builder()));
- public static final Item TUFF_BRICK_WALL = register(new BlockItem("tuff_brick_wall", builder()));
- public static final Item CHISELED_TUFF_BRICKS = register(new BlockItem("chiseled_tuff_bricks", builder()));
- public static final Item DRIPSTONE_BLOCK = register(new BlockItem("dripstone_block", builder()));
- public static final Item GRASS_BLOCK = register(new BlockItem("grass_block", builder()));
- public static final Item DIRT = register(new BlockItem("dirt", builder()));
- public static final Item COARSE_DIRT = register(new BlockItem("coarse_dirt", builder()));
- public static final Item PODZOL = register(new BlockItem("podzol", builder()));
- public static final Item ROOTED_DIRT = register(new BlockItem("rooted_dirt", builder()));
- public static final Item MUD = register(new BlockItem("mud", builder()));
- public static final Item CRIMSON_NYLIUM = register(new BlockItem("crimson_nylium", builder()));
- public static final Item WARPED_NYLIUM = register(new BlockItem("warped_nylium", builder()));
- public static final Item COBBLESTONE = register(new BlockItem("cobblestone", builder()));
- public static final Item OAK_PLANKS = register(new BlockItem("oak_planks", builder()));
- public static final Item SPRUCE_PLANKS = register(new BlockItem("spruce_planks", builder()));
- public static final Item BIRCH_PLANKS = register(new BlockItem("birch_planks", builder()));
- public static final Item JUNGLE_PLANKS = register(new BlockItem("jungle_planks", builder()));
- public static final Item ACACIA_PLANKS = register(new BlockItem("acacia_planks", builder()));
- public static final Item CHERRY_PLANKS = register(new BlockItem("cherry_planks", builder()));
- public static final Item DARK_OAK_PLANKS = register(new BlockItem("dark_oak_planks", builder()));
- public static final Item MANGROVE_PLANKS = register(new BlockItem("mangrove_planks", builder()));
- public static final Item BAMBOO_PLANKS = register(new BlockItem("bamboo_planks", builder()));
- public static final Item CRIMSON_PLANKS = register(new BlockItem("crimson_planks", builder()));
- public static final Item WARPED_PLANKS = register(new BlockItem("warped_planks", builder()));
- public static final Item BAMBOO_MOSAIC = register(new BlockItem("bamboo_mosaic", builder()));
- public static final Item OAK_SAPLING = register(new BlockItem("oak_sapling", builder()));
- public static final Item SPRUCE_SAPLING = register(new BlockItem("spruce_sapling", builder()));
- public static final Item BIRCH_SAPLING = register(new BlockItem("birch_sapling", builder()));
- public static final Item JUNGLE_SAPLING = register(new BlockItem("jungle_sapling", builder()));
- public static final Item ACACIA_SAPLING = register(new BlockItem("acacia_sapling", builder()));
- public static final Item CHERRY_SAPLING = register(new BlockItem("cherry_sapling", builder()));
- public static final Item DARK_OAK_SAPLING = register(new BlockItem("dark_oak_sapling", builder()));
- public static final Item MANGROVE_PROPAGULE = register(new BlockItem("mangrove_propagule", builder()));
- public static final Item BEDROCK = register(new BlockItem("bedrock", builder()));
- public static final Item SAND = register(new BlockItem("sand", builder()));
- public static final Item SUSPICIOUS_SAND = register(new BlockItem("suspicious_sand", builder()));
- public static final Item SUSPICIOUS_GRAVEL = register(new BlockItem("suspicious_gravel", builder()));
- public static final Item RED_SAND = register(new BlockItem("red_sand", builder()));
- public static final Item GRAVEL = register(new BlockItem("gravel", builder()));
- public static final Item COAL_ORE = register(new BlockItem("coal_ore", builder()));
- public static final Item DEEPSLATE_COAL_ORE = register(new BlockItem("deepslate_coal_ore", builder()));
- public static final Item IRON_ORE = register(new BlockItem("iron_ore", builder()));
- public static final Item DEEPSLATE_IRON_ORE = register(new BlockItem("deepslate_iron_ore", builder()));
- public static final Item COPPER_ORE = register(new BlockItem("copper_ore", builder()));
- public static final Item DEEPSLATE_COPPER_ORE = register(new BlockItem("deepslate_copper_ore", builder()));
- public static final Item GOLD_ORE = register(new BlockItem("gold_ore", builder()));
- public static final Item DEEPSLATE_GOLD_ORE = register(new BlockItem("deepslate_gold_ore", builder()));
- public static final Item REDSTONE_ORE = register(new BlockItem("redstone_ore", builder()));
- public static final Item DEEPSLATE_REDSTONE_ORE = register(new BlockItem("deepslate_redstone_ore", builder()));
- public static final Item EMERALD_ORE = register(new BlockItem("emerald_ore", builder()));
- public static final Item DEEPSLATE_EMERALD_ORE = register(new BlockItem("deepslate_emerald_ore", builder()));
- public static final Item LAPIS_ORE = register(new BlockItem("lapis_ore", builder()));
- public static final Item DEEPSLATE_LAPIS_ORE = register(new BlockItem("deepslate_lapis_ore", builder()));
- public static final Item DIAMOND_ORE = register(new BlockItem("diamond_ore", builder()));
- public static final Item DEEPSLATE_DIAMOND_ORE = register(new BlockItem("deepslate_diamond_ore", builder()));
- public static final Item NETHER_GOLD_ORE = register(new BlockItem("nether_gold_ore", builder()));
- public static final Item NETHER_QUARTZ_ORE = register(new BlockItem("nether_quartz_ore", builder()));
- public static final Item ANCIENT_DEBRIS = register(new BlockItem("ancient_debris", builder()));
- public static final Item COAL_BLOCK = register(new BlockItem("coal_block", builder()));
- public static final Item RAW_IRON_BLOCK = register(new BlockItem("raw_iron_block", builder()));
- public static final Item RAW_COPPER_BLOCK = register(new BlockItem("raw_copper_block", builder()));
- public static final Item RAW_GOLD_BLOCK = register(new BlockItem("raw_gold_block", builder()));
- public static final Item AMETHYST_BLOCK = register(new BlockItem("amethyst_block", builder()));
- public static final Item BUDDING_AMETHYST = register(new BlockItem("budding_amethyst", builder()));
- public static final Item IRON_BLOCK = register(new BlockItem("iron_block", builder()));
- public static final Item COPPER_BLOCK = register(new BlockItem("copper_block", builder()));
- public static final Item GOLD_BLOCK = register(new BlockItem("gold_block", builder()));
- public static final Item DIAMOND_BLOCK = register(new BlockItem("diamond_block", builder()));
- public static final Item NETHERITE_BLOCK = register(new BlockItem("netherite_block", builder()));
- public static final Item EXPOSED_COPPER = register(new BlockItem("exposed_copper", builder()));
- public static final Item WEATHERED_COPPER = register(new BlockItem("weathered_copper", builder()));
- public static final Item OXIDIZED_COPPER = register(new BlockItem("oxidized_copper", builder()));
- public static final Item CHISELED_COPPER = register(new BlockItem("chiseled_copper", builder()));
- public static final Item EXPOSED_CHISELED_COPPER = register(new BlockItem("exposed_chiseled_copper", builder()));
- public static final Item WEATHERED_CHISELED_COPPER = register(new BlockItem("weathered_chiseled_copper", builder()));
- public static final Item OXIDIZED_CHISELED_COPPER = register(new BlockItem("oxidized_chiseled_copper", builder()));
- public static final Item CUT_COPPER = register(new BlockItem("cut_copper", builder()));
- public static final Item EXPOSED_CUT_COPPER = register(new BlockItem("exposed_cut_copper", builder()));
- public static final Item WEATHERED_CUT_COPPER = register(new BlockItem("weathered_cut_copper", builder()));
- public static final Item OXIDIZED_CUT_COPPER = register(new BlockItem("oxidized_cut_copper", builder()));
- public static final Item CUT_COPPER_STAIRS = register(new BlockItem("cut_copper_stairs", builder()));
- public static final Item EXPOSED_CUT_COPPER_STAIRS = register(new BlockItem("exposed_cut_copper_stairs", builder()));
- public static final Item WEATHERED_CUT_COPPER_STAIRS = register(new BlockItem("weathered_cut_copper_stairs", builder()));
- public static final Item OXIDIZED_CUT_COPPER_STAIRS = register(new BlockItem("oxidized_cut_copper_stairs", builder()));
- public static final Item CUT_COPPER_SLAB = register(new BlockItem("cut_copper_slab", builder()));
- public static final Item EXPOSED_CUT_COPPER_SLAB = register(new BlockItem("exposed_cut_copper_slab", builder()));
- public static final Item WEATHERED_CUT_COPPER_SLAB = register(new BlockItem("weathered_cut_copper_slab", builder()));
- public static final Item OXIDIZED_CUT_COPPER_SLAB = register(new BlockItem("oxidized_cut_copper_slab", builder()));
- public static final Item WAXED_COPPER_BLOCK = register(new BlockItem("waxed_copper_block", builder()));
- public static final Item WAXED_EXPOSED_COPPER = register(new BlockItem("waxed_exposed_copper", builder()));
- public static final Item WAXED_WEATHERED_COPPER = register(new BlockItem("waxed_weathered_copper", builder()));
- public static final Item WAXED_OXIDIZED_COPPER = register(new BlockItem("waxed_oxidized_copper", builder()));
- public static final Item WAXED_CHISELED_COPPER = register(new BlockItem("waxed_chiseled_copper", builder()));
- public static final Item WAXED_EXPOSED_CHISELED_COPPER = register(new BlockItem("waxed_exposed_chiseled_copper", builder()));
- public static final Item WAXED_WEATHERED_CHISELED_COPPER = register(new BlockItem("waxed_weathered_chiseled_copper", builder()));
- public static final Item WAXED_OXIDIZED_CHISELED_COPPER = register(new BlockItem("waxed_oxidized_chiseled_copper", builder()));
- public static final Item WAXED_CUT_COPPER = register(new BlockItem("waxed_cut_copper", builder()));
- public static final Item WAXED_EXPOSED_CUT_COPPER = register(new BlockItem("waxed_exposed_cut_copper", builder()));
- public static final Item WAXED_WEATHERED_CUT_COPPER = register(new BlockItem("waxed_weathered_cut_copper", builder()));
- public static final Item WAXED_OXIDIZED_CUT_COPPER = register(new BlockItem("waxed_oxidized_cut_copper", builder()));
- public static final Item WAXED_CUT_COPPER_STAIRS = register(new BlockItem("waxed_cut_copper_stairs", builder()));
- public static final Item WAXED_EXPOSED_CUT_COPPER_STAIRS = register(new BlockItem("waxed_exposed_cut_copper_stairs", builder()));
- public static final Item WAXED_WEATHERED_CUT_COPPER_STAIRS = register(new BlockItem("waxed_weathered_cut_copper_stairs", builder()));
- public static final Item WAXED_OXIDIZED_CUT_COPPER_STAIRS = register(new BlockItem("waxed_oxidized_cut_copper_stairs", builder()));
- public static final Item WAXED_CUT_COPPER_SLAB = register(new BlockItem("waxed_cut_copper_slab", builder()));
- public static final Item WAXED_EXPOSED_CUT_COPPER_SLAB = register(new BlockItem("waxed_exposed_cut_copper_slab", builder()));
- public static final Item WAXED_WEATHERED_CUT_COPPER_SLAB = register(new BlockItem("waxed_weathered_cut_copper_slab", builder()));
- public static final Item WAXED_OXIDIZED_CUT_COPPER_SLAB = register(new BlockItem("waxed_oxidized_cut_copper_slab", builder()));
- public static final Item OAK_LOG = register(new BlockItem("oak_log", builder()));
- public static final Item SPRUCE_LOG = register(new BlockItem("spruce_log", builder()));
- public static final Item BIRCH_LOG = register(new BlockItem("birch_log", builder()));
- public static final Item JUNGLE_LOG = register(new BlockItem("jungle_log", builder()));
- public static final Item ACACIA_LOG = register(new BlockItem("acacia_log", builder()));
- public static final Item CHERRY_LOG = register(new BlockItem("cherry_log", builder()));
- public static final Item DARK_OAK_LOG = register(new BlockItem("dark_oak_log", builder()));
- public static final Item MANGROVE_LOG = register(new BlockItem("mangrove_log", builder()));
- public static final Item MANGROVE_ROOTS = register(new BlockItem("mangrove_roots", builder()));
- public static final Item MUDDY_MANGROVE_ROOTS = register(new BlockItem("muddy_mangrove_roots", builder()));
- public static final Item CRIMSON_STEM = register(new BlockItem("crimson_stem", builder()));
- public static final Item WARPED_STEM = register(new BlockItem("warped_stem", builder()));
- public static final Item BAMBOO_BLOCK = register(new BlockItem("bamboo_block", builder()));
- public static final Item STRIPPED_OAK_LOG = register(new BlockItem("stripped_oak_log", builder()));
- public static final Item STRIPPED_SPRUCE_LOG = register(new BlockItem("stripped_spruce_log", builder()));
- public static final Item STRIPPED_BIRCH_LOG = register(new BlockItem("stripped_birch_log", builder()));
- public static final Item STRIPPED_JUNGLE_LOG = register(new BlockItem("stripped_jungle_log", builder()));
- public static final Item STRIPPED_ACACIA_LOG = register(new BlockItem("stripped_acacia_log", builder()));
- public static final Item STRIPPED_CHERRY_LOG = register(new BlockItem("stripped_cherry_log", builder()));
- public static final Item STRIPPED_DARK_OAK_LOG = register(new BlockItem("stripped_dark_oak_log", builder()));
- public static final Item STRIPPED_MANGROVE_LOG = register(new BlockItem("stripped_mangrove_log", builder()));
- public static final Item STRIPPED_CRIMSON_STEM = register(new BlockItem("stripped_crimson_stem", builder()));
- public static final Item STRIPPED_WARPED_STEM = register(new BlockItem("stripped_warped_stem", builder()));
- public static final Item STRIPPED_OAK_WOOD = register(new BlockItem("stripped_oak_wood", builder()));
- public static final Item STRIPPED_SPRUCE_WOOD = register(new BlockItem("stripped_spruce_wood", builder()));
- public static final Item STRIPPED_BIRCH_WOOD = register(new BlockItem("stripped_birch_wood", builder()));
- public static final Item STRIPPED_JUNGLE_WOOD = register(new BlockItem("stripped_jungle_wood", builder()));
- public static final Item STRIPPED_ACACIA_WOOD = register(new BlockItem("stripped_acacia_wood", builder()));
- public static final Item STRIPPED_CHERRY_WOOD = register(new BlockItem("stripped_cherry_wood", builder()));
- public static final Item STRIPPED_DARK_OAK_WOOD = register(new BlockItem("stripped_dark_oak_wood", builder()));
- public static final Item STRIPPED_MANGROVE_WOOD = register(new BlockItem("stripped_mangrove_wood", builder()));
- public static final Item STRIPPED_CRIMSON_HYPHAE = register(new BlockItem("stripped_crimson_hyphae", builder()));
- public static final Item STRIPPED_WARPED_HYPHAE = register(new BlockItem("stripped_warped_hyphae", builder()));
- public static final Item STRIPPED_BAMBOO_BLOCK = register(new BlockItem("stripped_bamboo_block", builder()));
- public static final Item OAK_WOOD = register(new BlockItem("oak_wood", builder()));
- public static final Item SPRUCE_WOOD = register(new BlockItem("spruce_wood", builder()));
- public static final Item BIRCH_WOOD = register(new BlockItem("birch_wood", builder()));
- public static final Item JUNGLE_WOOD = register(new BlockItem("jungle_wood", builder()));
- public static final Item ACACIA_WOOD = register(new BlockItem("acacia_wood", builder()));
- public static final Item CHERRY_WOOD = register(new BlockItem("cherry_wood", builder()));
- public static final Item DARK_OAK_WOOD = register(new BlockItem("dark_oak_wood", builder()));
- public static final Item MANGROVE_WOOD = register(new BlockItem("mangrove_wood", builder()));
- public static final Item CRIMSON_HYPHAE = register(new BlockItem("crimson_hyphae", builder()));
- public static final Item WARPED_HYPHAE = register(new BlockItem("warped_hyphae", builder()));
- public static final Item OAK_LEAVES = register(new BlockItem("oak_leaves", builder()));
- public static final Item SPRUCE_LEAVES = register(new BlockItem("spruce_leaves", builder()));
- public static final Item BIRCH_LEAVES = register(new BlockItem("birch_leaves", builder()));
- public static final Item JUNGLE_LEAVES = register(new BlockItem("jungle_leaves", builder()));
- public static final Item ACACIA_LEAVES = register(new BlockItem("acacia_leaves", builder()));
- public static final Item CHERRY_LEAVES = register(new BlockItem("cherry_leaves", builder()));
- public static final Item DARK_OAK_LEAVES = register(new BlockItem("dark_oak_leaves", builder()));
- public static final Item MANGROVE_LEAVES = register(new BlockItem("mangrove_leaves", builder()));
- public static final Item AZALEA_LEAVES = register(new BlockItem("azalea_leaves", builder()));
- public static final Item FLOWERING_AZALEA_LEAVES = register(new BlockItem("flowering_azalea_leaves", builder()));
- public static final Item SPONGE = register(new BlockItem("sponge", builder()));
- public static final Item WET_SPONGE = register(new BlockItem("wet_sponge", builder()));
- public static final Item GLASS = register(new BlockItem("glass", builder()));
- public static final Item TINTED_GLASS = register(new BlockItem("tinted_glass", builder()));
- public static final Item LAPIS_BLOCK = register(new BlockItem("lapis_block", builder()));
- public static final Item SANDSTONE = register(new BlockItem("sandstone", builder()));
- public static final Item CHISELED_SANDSTONE = register(new BlockItem("chiseled_sandstone", builder()));
- public static final Item CUT_SANDSTONE = register(new BlockItem("cut_sandstone", builder()));
- public static final Item COBWEB = register(new BlockItem("cobweb", builder()));
- public static final Item SHORT_GRASS = register(new BlockItem("short_grass", builder()));
- public static final Item FERN = register(new BlockItem("fern", builder()));
- public static final Item AZALEA = register(new BlockItem("azalea", builder()));
- public static final Item FLOWERING_AZALEA = register(new BlockItem("flowering_azalea", builder()));
- public static final Item DEAD_BUSH = register(new BlockItem("dead_bush", builder()));
- public static final Item SEAGRASS = register(new BlockItem("seagrass", builder()));
- public static final Item SEA_PICKLE = register(new BlockItem("sea_pickle", builder()));
- public static final Item WHITE_WOOL = register(new BlockItem("white_wool", builder()));
- public static final Item ORANGE_WOOL = register(new BlockItem("orange_wool", builder()));
- public static final Item MAGENTA_WOOL = register(new BlockItem("magenta_wool", builder()));
- public static final Item LIGHT_BLUE_WOOL = register(new BlockItem("light_blue_wool", builder()));
- public static final Item YELLOW_WOOL = register(new BlockItem("yellow_wool", builder()));
- public static final Item LIME_WOOL = register(new BlockItem("lime_wool", builder()));
- public static final Item PINK_WOOL = register(new BlockItem("pink_wool", builder()));
- public static final Item GRAY_WOOL = register(new BlockItem("gray_wool", builder()));
- public static final Item LIGHT_GRAY_WOOL = register(new BlockItem("light_gray_wool", builder()));
- public static final Item CYAN_WOOL = register(new BlockItem("cyan_wool", builder()));
- public static final Item PURPLE_WOOL = register(new BlockItem("purple_wool", builder()));
- public static final Item BLUE_WOOL = register(new BlockItem("blue_wool", builder()));
- public static final Item BROWN_WOOL = register(new BlockItem("brown_wool", builder()));
- public static final Item GREEN_WOOL = register(new BlockItem("green_wool", builder()));
- public static final Item RED_WOOL = register(new BlockItem("red_wool", builder()));
- public static final Item BLACK_WOOL = register(new BlockItem("black_wool", builder()));
- public static final Item DANDELION = register(new FlowerItem("dandelion", builder()));
- public static final Item POPPY = register(new FlowerItem("poppy", builder()));
- public static final Item BLUE_ORCHID = register(new FlowerItem("blue_orchid", builder()));
- public static final Item ALLIUM = register(new FlowerItem("allium", builder()));
- public static final Item AZURE_BLUET = register(new FlowerItem("azure_bluet", builder()));
- public static final Item RED_TULIP = register(new FlowerItem("red_tulip", builder()));
- public static final Item ORANGE_TULIP = register(new FlowerItem("orange_tulip", builder()));
- public static final Item WHITE_TULIP = register(new FlowerItem("white_tulip", builder()));
- public static final Item PINK_TULIP = register(new FlowerItem("pink_tulip", builder()));
- public static final Item OXEYE_DAISY = register(new FlowerItem("oxeye_daisy", builder()));
- public static final Item CORNFLOWER = register(new FlowerItem("cornflower", builder()));
- public static final Item LILY_OF_THE_VALLEY = register(new FlowerItem("lily_of_the_valley", builder()));
- public static final Item WITHER_ROSE = register(new FlowerItem("wither_rose", builder()));
- public static final Item TORCHFLOWER = register(new FlowerItem("torchflower", builder()));
- public static final Item PITCHER_PLANT = register(new BlockItem("pitcher_plant", builder()));
- public static final Item SPORE_BLOSSOM = register(new BlockItem("spore_blossom", builder()));
- public static final Item BROWN_MUSHROOM = register(new BlockItem("brown_mushroom", builder()));
- public static final Item RED_MUSHROOM = register(new BlockItem("red_mushroom", builder()));
- public static final Item CRIMSON_FUNGUS = register(new BlockItem("crimson_fungus", builder()));
- public static final Item WARPED_FUNGUS = register(new BlockItem("warped_fungus", builder()));
- public static final Item CRIMSON_ROOTS = register(new BlockItem("crimson_roots", builder()));
- public static final Item WARPED_ROOTS = register(new BlockItem("warped_roots", builder()));
- public static final Item NETHER_SPROUTS = register(new BlockItem("nether_sprouts", builder()));
- public static final Item WEEPING_VINES = register(new BlockItem("weeping_vines", builder()));
- public static final Item TWISTING_VINES = register(new BlockItem("twisting_vines", builder()));
- public static final Item SUGAR_CANE = register(new BlockItem("sugar_cane", builder()));
- public static final Item KELP = register(new BlockItem("kelp", builder()));
- public static final Item MOSS_CARPET = register(new BlockItem("moss_carpet", builder()));
- public static final Item PINK_PETALS = register(new BlockItem("pink_petals", builder()));
- public static final Item MOSS_BLOCK = register(new BlockItem("moss_block", builder()));
- public static final Item HANGING_ROOTS = register(new BlockItem("hanging_roots", builder()));
- public static final Item BIG_DRIPLEAF = register(new BlockItem("big_dripleaf", builder()));
- public static final Item SMALL_DRIPLEAF = register(new BlockItem("small_dripleaf", builder()));
- public static final Item BAMBOO = register(new BlockItem("bamboo", builder()));
- public static final Item OAK_SLAB = register(new BlockItem("oak_slab", builder()));
- public static final Item SPRUCE_SLAB = register(new BlockItem("spruce_slab", builder()));
- public static final Item BIRCH_SLAB = register(new BlockItem("birch_slab", builder()));
- public static final Item JUNGLE_SLAB = register(new BlockItem("jungle_slab", builder()));
- public static final Item ACACIA_SLAB = register(new BlockItem("acacia_slab", builder()));
- public static final Item CHERRY_SLAB = register(new BlockItem("cherry_slab", builder()));
- public static final Item DARK_OAK_SLAB = register(new BlockItem("dark_oak_slab", builder()));
- public static final Item MANGROVE_SLAB = register(new BlockItem("mangrove_slab", builder()));
- public static final Item BAMBOO_SLAB = register(new BlockItem("bamboo_slab", builder()));
- public static final Item BAMBOO_MOSAIC_SLAB = register(new BlockItem("bamboo_mosaic_slab", builder()));
- public static final Item CRIMSON_SLAB = register(new BlockItem("crimson_slab", builder()));
- public static final Item WARPED_SLAB = register(new BlockItem("warped_slab", builder()));
- public static final Item STONE_SLAB = register(new BlockItem("stone_slab", builder()));
- public static final Item SMOOTH_STONE_SLAB = register(new BlockItem("smooth_stone_slab", builder()));
- public static final Item SANDSTONE_SLAB = register(new BlockItem("sandstone_slab", builder()));
- public static final Item CUT_SANDSTONE_SLAB = register(new BlockItem("cut_sandstone_slab", builder()));
- public static final Item PETRIFIED_OAK_SLAB = register(new BlockItem("petrified_oak_slab", builder()));
- public static final Item COBBLESTONE_SLAB = register(new BlockItem("cobblestone_slab", builder()));
- public static final Item BRICK_SLAB = register(new BlockItem("brick_slab", builder()));
- public static final Item STONE_BRICK_SLAB = register(new BlockItem("stone_brick_slab", builder()));
- public static final Item MUD_BRICK_SLAB = register(new BlockItem("mud_brick_slab", builder()));
- public static final Item NETHER_BRICK_SLAB = register(new BlockItem("nether_brick_slab", builder()));
- public static final Item QUARTZ_SLAB = register(new BlockItem("quartz_slab", builder()));
- public static final Item RED_SANDSTONE_SLAB = register(new BlockItem("red_sandstone_slab", builder()));
- public static final Item CUT_RED_SANDSTONE_SLAB = register(new BlockItem("cut_red_sandstone_slab", builder()));
- public static final Item PURPUR_SLAB = register(new BlockItem("purpur_slab", builder()));
- public static final Item PRISMARINE_SLAB = register(new BlockItem("prismarine_slab", builder()));
- public static final Item PRISMARINE_BRICK_SLAB = register(new BlockItem("prismarine_brick_slab", builder()));
- public static final Item DARK_PRISMARINE_SLAB = register(new BlockItem("dark_prismarine_slab", builder()));
- public static final Item SMOOTH_QUARTZ = register(new BlockItem("smooth_quartz", builder()));
- public static final Item SMOOTH_RED_SANDSTONE = register(new BlockItem("smooth_red_sandstone", builder()));
- public static final Item SMOOTH_SANDSTONE = register(new BlockItem("smooth_sandstone", builder()));
- public static final Item SMOOTH_STONE = register(new BlockItem("smooth_stone", builder()));
- public static final Item BRICKS = register(new BlockItem("bricks", builder()));
- public static final Item BOOKSHELF = register(new BlockItem("bookshelf", builder()));
- public static final Item CHISELED_BOOKSHELF = register(new BlockItem("chiseled_bookshelf", builder()));
- public static final Item DECORATED_POT = register(new DecoratedPotItem("decorated_pot", builder()));
- public static final Item MOSSY_COBBLESTONE = register(new BlockItem("mossy_cobblestone", builder()));
- public static final Item OBSIDIAN = register(new BlockItem("obsidian", builder()));
- public static final Item TORCH = register(new BlockItem("torch", builder()));
- public static final Item END_ROD = register(new BlockItem("end_rod", builder()));
- public static final Item CHORUS_PLANT = register(new BlockItem("chorus_plant", builder()));
- public static final Item CHORUS_FLOWER = register(new BlockItem("chorus_flower", builder()));
- public static final Item PURPUR_BLOCK = register(new BlockItem("purpur_block", builder()));
- public static final Item PURPUR_PILLAR = register(new BlockItem("purpur_pillar", builder()));
- public static final Item PURPUR_STAIRS = register(new BlockItem("purpur_stairs", builder()));
- public static final Item SPAWNER = register(new BlockItem("spawner", builder()));
- public static final Item CHEST = register(new ChestItem("chest", builder()));
- public static final Item CRAFTING_TABLE = register(new BlockItem("crafting_table", builder()));
- public static final Item FARMLAND = register(new BlockItem("farmland", builder()));
- public static final Item FURNACE = register(new BlockItem("furnace", builder()));
- public static final Item LADDER = register(new BlockItem("ladder", builder()));
- public static final Item COBBLESTONE_STAIRS = register(new BlockItem("cobblestone_stairs", builder()));
- public static final Item SNOW = register(new BlockItem("snow", builder()));
- public static final Item ICE = register(new BlockItem("ice", builder()));
- public static final Item SNOW_BLOCK = register(new BlockItem("snow_block", builder()));
- public static final Item CACTUS = register(new BlockItem("cactus", builder()));
- public static final Item CLAY = register(new BlockItem("clay", builder()));
- public static final Item JUKEBOX = register(new BlockItem("jukebox", builder()));
- public static final Item OAK_FENCE = register(new BlockItem("oak_fence", builder()));
- public static final Item SPRUCE_FENCE = register(new BlockItem("spruce_fence", builder()));
- public static final Item BIRCH_FENCE = register(new BlockItem("birch_fence", builder()));
- public static final Item JUNGLE_FENCE = register(new BlockItem("jungle_fence", builder()));
- public static final Item ACACIA_FENCE = register(new BlockItem("acacia_fence", builder()));
- public static final Item CHERRY_FENCE = register(new BlockItem("cherry_fence", builder()));
- public static final Item DARK_OAK_FENCE = register(new BlockItem("dark_oak_fence", builder()));
- public static final Item MANGROVE_FENCE = register(new BlockItem("mangrove_fence", builder()));
- public static final Item BAMBOO_FENCE = register(new BlockItem("bamboo_fence", builder()));
- public static final Item CRIMSON_FENCE = register(new BlockItem("crimson_fence", builder()));
- public static final Item WARPED_FENCE = register(new BlockItem("warped_fence", builder()));
- public static final Item PUMPKIN = register(new BlockItem("pumpkin", builder()));
- public static final Item CARVED_PUMPKIN = register(new BlockItem("carved_pumpkin", builder()));
- public static final Item JACK_O_LANTERN = register(new BlockItem("jack_o_lantern", builder()));
- public static final Item NETHERRACK = register(new BlockItem("netherrack", builder()));
- public static final Item SOUL_SAND = register(new BlockItem("soul_sand", builder()));
- public static final Item SOUL_SOIL = register(new BlockItem("soul_soil", builder()));
- public static final Item BASALT = register(new BlockItem("basalt", builder()));
- public static final Item POLISHED_BASALT = register(new BlockItem("polished_basalt", builder()));
- public static final Item SMOOTH_BASALT = register(new BlockItem("smooth_basalt", builder()));
- public static final Item SOUL_TORCH = register(new BlockItem("soul_torch", builder()));
- public static final Item GLOWSTONE = register(new BlockItem("glowstone", builder()));
- public static final Item INFESTED_STONE = register(new BlockItem("infested_stone", builder()));
- public static final Item INFESTED_COBBLESTONE = register(new BlockItem("infested_cobblestone", builder()));
- public static final Item INFESTED_STONE_BRICKS = register(new BlockItem("infested_stone_bricks", builder()));
- public static final Item INFESTED_MOSSY_STONE_BRICKS = register(new BlockItem("infested_mossy_stone_bricks", builder()));
- public static final Item INFESTED_CRACKED_STONE_BRICKS = register(new BlockItem("infested_cracked_stone_bricks", builder()));
- public static final Item INFESTED_CHISELED_STONE_BRICKS = register(new BlockItem("infested_chiseled_stone_bricks", builder()));
- public static final Item INFESTED_DEEPSLATE = register(new BlockItem("infested_deepslate", builder()));
- public static final Item STONE_BRICKS = register(new BlockItem("stone_bricks", builder()));
- public static final Item MOSSY_STONE_BRICKS = register(new BlockItem("mossy_stone_bricks", builder()));
- public static final Item CRACKED_STONE_BRICKS = register(new BlockItem("cracked_stone_bricks", builder()));
- public static final Item CHISELED_STONE_BRICKS = register(new BlockItem("chiseled_stone_bricks", builder()));
- public static final Item PACKED_MUD = register(new BlockItem("packed_mud", builder()));
- public static final Item MUD_BRICKS = register(new BlockItem("mud_bricks", builder()));
- public static final Item DEEPSLATE_BRICKS = register(new BlockItem("deepslate_bricks", builder()));
- public static final Item CRACKED_DEEPSLATE_BRICKS = register(new BlockItem("cracked_deepslate_bricks", builder()));
- public static final Item DEEPSLATE_TILES = register(new BlockItem("deepslate_tiles", builder()));
- public static final Item CRACKED_DEEPSLATE_TILES = register(new BlockItem("cracked_deepslate_tiles", builder()));
- public static final Item CHISELED_DEEPSLATE = register(new BlockItem("chiseled_deepslate", builder()));
- public static final Item REINFORCED_DEEPSLATE = register(new BlockItem("reinforced_deepslate", builder()));
- public static final Item BROWN_MUSHROOM_BLOCK = register(new BlockItem("brown_mushroom_block", builder()));
- public static final Item RED_MUSHROOM_BLOCK = register(new BlockItem("red_mushroom_block", builder()));
- public static final Item MUSHROOM_STEM = register(new BlockItem("mushroom_stem", builder()));
- public static final Item IRON_BARS = register(new BlockItem("iron_bars", builder()));
- public static final Item CHAIN = register(new BlockItem("chain", builder()));
- public static final Item GLASS_PANE = register(new BlockItem("glass_pane", builder()));
- public static final Item MELON = register(new BlockItem("melon", builder()));
- public static final Item VINE = register(new BlockItem("vine", builder()));
- public static final Item GLOW_LICHEN = register(new BlockItem("glow_lichen", builder()));
- public static final Item BRICK_STAIRS = register(new BlockItem("brick_stairs", builder()));
- public static final Item STONE_BRICK_STAIRS = register(new BlockItem("stone_brick_stairs", builder()));
- public static final Item MUD_BRICK_STAIRS = register(new BlockItem("mud_brick_stairs", builder()));
- public static final Item MYCELIUM = register(new BlockItem("mycelium", builder()));
- public static final Item LILY_PAD = register(new BlockItem("lily_pad", builder()));
- public static final Item NETHER_BRICKS = register(new BlockItem("nether_bricks", builder()));
- public static final Item CRACKED_NETHER_BRICKS = register(new BlockItem("cracked_nether_bricks", builder()));
- public static final Item CHISELED_NETHER_BRICKS = register(new BlockItem("chiseled_nether_bricks", builder()));
- public static final Item NETHER_BRICK_FENCE = register(new BlockItem("nether_brick_fence", builder()));
- public static final Item NETHER_BRICK_STAIRS = register(new BlockItem("nether_brick_stairs", builder()));
- public static final Item SCULK = register(new BlockItem("sculk", builder()));
- public static final Item SCULK_VEIN = register(new BlockItem("sculk_vein", builder()));
- public static final Item SCULK_CATALYST = register(new BlockItem("sculk_catalyst", builder()));
- public static final Item SCULK_SHRIEKER = register(new BlockItem("sculk_shrieker", builder()));
- public static final Item ENCHANTING_TABLE = register(new BlockItem("enchanting_table", builder()));
- public static final Item END_PORTAL_FRAME = register(new BlockItem("end_portal_frame", builder()));
- public static final Item END_STONE = register(new BlockItem("end_stone", builder()));
- public static final Item END_STONE_BRICKS = register(new BlockItem("end_stone_bricks", builder()));
- public static final Item DRAGON_EGG = register(new BlockItem("dragon_egg", builder()));
- public static final Item SANDSTONE_STAIRS = register(new BlockItem("sandstone_stairs", builder()));
- public static final Item ENDER_CHEST = register(new ChestItem("ender_chest", builder()));
- public static final Item EMERALD_BLOCK = register(new BlockItem("emerald_block", builder()));
- public static final Item OAK_STAIRS = register(new BlockItem("oak_stairs", builder()));
- public static final Item SPRUCE_STAIRS = register(new BlockItem("spruce_stairs", builder()));
- public static final Item BIRCH_STAIRS = register(new BlockItem("birch_stairs", builder()));
- public static final Item JUNGLE_STAIRS = register(new BlockItem("jungle_stairs", builder()));
- public static final Item ACACIA_STAIRS = register(new BlockItem("acacia_stairs", builder()));
- public static final Item CHERRY_STAIRS = register(new BlockItem("cherry_stairs", builder()));
- public static final Item DARK_OAK_STAIRS = register(new BlockItem("dark_oak_stairs", builder()));
- public static final Item MANGROVE_STAIRS = register(new BlockItem("mangrove_stairs", builder()));
- public static final Item BAMBOO_STAIRS = register(new BlockItem("bamboo_stairs", builder()));
- public static final Item BAMBOO_MOSAIC_STAIRS = register(new BlockItem("bamboo_mosaic_stairs", builder()));
- public static final Item CRIMSON_STAIRS = register(new BlockItem("crimson_stairs", builder()));
- public static final Item WARPED_STAIRS = register(new BlockItem("warped_stairs", builder()));
- public static final Item COMMAND_BLOCK = register(new BlockItem("command_block", builder()));
- public static final Item BEACON = register(new BlockItem("beacon", builder()));
- public static final Item COBBLESTONE_WALL = register(new BlockItem("cobblestone_wall", builder()));
- public static final Item MOSSY_COBBLESTONE_WALL = register(new BlockItem("mossy_cobblestone_wall", builder()));
- public static final Item BRICK_WALL = register(new BlockItem("brick_wall", builder()));
- public static final Item PRISMARINE_WALL = register(new BlockItem("prismarine_wall", builder()));
- public static final Item RED_SANDSTONE_WALL = register(new BlockItem("red_sandstone_wall", builder()));
- public static final Item MOSSY_STONE_BRICK_WALL = register(new BlockItem("mossy_stone_brick_wall", builder()));
- public static final Item GRANITE_WALL = register(new BlockItem("granite_wall", builder()));
- public static final Item STONE_BRICK_WALL = register(new BlockItem("stone_brick_wall", builder()));
- public static final Item MUD_BRICK_WALL = register(new BlockItem("mud_brick_wall", builder()));
- public static final Item NETHER_BRICK_WALL = register(new BlockItem("nether_brick_wall", builder()));
- public static final Item ANDESITE_WALL = register(new BlockItem("andesite_wall", builder()));
- public static final Item RED_NETHER_BRICK_WALL = register(new BlockItem("red_nether_brick_wall", builder()));
- public static final Item SANDSTONE_WALL = register(new BlockItem("sandstone_wall", builder()));
- public static final Item END_STONE_BRICK_WALL = register(new BlockItem("end_stone_brick_wall", builder()));
- public static final Item DIORITE_WALL = register(new BlockItem("diorite_wall", builder()));
- public static final Item BLACKSTONE_WALL = register(new BlockItem("blackstone_wall", builder()));
- public static final Item POLISHED_BLACKSTONE_WALL = register(new BlockItem("polished_blackstone_wall", builder()));
- public static final Item POLISHED_BLACKSTONE_BRICK_WALL = register(new BlockItem("polished_blackstone_brick_wall", builder()));
- public static final Item COBBLED_DEEPSLATE_WALL = register(new BlockItem("cobbled_deepslate_wall", builder()));
- public static final Item POLISHED_DEEPSLATE_WALL = register(new BlockItem("polished_deepslate_wall", builder()));
- public static final Item DEEPSLATE_BRICK_WALL = register(new BlockItem("deepslate_brick_wall", builder()));
- public static final Item DEEPSLATE_TILE_WALL = register(new BlockItem("deepslate_tile_wall", builder()));
- public static final Item ANVIL = register(new BlockItem("anvil", builder()));
- public static final Item CHIPPED_ANVIL = register(new BlockItem("chipped_anvil", builder()));
- public static final Item DAMAGED_ANVIL = register(new BlockItem("damaged_anvil", builder()));
- public static final Item CHISELED_QUARTZ_BLOCK = register(new BlockItem("chiseled_quartz_block", builder()));
- public static final Item QUARTZ_BLOCK = register(new BlockItem("quartz_block", builder()));
- public static final Item QUARTZ_BRICKS = register(new BlockItem("quartz_bricks", builder()));
- public static final Item QUARTZ_PILLAR = register(new BlockItem("quartz_pillar", builder()));
- public static final Item QUARTZ_STAIRS = register(new BlockItem("quartz_stairs", builder()));
- public static final Item WHITE_TERRACOTTA = register(new BlockItem("white_terracotta", builder()));
- public static final Item ORANGE_TERRACOTTA = register(new BlockItem("orange_terracotta", builder()));
- public static final Item MAGENTA_TERRACOTTA = register(new BlockItem("magenta_terracotta", builder()));
- public static final Item LIGHT_BLUE_TERRACOTTA = register(new BlockItem("light_blue_terracotta", builder()));
- public static final Item YELLOW_TERRACOTTA = register(new BlockItem("yellow_terracotta", builder()));
- public static final Item LIME_TERRACOTTA = register(new BlockItem("lime_terracotta", builder()));
- public static final Item PINK_TERRACOTTA = register(new BlockItem("pink_terracotta", builder()));
- public static final Item GRAY_TERRACOTTA = register(new BlockItem("gray_terracotta", builder()));
- public static final Item LIGHT_GRAY_TERRACOTTA = register(new BlockItem("light_gray_terracotta", builder()));
- public static final Item CYAN_TERRACOTTA = register(new BlockItem("cyan_terracotta", builder()));
- public static final Item PURPLE_TERRACOTTA = register(new BlockItem("purple_terracotta", builder()));
- public static final Item BLUE_TERRACOTTA = register(new BlockItem("blue_terracotta", builder()));
- public static final Item BROWN_TERRACOTTA = register(new BlockItem("brown_terracotta", builder()));
- public static final Item GREEN_TERRACOTTA = register(new BlockItem("green_terracotta", builder()));
- public static final Item RED_TERRACOTTA = register(new BlockItem("red_terracotta", builder()));
- public static final Item BLACK_TERRACOTTA = register(new BlockItem("black_terracotta", builder()));
- public static final Item BARRIER = register(new BlockItem("barrier", builder()));
- public static final Item LIGHT = register(new BlockItem("light", builder()));
- public static final Item HAY_BLOCK = register(new BlockItem("hay_block", builder()));
- public static final Item WHITE_CARPET = register(new BlockItem("white_carpet", builder()));
- public static final Item ORANGE_CARPET = register(new BlockItem("orange_carpet", builder()));
- public static final Item MAGENTA_CARPET = register(new BlockItem("magenta_carpet", builder()));
- public static final Item LIGHT_BLUE_CARPET = register(new BlockItem("light_blue_carpet", builder()));
- public static final Item YELLOW_CARPET = register(new BlockItem("yellow_carpet", builder()));
- public static final Item LIME_CARPET = register(new BlockItem("lime_carpet", builder()));
- public static final Item PINK_CARPET = register(new BlockItem("pink_carpet", builder()));
- public static final Item GRAY_CARPET = register(new BlockItem("gray_carpet", builder()));
- public static final Item LIGHT_GRAY_CARPET = register(new BlockItem("light_gray_carpet", builder()));
- public static final Item CYAN_CARPET = register(new BlockItem("cyan_carpet", builder()));
- public static final Item PURPLE_CARPET = register(new BlockItem("purple_carpet", builder()));
- public static final Item BLUE_CARPET = register(new BlockItem("blue_carpet", builder()));
- public static final Item BROWN_CARPET = register(new BlockItem("brown_carpet", builder()));
- public static final Item GREEN_CARPET = register(new BlockItem("green_carpet", builder()));
- public static final Item RED_CARPET = register(new BlockItem("red_carpet", builder()));
- public static final Item BLACK_CARPET = register(new BlockItem("black_carpet", builder()));
- public static final Item TERRACOTTA = register(new BlockItem("terracotta", builder()));
- public static final Item PACKED_ICE = register(new BlockItem("packed_ice", builder()));
- public static final Item DIRT_PATH = register(new BlockItem("dirt_path", builder()));
- public static final Item SUNFLOWER = register(new BlockItem("sunflower", builder()));
- public static final Item LILAC = register(new BlockItem("lilac", builder()));
- public static final Item ROSE_BUSH = register(new BlockItem("rose_bush", builder()));
- public static final Item PEONY = register(new BlockItem("peony", builder()));
- public static final Item TALL_GRASS = register(new BlockItem("tall_grass", builder()));
- public static final Item LARGE_FERN = register(new BlockItem("large_fern", builder()));
- public static final Item WHITE_STAINED_GLASS = register(new BlockItem("white_stained_glass", builder()));
- public static final Item ORANGE_STAINED_GLASS = register(new BlockItem("orange_stained_glass", builder()));
- public static final Item MAGENTA_STAINED_GLASS = register(new BlockItem("magenta_stained_glass", builder()));
- public static final Item LIGHT_BLUE_STAINED_GLASS = register(new BlockItem("light_blue_stained_glass", builder()));
- public static final Item YELLOW_STAINED_GLASS = register(new BlockItem("yellow_stained_glass", builder()));
- public static final Item LIME_STAINED_GLASS = register(new BlockItem("lime_stained_glass", builder()));
- public static final Item PINK_STAINED_GLASS = register(new BlockItem("pink_stained_glass", builder()));
- public static final Item GRAY_STAINED_GLASS = register(new BlockItem("gray_stained_glass", builder()));
- public static final Item LIGHT_GRAY_STAINED_GLASS = register(new BlockItem("light_gray_stained_glass", builder()));
- public static final Item CYAN_STAINED_GLASS = register(new BlockItem("cyan_stained_glass", builder()));
- public static final Item PURPLE_STAINED_GLASS = register(new BlockItem("purple_stained_glass", builder()));
- public static final Item BLUE_STAINED_GLASS = register(new BlockItem("blue_stained_glass", builder()));
- public static final Item BROWN_STAINED_GLASS = register(new BlockItem("brown_stained_glass", builder()));
- public static final Item GREEN_STAINED_GLASS = register(new BlockItem("green_stained_glass", builder()));
- public static final Item RED_STAINED_GLASS = register(new BlockItem("red_stained_glass", builder()));
- public static final Item BLACK_STAINED_GLASS = register(new BlockItem("black_stained_glass", builder()));
- public static final Item WHITE_STAINED_GLASS_PANE = register(new BlockItem("white_stained_glass_pane", builder()));
- public static final Item ORANGE_STAINED_GLASS_PANE = register(new BlockItem("orange_stained_glass_pane", builder()));
- public static final Item MAGENTA_STAINED_GLASS_PANE = register(new BlockItem("magenta_stained_glass_pane", builder()));
- public static final Item LIGHT_BLUE_STAINED_GLASS_PANE = register(new BlockItem("light_blue_stained_glass_pane", builder()));
- public static final Item YELLOW_STAINED_GLASS_PANE = register(new BlockItem("yellow_stained_glass_pane", builder()));
- public static final Item LIME_STAINED_GLASS_PANE = register(new BlockItem("lime_stained_glass_pane", builder()));
- public static final Item PINK_STAINED_GLASS_PANE = register(new BlockItem("pink_stained_glass_pane", builder()));
- public static final Item GRAY_STAINED_GLASS_PANE = register(new BlockItem("gray_stained_glass_pane", builder()));
- public static final Item LIGHT_GRAY_STAINED_GLASS_PANE = register(new BlockItem("light_gray_stained_glass_pane", builder()));
- public static final Item CYAN_STAINED_GLASS_PANE = register(new BlockItem("cyan_stained_glass_pane", builder()));
- public static final Item PURPLE_STAINED_GLASS_PANE = register(new BlockItem("purple_stained_glass_pane", builder()));
- public static final Item BLUE_STAINED_GLASS_PANE = register(new BlockItem("blue_stained_glass_pane", builder()));
- public static final Item BROWN_STAINED_GLASS_PANE = register(new BlockItem("brown_stained_glass_pane", builder()));
- public static final Item GREEN_STAINED_GLASS_PANE = register(new BlockItem("green_stained_glass_pane", builder()));
- public static final Item RED_STAINED_GLASS_PANE = register(new BlockItem("red_stained_glass_pane", builder()));
- public static final Item BLACK_STAINED_GLASS_PANE = register(new BlockItem("black_stained_glass_pane", builder()));
- public static final Item PRISMARINE = register(new BlockItem("prismarine", builder()));
- public static final Item PRISMARINE_BRICKS = register(new BlockItem("prismarine_bricks", builder()));
- public static final Item DARK_PRISMARINE = register(new BlockItem("dark_prismarine", builder()));
- public static final Item PRISMARINE_STAIRS = register(new BlockItem("prismarine_stairs", builder()));
- public static final Item PRISMARINE_BRICK_STAIRS = register(new BlockItem("prismarine_brick_stairs", builder()));
- public static final Item DARK_PRISMARINE_STAIRS = register(new BlockItem("dark_prismarine_stairs", builder()));
- public static final Item SEA_LANTERN = register(new BlockItem("sea_lantern", builder()));
- public static final Item RED_SANDSTONE = register(new BlockItem("red_sandstone", builder()));
- public static final Item CHISELED_RED_SANDSTONE = register(new BlockItem("chiseled_red_sandstone", builder()));
- public static final Item CUT_RED_SANDSTONE = register(new BlockItem("cut_red_sandstone", builder()));
- public static final Item RED_SANDSTONE_STAIRS = register(new BlockItem("red_sandstone_stairs", builder()));
- public static final Item REPEATING_COMMAND_BLOCK = register(new BlockItem("repeating_command_block", builder()));
- public static final Item CHAIN_COMMAND_BLOCK = register(new BlockItem("chain_command_block", builder()));
- public static final Item MAGMA_BLOCK = register(new BlockItem("magma_block", builder()));
- public static final Item NETHER_WART_BLOCK = register(new BlockItem("nether_wart_block", builder()));
- public static final Item WARPED_WART_BLOCK = register(new BlockItem("warped_wart_block", builder()));
- public static final Item RED_NETHER_BRICKS = register(new BlockItem("red_nether_bricks", builder()));
- public static final Item BONE_BLOCK = register(new BlockItem("bone_block", builder()));
- public static final Item STRUCTURE_VOID = register(new BlockItem("structure_void", builder()));
- public static final Item SHULKER_BOX = register(new ShulkerBoxItem("shulker_box", builder().stackSize(1)));
- public static final Item WHITE_SHULKER_BOX = register(new ShulkerBoxItem("white_shulker_box", builder().stackSize(1)));
- public static final Item ORANGE_SHULKER_BOX = register(new ShulkerBoxItem("orange_shulker_box", builder().stackSize(1)));
- public static final Item MAGENTA_SHULKER_BOX = register(new ShulkerBoxItem("magenta_shulker_box", builder().stackSize(1)));
- public static final Item LIGHT_BLUE_SHULKER_BOX = register(new ShulkerBoxItem("light_blue_shulker_box", builder().stackSize(1)));
- public static final Item YELLOW_SHULKER_BOX = register(new ShulkerBoxItem("yellow_shulker_box", builder().stackSize(1)));
- public static final Item LIME_SHULKER_BOX = register(new ShulkerBoxItem("lime_shulker_box", builder().stackSize(1)));
- public static final Item PINK_SHULKER_BOX = register(new ShulkerBoxItem("pink_shulker_box", builder().stackSize(1)));
- public static final Item GRAY_SHULKER_BOX = register(new ShulkerBoxItem("gray_shulker_box", builder().stackSize(1)));
- public static final Item LIGHT_GRAY_SHULKER_BOX = register(new ShulkerBoxItem("light_gray_shulker_box", builder().stackSize(1)));
- public static final Item CYAN_SHULKER_BOX = register(new ShulkerBoxItem("cyan_shulker_box", builder().stackSize(1)));
- public static final Item PURPLE_SHULKER_BOX = register(new ShulkerBoxItem("purple_shulker_box", builder().stackSize(1)));
- public static final Item BLUE_SHULKER_BOX = register(new ShulkerBoxItem("blue_shulker_box", builder().stackSize(1)));
- public static final Item BROWN_SHULKER_BOX = register(new ShulkerBoxItem("brown_shulker_box", builder().stackSize(1)));
- public static final Item GREEN_SHULKER_BOX = register(new ShulkerBoxItem("green_shulker_box", builder().stackSize(1)));
- public static final Item RED_SHULKER_BOX = register(new ShulkerBoxItem("red_shulker_box", builder().stackSize(1)));
- public static final Item BLACK_SHULKER_BOX = register(new ShulkerBoxItem("black_shulker_box", builder().stackSize(1)));
- public static final Item WHITE_GLAZED_TERRACOTTA = register(new BlockItem("white_glazed_terracotta", builder()));
- public static final Item ORANGE_GLAZED_TERRACOTTA = register(new BlockItem("orange_glazed_terracotta", builder()));
- public static final Item MAGENTA_GLAZED_TERRACOTTA = register(new BlockItem("magenta_glazed_terracotta", builder()));
- public static final Item LIGHT_BLUE_GLAZED_TERRACOTTA = register(new BlockItem("light_blue_glazed_terracotta", builder()));
- public static final Item YELLOW_GLAZED_TERRACOTTA = register(new BlockItem("yellow_glazed_terracotta", builder()));
- public static final Item LIME_GLAZED_TERRACOTTA = register(new BlockItem("lime_glazed_terracotta", builder()));
- public static final Item PINK_GLAZED_TERRACOTTA = register(new BlockItem("pink_glazed_terracotta", builder()));
- public static final Item GRAY_GLAZED_TERRACOTTA = register(new BlockItem("gray_glazed_terracotta", builder()));
- public static final Item LIGHT_GRAY_GLAZED_TERRACOTTA = register(new BlockItem("light_gray_glazed_terracotta", builder()));
- public static final Item CYAN_GLAZED_TERRACOTTA = register(new BlockItem("cyan_glazed_terracotta", builder()));
- public static final Item PURPLE_GLAZED_TERRACOTTA = register(new BlockItem("purple_glazed_terracotta", builder()));
- public static final Item BLUE_GLAZED_TERRACOTTA = register(new BlockItem("blue_glazed_terracotta", builder()));
- public static final Item BROWN_GLAZED_TERRACOTTA = register(new BlockItem("brown_glazed_terracotta", builder()));
- public static final Item GREEN_GLAZED_TERRACOTTA = register(new BlockItem("green_glazed_terracotta", builder()));
- public static final Item RED_GLAZED_TERRACOTTA = register(new BlockItem("red_glazed_terracotta", builder()));
- public static final Item BLACK_GLAZED_TERRACOTTA = register(new BlockItem("black_glazed_terracotta", builder()));
- public static final Item WHITE_CONCRETE = register(new BlockItem("white_concrete", builder()));
- public static final Item ORANGE_CONCRETE = register(new BlockItem("orange_concrete", builder()));
- public static final Item MAGENTA_CONCRETE = register(new BlockItem("magenta_concrete", builder()));
- public static final Item LIGHT_BLUE_CONCRETE = register(new BlockItem("light_blue_concrete", builder()));
- public static final Item YELLOW_CONCRETE = register(new BlockItem("yellow_concrete", builder()));
- public static final Item LIME_CONCRETE = register(new BlockItem("lime_concrete", builder()));
- public static final Item PINK_CONCRETE = register(new BlockItem("pink_concrete", builder()));
- public static final Item GRAY_CONCRETE = register(new BlockItem("gray_concrete", builder()));
- public static final Item LIGHT_GRAY_CONCRETE = register(new BlockItem("light_gray_concrete", builder()));
- public static final Item CYAN_CONCRETE = register(new BlockItem("cyan_concrete", builder()));
- public static final Item PURPLE_CONCRETE = register(new BlockItem("purple_concrete", builder()));
- public static final Item BLUE_CONCRETE = register(new BlockItem("blue_concrete", builder()));
- public static final Item BROWN_CONCRETE = register(new BlockItem("brown_concrete", builder()));
- public static final Item GREEN_CONCRETE = register(new BlockItem("green_concrete", builder()));
- public static final Item RED_CONCRETE = register(new BlockItem("red_concrete", builder()));
- public static final Item BLACK_CONCRETE = register(new BlockItem("black_concrete", builder()));
- public static final Item WHITE_CONCRETE_POWDER = register(new BlockItem("white_concrete_powder", builder()));
- public static final Item ORANGE_CONCRETE_POWDER = register(new BlockItem("orange_concrete_powder", builder()));
- public static final Item MAGENTA_CONCRETE_POWDER = register(new BlockItem("magenta_concrete_powder", builder()));
- public static final Item LIGHT_BLUE_CONCRETE_POWDER = register(new BlockItem("light_blue_concrete_powder", builder()));
- public static final Item YELLOW_CONCRETE_POWDER = register(new BlockItem("yellow_concrete_powder", builder()));
- public static final Item LIME_CONCRETE_POWDER = register(new BlockItem("lime_concrete_powder", builder()));
- public static final Item PINK_CONCRETE_POWDER = register(new BlockItem("pink_concrete_powder", builder()));
- public static final Item GRAY_CONCRETE_POWDER = register(new BlockItem("gray_concrete_powder", builder()));
- public static final Item LIGHT_GRAY_CONCRETE_POWDER = register(new BlockItem("light_gray_concrete_powder", builder()));
- public static final Item CYAN_CONCRETE_POWDER = register(new BlockItem("cyan_concrete_powder", builder()));
- public static final Item PURPLE_CONCRETE_POWDER = register(new BlockItem("purple_concrete_powder", builder()));
- public static final Item BLUE_CONCRETE_POWDER = register(new BlockItem("blue_concrete_powder", builder()));
- public static final Item BROWN_CONCRETE_POWDER = register(new BlockItem("brown_concrete_powder", builder()));
- public static final Item GREEN_CONCRETE_POWDER = register(new BlockItem("green_concrete_powder", builder()));
- public static final Item RED_CONCRETE_POWDER = register(new BlockItem("red_concrete_powder", builder()));
- public static final Item BLACK_CONCRETE_POWDER = register(new BlockItem("black_concrete_powder", builder()));
- public static final Item TURTLE_EGG = register(new BlockItem("turtle_egg", builder()));
- public static final Item SNIFFER_EGG = register(new BlockItem("sniffer_egg", builder()));
- public static final Item DEAD_TUBE_CORAL_BLOCK = register(new BlockItem("dead_tube_coral_block", builder()));
- public static final Item DEAD_BRAIN_CORAL_BLOCK = register(new BlockItem("dead_brain_coral_block", builder()));
- public static final Item DEAD_BUBBLE_CORAL_BLOCK = register(new BlockItem("dead_bubble_coral_block", builder()));
- public static final Item DEAD_FIRE_CORAL_BLOCK = register(new BlockItem("dead_fire_coral_block", builder()));
- public static final Item DEAD_HORN_CORAL_BLOCK = register(new BlockItem("dead_horn_coral_block", builder()));
- public static final Item TUBE_CORAL_BLOCK = register(new BlockItem("tube_coral_block", builder()));
- public static final Item BRAIN_CORAL_BLOCK = register(new BlockItem("brain_coral_block", builder()));
- public static final Item BUBBLE_CORAL_BLOCK = register(new BlockItem("bubble_coral_block", builder()));
- public static final Item FIRE_CORAL_BLOCK = register(new BlockItem("fire_coral_block", builder()));
- public static final Item HORN_CORAL_BLOCK = register(new BlockItem("horn_coral_block", builder()));
- public static final Item TUBE_CORAL = register(new BlockItem("tube_coral", builder()));
- public static final Item BRAIN_CORAL = register(new BlockItem("brain_coral", builder()));
- public static final Item BUBBLE_CORAL = register(new BlockItem("bubble_coral", builder()));
- public static final Item FIRE_CORAL = register(new BlockItem("fire_coral", builder()));
- public static final Item HORN_CORAL = register(new BlockItem("horn_coral", builder()));
- public static final Item DEAD_BRAIN_CORAL = register(new BlockItem("dead_brain_coral", builder()));
- public static final Item DEAD_BUBBLE_CORAL = register(new BlockItem("dead_bubble_coral", builder()));
- public static final Item DEAD_FIRE_CORAL = register(new BlockItem("dead_fire_coral", builder()));
- public static final Item DEAD_HORN_CORAL = register(new BlockItem("dead_horn_coral", builder()));
- public static final Item DEAD_TUBE_CORAL = register(new BlockItem("dead_tube_coral", builder()));
- public static final Item TUBE_CORAL_FAN = register(new BlockItem("tube_coral_fan", builder()));
- public static final Item BRAIN_CORAL_FAN = register(new BlockItem("brain_coral_fan", builder()));
- public static final Item BUBBLE_CORAL_FAN = register(new BlockItem("bubble_coral_fan", builder()));
- public static final Item FIRE_CORAL_FAN = register(new BlockItem("fire_coral_fan", builder()));
- public static final Item HORN_CORAL_FAN = register(new BlockItem("horn_coral_fan", builder()));
- public static final Item DEAD_TUBE_CORAL_FAN = register(new BlockItem("dead_tube_coral_fan", builder()));
- public static final Item DEAD_BRAIN_CORAL_FAN = register(new BlockItem("dead_brain_coral_fan", builder()));
- public static final Item DEAD_BUBBLE_CORAL_FAN = register(new BlockItem("dead_bubble_coral_fan", builder()));
- public static final Item DEAD_FIRE_CORAL_FAN = register(new BlockItem("dead_fire_coral_fan", builder()));
- public static final Item DEAD_HORN_CORAL_FAN = register(new BlockItem("dead_horn_coral_fan", builder()));
- public static final Item BLUE_ICE = register(new BlockItem("blue_ice", builder()));
- public static final Item CONDUIT = register(new BlockItem("conduit", builder()));
- public static final Item POLISHED_GRANITE_STAIRS = register(new BlockItem("polished_granite_stairs", builder()));
- public static final Item SMOOTH_RED_SANDSTONE_STAIRS = register(new BlockItem("smooth_red_sandstone_stairs", builder()));
- public static final Item MOSSY_STONE_BRICK_STAIRS = register(new BlockItem("mossy_stone_brick_stairs", builder()));
- public static final Item POLISHED_DIORITE_STAIRS = register(new BlockItem("polished_diorite_stairs", builder()));
- public static final Item MOSSY_COBBLESTONE_STAIRS = register(new BlockItem("mossy_cobblestone_stairs", builder()));
- public static final Item END_STONE_BRICK_STAIRS = register(new BlockItem("end_stone_brick_stairs", builder()));
- public static final Item STONE_STAIRS = register(new BlockItem("stone_stairs", builder()));
- public static final Item SMOOTH_SANDSTONE_STAIRS = register(new BlockItem("smooth_sandstone_stairs", builder()));
- public static final Item SMOOTH_QUARTZ_STAIRS = register(new BlockItem("smooth_quartz_stairs", builder()));
- public static final Item GRANITE_STAIRS = register(new BlockItem("granite_stairs", builder()));
- public static final Item ANDESITE_STAIRS = register(new BlockItem("andesite_stairs", builder()));
- public static final Item RED_NETHER_BRICK_STAIRS = register(new BlockItem("red_nether_brick_stairs", builder()));
- public static final Item POLISHED_ANDESITE_STAIRS = register(new BlockItem("polished_andesite_stairs", builder()));
- public static final Item DIORITE_STAIRS = register(new BlockItem("diorite_stairs", builder()));
- public static final Item COBBLED_DEEPSLATE_STAIRS = register(new BlockItem("cobbled_deepslate_stairs", builder()));
- public static final Item POLISHED_DEEPSLATE_STAIRS = register(new BlockItem("polished_deepslate_stairs", builder()));
- public static final Item DEEPSLATE_BRICK_STAIRS = register(new BlockItem("deepslate_brick_stairs", builder()));
- public static final Item DEEPSLATE_TILE_STAIRS = register(new BlockItem("deepslate_tile_stairs", builder()));
- public static final Item POLISHED_GRANITE_SLAB = register(new BlockItem("polished_granite_slab", builder()));
- public static final Item SMOOTH_RED_SANDSTONE_SLAB = register(new BlockItem("smooth_red_sandstone_slab", builder()));
- public static final Item MOSSY_STONE_BRICK_SLAB = register(new BlockItem("mossy_stone_brick_slab", builder()));
- public static final Item POLISHED_DIORITE_SLAB = register(new BlockItem("polished_diorite_slab", builder()));
- public static final Item MOSSY_COBBLESTONE_SLAB = register(new BlockItem("mossy_cobblestone_slab", builder()));
- public static final Item END_STONE_BRICK_SLAB = register(new BlockItem("end_stone_brick_slab", builder()));
- public static final Item SMOOTH_SANDSTONE_SLAB = register(new BlockItem("smooth_sandstone_slab", builder()));
- public static final Item SMOOTH_QUARTZ_SLAB = register(new BlockItem("smooth_quartz_slab", builder()));
- public static final Item GRANITE_SLAB = register(new BlockItem("granite_slab", builder()));
- public static final Item ANDESITE_SLAB = register(new BlockItem("andesite_slab", builder()));
- public static final Item RED_NETHER_BRICK_SLAB = register(new BlockItem("red_nether_brick_slab", builder()));
- public static final Item POLISHED_ANDESITE_SLAB = register(new BlockItem("polished_andesite_slab", builder()));
- public static final Item DIORITE_SLAB = register(new BlockItem("diorite_slab", builder()));
- public static final Item COBBLED_DEEPSLATE_SLAB = register(new BlockItem("cobbled_deepslate_slab", builder()));
- public static final Item POLISHED_DEEPSLATE_SLAB = register(new BlockItem("polished_deepslate_slab", builder()));
- public static final Item DEEPSLATE_BRICK_SLAB = register(new BlockItem("deepslate_brick_slab", builder()));
- public static final Item DEEPSLATE_TILE_SLAB = register(new BlockItem("deepslate_tile_slab", builder()));
- public static final Item SCAFFOLDING = register(new BlockItem("scaffolding", builder()));
- public static final Item REDSTONE = register(new BlockItem("redstone", builder()));
- public static final Item REDSTONE_TORCH = register(new BlockItem("redstone_torch", builder()));
- public static final Item REDSTONE_BLOCK = register(new BlockItem("redstone_block", builder()));
- public static final Item REPEATER = register(new BlockItem("repeater", builder()));
- public static final Item COMPARATOR = register(new BlockItem("comparator", builder()));
- public static final Item PISTON = register(new BlockItem("piston", builder()));
- public static final Item STICKY_PISTON = register(new BlockItem("sticky_piston", builder()));
- public static final Item SLIME_BLOCK = register(new BlockItem("slime_block", builder()));
- public static final Item HONEY_BLOCK = register(new BlockItem("honey_block", builder()));
- public static final Item OBSERVER = register(new BlockItem("observer", builder()));
- public static final Item HOPPER = register(new BlockItem("hopper", builder()));
- public static final Item DISPENSER = register(new BlockItem("dispenser", builder()));
- public static final Item DROPPER = register(new BlockItem("dropper", builder()));
- public static final Item LECTERN = register(new BlockItem("lectern", builder()));
- public static final Item TARGET = register(new BlockItem("target", builder()));
- public static final Item LEVER = register(new BlockItem("lever", builder()));
- public static final Item LIGHTNING_ROD = register(new BlockItem("lightning_rod", builder()));
- public static final Item DAYLIGHT_DETECTOR = register(new BlockItem("daylight_detector", builder()));
- public static final Item SCULK_SENSOR = register(new BlockItem("sculk_sensor", builder()));
- public static final Item CALIBRATED_SCULK_SENSOR = register(new BlockItem("calibrated_sculk_sensor", builder()));
- public static final Item TRIPWIRE_HOOK = register(new BlockItem("tripwire_hook", builder()));
- public static final Item TRAPPED_CHEST = register(new ChestItem("trapped_chest", builder()));
- public static final Item TNT = register(new BlockItem("tnt", builder()));
- public static final Item REDSTONE_LAMP = register(new BlockItem("redstone_lamp", builder()));
- public static final Item NOTE_BLOCK = register(new BlockItem("note_block", builder()));
- public static final Item STONE_BUTTON = register(new BlockItem("stone_button", builder()));
- public static final Item POLISHED_BLACKSTONE_BUTTON = register(new BlockItem("polished_blackstone_button", builder()));
- public static final Item OAK_BUTTON = register(new BlockItem("oak_button", builder()));
- public static final Item SPRUCE_BUTTON = register(new BlockItem("spruce_button", builder()));
- public static final Item BIRCH_BUTTON = register(new BlockItem("birch_button", builder()));
- public static final Item JUNGLE_BUTTON = register(new BlockItem("jungle_button", builder()));
- public static final Item ACACIA_BUTTON = register(new BlockItem("acacia_button", builder()));
- public static final Item CHERRY_BUTTON = register(new BlockItem("cherry_button", builder()));
- public static final Item DARK_OAK_BUTTON = register(new BlockItem("dark_oak_button", builder()));
- public static final Item MANGROVE_BUTTON = register(new BlockItem("mangrove_button", builder()));
- public static final Item BAMBOO_BUTTON = register(new BlockItem("bamboo_button", builder()));
- public static final Item CRIMSON_BUTTON = register(new BlockItem("crimson_button", builder()));
- public static final Item WARPED_BUTTON = register(new BlockItem("warped_button", builder()));
- public static final Item STONE_PRESSURE_PLATE = register(new BlockItem("stone_pressure_plate", builder()));
- public static final Item POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new BlockItem("polished_blackstone_pressure_plate", builder()));
- public static final Item LIGHT_WEIGHTED_PRESSURE_PLATE = register(new BlockItem("light_weighted_pressure_plate", builder()));
- public static final Item HEAVY_WEIGHTED_PRESSURE_PLATE = register(new BlockItem("heavy_weighted_pressure_plate", builder()));
- public static final Item OAK_PRESSURE_PLATE = register(new BlockItem("oak_pressure_plate", builder()));
- public static final Item SPRUCE_PRESSURE_PLATE = register(new BlockItem("spruce_pressure_plate", builder()));
- public static final Item BIRCH_PRESSURE_PLATE = register(new BlockItem("birch_pressure_plate", builder()));
- public static final Item JUNGLE_PRESSURE_PLATE = register(new BlockItem("jungle_pressure_plate", builder()));
- public static final Item ACACIA_PRESSURE_PLATE = register(new BlockItem("acacia_pressure_plate", builder()));
- public static final Item CHERRY_PRESSURE_PLATE = register(new BlockItem("cherry_pressure_plate", builder()));
- public static final Item DARK_OAK_PRESSURE_PLATE = register(new BlockItem("dark_oak_pressure_plate", builder()));
- public static final Item MANGROVE_PRESSURE_PLATE = register(new BlockItem("mangrove_pressure_plate", builder()));
- public static final Item BAMBOO_PRESSURE_PLATE = register(new BlockItem("bamboo_pressure_plate", builder()));
- public static final Item CRIMSON_PRESSURE_PLATE = register(new BlockItem("crimson_pressure_plate", builder()));
- public static final Item WARPED_PRESSURE_PLATE = register(new BlockItem("warped_pressure_plate", builder()));
- public static final Item IRON_DOOR = register(new BlockItem("iron_door", builder()));
- public static final Item OAK_DOOR = register(new BlockItem("oak_door", builder()));
- public static final Item SPRUCE_DOOR = register(new BlockItem("spruce_door", builder()));
- public static final Item BIRCH_DOOR = register(new BlockItem("birch_door", builder()));
- public static final Item JUNGLE_DOOR = register(new BlockItem("jungle_door", builder()));
- public static final Item ACACIA_DOOR = register(new BlockItem("acacia_door", builder()));
- public static final Item CHERRY_DOOR = register(new BlockItem("cherry_door", builder()));
- public static final Item DARK_OAK_DOOR = register(new BlockItem("dark_oak_door", builder()));
- public static final Item MANGROVE_DOOR = register(new BlockItem("mangrove_door", builder()));
- public static final Item BAMBOO_DOOR = register(new BlockItem("bamboo_door", builder()));
- public static final Item CRIMSON_DOOR = register(new BlockItem("crimson_door", builder()));
- public static final Item WARPED_DOOR = register(new BlockItem("warped_door", builder()));
- public static final Item COPPER_DOOR = register(new BlockItem("copper_door", builder()));
- public static final Item EXPOSED_COPPER_DOOR = register(new BlockItem("exposed_copper_door", builder()));
- public static final Item WEATHERED_COPPER_DOOR = register(new BlockItem("weathered_copper_door", builder()));
- public static final Item OXIDIZED_COPPER_DOOR = register(new BlockItem("oxidized_copper_door", builder()));
- public static final Item WAXED_COPPER_DOOR = register(new BlockItem("waxed_copper_door", builder()));
- public static final Item WAXED_EXPOSED_COPPER_DOOR = register(new BlockItem("waxed_exposed_copper_door", builder()));
- public static final Item WAXED_WEATHERED_COPPER_DOOR = register(new BlockItem("waxed_weathered_copper_door", builder()));
- public static final Item WAXED_OXIDIZED_COPPER_DOOR = register(new BlockItem("waxed_oxidized_copper_door", builder()));
- public static final Item IRON_TRAPDOOR = register(new BlockItem("iron_trapdoor", builder()));
- public static final Item OAK_TRAPDOOR = register(new BlockItem("oak_trapdoor", builder()));
- public static final Item SPRUCE_TRAPDOOR = register(new BlockItem("spruce_trapdoor", builder()));
- public static final Item BIRCH_TRAPDOOR = register(new BlockItem("birch_trapdoor", builder()));
- public static final Item JUNGLE_TRAPDOOR = register(new BlockItem("jungle_trapdoor", builder()));
- public static final Item ACACIA_TRAPDOOR = register(new BlockItem("acacia_trapdoor", builder()));
- public static final Item CHERRY_TRAPDOOR = register(new BlockItem("cherry_trapdoor", builder()));
- public static final Item DARK_OAK_TRAPDOOR = register(new BlockItem("dark_oak_trapdoor", builder()));
- public static final Item MANGROVE_TRAPDOOR = register(new BlockItem("mangrove_trapdoor", builder()));
- public static final Item BAMBOO_TRAPDOOR = register(new BlockItem("bamboo_trapdoor", builder()));
- public static final Item CRIMSON_TRAPDOOR = register(new BlockItem("crimson_trapdoor", builder()));
- public static final Item WARPED_TRAPDOOR = register(new BlockItem("warped_trapdoor", builder()));
- public static final Item COPPER_TRAPDOOR = register(new BlockItem("copper_trapdoor", builder()));
- public static final Item EXPOSED_COPPER_TRAPDOOR = register(new BlockItem("exposed_copper_trapdoor", builder()));
- public static final Item WEATHERED_COPPER_TRAPDOOR = register(new BlockItem("weathered_copper_trapdoor", builder()));
- public static final Item OXIDIZED_COPPER_TRAPDOOR = register(new BlockItem("oxidized_copper_trapdoor", builder()));
- public static final Item WAXED_COPPER_TRAPDOOR = register(new BlockItem("waxed_copper_trapdoor", builder()));
- public static final Item WAXED_EXPOSED_COPPER_TRAPDOOR = register(new BlockItem("waxed_exposed_copper_trapdoor", builder()));
- public static final Item WAXED_WEATHERED_COPPER_TRAPDOOR = register(new BlockItem("waxed_weathered_copper_trapdoor", builder()));
- public static final Item WAXED_OXIDIZED_COPPER_TRAPDOOR = register(new BlockItem("waxed_oxidized_copper_trapdoor", builder()));
- public static final Item OAK_FENCE_GATE = register(new BlockItem("oak_fence_gate", builder()));
- public static final Item SPRUCE_FENCE_GATE = register(new BlockItem("spruce_fence_gate", builder()));
- public static final Item BIRCH_FENCE_GATE = register(new BlockItem("birch_fence_gate", builder()));
- public static final Item JUNGLE_FENCE_GATE = register(new BlockItem("jungle_fence_gate", builder()));
- public static final Item ACACIA_FENCE_GATE = register(new BlockItem("acacia_fence_gate", builder()));
- public static final Item CHERRY_FENCE_GATE = register(new BlockItem("cherry_fence_gate", builder()));
- public static final Item DARK_OAK_FENCE_GATE = register(new BlockItem("dark_oak_fence_gate", builder()));
- public static final Item MANGROVE_FENCE_GATE = register(new BlockItem("mangrove_fence_gate", builder()));
- public static final Item BAMBOO_FENCE_GATE = register(new BlockItem("bamboo_fence_gate", builder()));
- public static final Item CRIMSON_FENCE_GATE = register(new BlockItem("crimson_fence_gate", builder()));
- public static final Item WARPED_FENCE_GATE = register(new BlockItem("warped_fence_gate", builder()));
- public static final Item POWERED_RAIL = register(new BlockItem("powered_rail", builder()));
- public static final Item DETECTOR_RAIL = register(new BlockItem("detector_rail", builder()));
- public static final Item RAIL = register(new BlockItem("rail", builder()));
- public static final Item ACTIVATOR_RAIL = register(new BlockItem("activator_rail", builder()));
+ public static final Item STONE = register(new BlockItem(builder(), Blocks.STONE));
+ public static final Item GRANITE = register(new BlockItem(builder(), Blocks.GRANITE));
+ public static final Item POLISHED_GRANITE = register(new BlockItem(builder(), Blocks.POLISHED_GRANITE));
+ public static final Item DIORITE = register(new BlockItem(builder(), Blocks.DIORITE));
+ public static final Item POLISHED_DIORITE = register(new BlockItem(builder(), Blocks.POLISHED_DIORITE));
+ public static final Item ANDESITE = register(new BlockItem(builder(), Blocks.ANDESITE));
+ public static final Item POLISHED_ANDESITE = register(new BlockItem(builder(), Blocks.POLISHED_ANDESITE));
+ public static final Item DEEPSLATE = register(new BlockItem(builder(), Blocks.DEEPSLATE));
+ public static final Item COBBLED_DEEPSLATE = register(new BlockItem(builder(), Blocks.COBBLED_DEEPSLATE));
+ public static final Item POLISHED_DEEPSLATE = register(new BlockItem(builder(), Blocks.POLISHED_DEEPSLATE));
+ public static final Item CALCITE = register(new BlockItem(builder(), Blocks.CALCITE));
+ public static final Item TUFF = register(new BlockItem(builder(), Blocks.TUFF));
+ public static final Item TUFF_SLAB = register(new BlockItem(builder(), Blocks.TUFF_SLAB));
+ public static final Item TUFF_STAIRS = register(new BlockItem(builder(), Blocks.TUFF_STAIRS));
+ public static final Item TUFF_WALL = register(new BlockItem(builder(), Blocks.TUFF_WALL));
+ public static final Item CHISELED_TUFF = register(new BlockItem(builder(), Blocks.CHISELED_TUFF));
+ public static final Item POLISHED_TUFF = register(new BlockItem(builder(), Blocks.POLISHED_TUFF));
+ public static final Item POLISHED_TUFF_SLAB = register(new BlockItem(builder(), Blocks.POLISHED_TUFF_SLAB));
+ public static final Item POLISHED_TUFF_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_TUFF_STAIRS));
+ public static final Item POLISHED_TUFF_WALL = register(new BlockItem(builder(), Blocks.POLISHED_TUFF_WALL));
+ public static final Item TUFF_BRICKS = register(new BlockItem(builder(), Blocks.TUFF_BRICKS));
+ public static final Item TUFF_BRICK_SLAB = register(new BlockItem(builder(), Blocks.TUFF_BRICK_SLAB));
+ public static final Item TUFF_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.TUFF_BRICK_STAIRS));
+ public static final Item TUFF_BRICK_WALL = register(new BlockItem(builder(), Blocks.TUFF_BRICK_WALL));
+ public static final Item CHISELED_TUFF_BRICKS = register(new BlockItem(builder(), Blocks.CHISELED_TUFF_BRICKS));
+ public static final Item DRIPSTONE_BLOCK = register(new BlockItem(builder(), Blocks.DRIPSTONE_BLOCK));
+ public static final Item GRASS_BLOCK = register(new BlockItem(builder(), Blocks.GRASS_BLOCK));
+ public static final Item DIRT = register(new BlockItem(builder(), Blocks.DIRT));
+ public static final Item COARSE_DIRT = register(new BlockItem(builder(), Blocks.COARSE_DIRT));
+ public static final Item PODZOL = register(new BlockItem(builder(), Blocks.PODZOL));
+ public static final Item ROOTED_DIRT = register(new BlockItem(builder(), Blocks.ROOTED_DIRT));
+ public static final Item MUD = register(new BlockItem(builder(), Blocks.MUD));
+ public static final Item CRIMSON_NYLIUM = register(new BlockItem(builder(), Blocks.CRIMSON_NYLIUM));
+ public static final Item WARPED_NYLIUM = register(new BlockItem(builder(), Blocks.WARPED_NYLIUM));
+ public static final Item COBBLESTONE = register(new BlockItem(builder(), Blocks.COBBLESTONE));
+ public static final Item OAK_PLANKS = register(new BlockItem(builder(), Blocks.OAK_PLANKS));
+ public static final Item SPRUCE_PLANKS = register(new BlockItem(builder(), Blocks.SPRUCE_PLANKS));
+ public static final Item BIRCH_PLANKS = register(new BlockItem(builder(), Blocks.BIRCH_PLANKS));
+ public static final Item JUNGLE_PLANKS = register(new BlockItem(builder(), Blocks.JUNGLE_PLANKS));
+ public static final Item ACACIA_PLANKS = register(new BlockItem(builder(), Blocks.ACACIA_PLANKS));
+ public static final Item CHERRY_PLANKS = register(new BlockItem(builder(), Blocks.CHERRY_PLANKS));
+ public static final Item DARK_OAK_PLANKS = register(new BlockItem(builder(), Blocks.DARK_OAK_PLANKS));
+ public static final Item MANGROVE_PLANKS = register(new BlockItem(builder(), Blocks.MANGROVE_PLANKS));
+ public static final Item BAMBOO_PLANKS = register(new BlockItem(builder(), Blocks.BAMBOO_PLANKS));
+ public static final Item CRIMSON_PLANKS = register(new BlockItem(builder(), Blocks.CRIMSON_PLANKS));
+ public static final Item WARPED_PLANKS = register(new BlockItem(builder(), Blocks.WARPED_PLANKS));
+ public static final Item BAMBOO_MOSAIC = register(new BlockItem(builder(), Blocks.BAMBOO_MOSAIC));
+ public static final Item OAK_SAPLING = register(new BlockItem(builder(), Blocks.OAK_SAPLING));
+ public static final Item SPRUCE_SAPLING = register(new BlockItem(builder(), Blocks.SPRUCE_SAPLING));
+ public static final Item BIRCH_SAPLING = register(new BlockItem(builder(), Blocks.BIRCH_SAPLING));
+ public static final Item JUNGLE_SAPLING = register(new BlockItem(builder(), Blocks.JUNGLE_SAPLING));
+ public static final Item ACACIA_SAPLING = register(new BlockItem(builder(), Blocks.ACACIA_SAPLING));
+ public static final Item CHERRY_SAPLING = register(new BlockItem(builder(), Blocks.CHERRY_SAPLING));
+ public static final Item DARK_OAK_SAPLING = register(new BlockItem(builder(), Blocks.DARK_OAK_SAPLING));
+ public static final Item MANGROVE_PROPAGULE = register(new BlockItem(builder(), Blocks.MANGROVE_PROPAGULE));
+ public static final Item BEDROCK = register(new BlockItem(builder(), Blocks.BEDROCK));
+ public static final Item SAND = register(new BlockItem(builder(), Blocks.SAND));
+ public static final Item SUSPICIOUS_SAND = register(new BlockItem(builder(), Blocks.SUSPICIOUS_SAND));
+ public static final Item SUSPICIOUS_GRAVEL = register(new BlockItem(builder(), Blocks.SUSPICIOUS_GRAVEL));
+ public static final Item RED_SAND = register(new BlockItem(builder(), Blocks.RED_SAND));
+ public static final Item GRAVEL = register(new BlockItem(builder(), Blocks.GRAVEL));
+ public static final Item COAL_ORE = register(new BlockItem(builder(), Blocks.COAL_ORE));
+ public static final Item DEEPSLATE_COAL_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_COAL_ORE));
+ public static final Item IRON_ORE = register(new BlockItem(builder(), Blocks.IRON_ORE));
+ public static final Item DEEPSLATE_IRON_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_IRON_ORE));
+ public static final Item COPPER_ORE = register(new BlockItem(builder(), Blocks.COPPER_ORE));
+ public static final Item DEEPSLATE_COPPER_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_COPPER_ORE));
+ public static final Item GOLD_ORE = register(new BlockItem(builder(), Blocks.GOLD_ORE));
+ public static final Item DEEPSLATE_GOLD_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_GOLD_ORE));
+ public static final Item REDSTONE_ORE = register(new BlockItem(builder(), Blocks.REDSTONE_ORE));
+ public static final Item DEEPSLATE_REDSTONE_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_REDSTONE_ORE));
+ public static final Item EMERALD_ORE = register(new BlockItem(builder(), Blocks.EMERALD_ORE));
+ public static final Item DEEPSLATE_EMERALD_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_EMERALD_ORE));
+ public static final Item LAPIS_ORE = register(new BlockItem(builder(), Blocks.LAPIS_ORE));
+ public static final Item DEEPSLATE_LAPIS_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_LAPIS_ORE));
+ public static final Item DIAMOND_ORE = register(new BlockItem(builder(), Blocks.DIAMOND_ORE));
+ public static final Item DEEPSLATE_DIAMOND_ORE = register(new BlockItem(builder(), Blocks.DEEPSLATE_DIAMOND_ORE));
+ public static final Item NETHER_GOLD_ORE = register(new BlockItem(builder(), Blocks.NETHER_GOLD_ORE));
+ public static final Item NETHER_QUARTZ_ORE = register(new BlockItem(builder(), Blocks.NETHER_QUARTZ_ORE));
+ public static final Item ANCIENT_DEBRIS = register(new BlockItem(builder(), Blocks.ANCIENT_DEBRIS));
+ public static final Item COAL_BLOCK = register(new BlockItem(builder(), Blocks.COAL_BLOCK));
+ public static final Item RAW_IRON_BLOCK = register(new BlockItem(builder(), Blocks.RAW_IRON_BLOCK));
+ public static final Item RAW_COPPER_BLOCK = register(new BlockItem(builder(), Blocks.RAW_COPPER_BLOCK));
+ public static final Item RAW_GOLD_BLOCK = register(new BlockItem(builder(), Blocks.RAW_GOLD_BLOCK));
+ public static final Item HEAVY_CORE = register(new BlockItem(builder(), Blocks.HEAVY_CORE));
+ public static final Item AMETHYST_BLOCK = register(new BlockItem(builder(), Blocks.AMETHYST_BLOCK));
+ public static final Item BUDDING_AMETHYST = register(new BlockItem(builder(), Blocks.BUDDING_AMETHYST));
+ public static final Item IRON_BLOCK = register(new BlockItem(builder(), Blocks.IRON_BLOCK));
+ public static final Item COPPER_BLOCK = register(new BlockItem(builder(), Blocks.COPPER_BLOCK));
+ public static final Item GOLD_BLOCK = register(new BlockItem(builder(), Blocks.GOLD_BLOCK));
+ public static final Item DIAMOND_BLOCK = register(new BlockItem(builder(), Blocks.DIAMOND_BLOCK));
+ public static final Item NETHERITE_BLOCK = register(new BlockItem(builder(), Blocks.NETHERITE_BLOCK));
+ public static final Item EXPOSED_COPPER = register(new BlockItem(builder(), Blocks.EXPOSED_COPPER));
+ public static final Item WEATHERED_COPPER = register(new BlockItem(builder(), Blocks.WEATHERED_COPPER));
+ public static final Item OXIDIZED_COPPER = register(new BlockItem(builder(), Blocks.OXIDIZED_COPPER));
+ public static final Item CHISELED_COPPER = register(new BlockItem(builder(), Blocks.CHISELED_COPPER));
+ public static final Item EXPOSED_CHISELED_COPPER = register(new BlockItem(builder(), Blocks.EXPOSED_CHISELED_COPPER));
+ public static final Item WEATHERED_CHISELED_COPPER = register(new BlockItem(builder(), Blocks.WEATHERED_CHISELED_COPPER));
+ public static final Item OXIDIZED_CHISELED_COPPER = register(new BlockItem(builder(), Blocks.OXIDIZED_CHISELED_COPPER));
+ public static final Item CUT_COPPER = register(new BlockItem(builder(), Blocks.CUT_COPPER));
+ public static final Item EXPOSED_CUT_COPPER = register(new BlockItem(builder(), Blocks.EXPOSED_CUT_COPPER));
+ public static final Item WEATHERED_CUT_COPPER = register(new BlockItem(builder(), Blocks.WEATHERED_CUT_COPPER));
+ public static final Item OXIDIZED_CUT_COPPER = register(new BlockItem(builder(), Blocks.OXIDIZED_CUT_COPPER));
+ public static final Item CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.CUT_COPPER_STAIRS));
+ public static final Item EXPOSED_CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.EXPOSED_CUT_COPPER_STAIRS));
+ public static final Item WEATHERED_CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.WEATHERED_CUT_COPPER_STAIRS));
+ public static final Item OXIDIZED_CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.OXIDIZED_CUT_COPPER_STAIRS));
+ public static final Item CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.CUT_COPPER_SLAB));
+ public static final Item EXPOSED_CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.EXPOSED_CUT_COPPER_SLAB));
+ public static final Item WEATHERED_CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.WEATHERED_CUT_COPPER_SLAB));
+ public static final Item OXIDIZED_CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.OXIDIZED_CUT_COPPER_SLAB));
+ public static final Item WAXED_COPPER_BLOCK = register(new BlockItem(builder(), Blocks.WAXED_COPPER_BLOCK));
+ public static final Item WAXED_EXPOSED_COPPER = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_COPPER));
+ public static final Item WAXED_WEATHERED_COPPER = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_COPPER));
+ public static final Item WAXED_OXIDIZED_COPPER = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_COPPER));
+ public static final Item WAXED_CHISELED_COPPER = register(new BlockItem(builder(), Blocks.WAXED_CHISELED_COPPER));
+ public static final Item WAXED_EXPOSED_CHISELED_COPPER = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_CHISELED_COPPER));
+ public static final Item WAXED_WEATHERED_CHISELED_COPPER = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_CHISELED_COPPER));
+ public static final Item WAXED_OXIDIZED_CHISELED_COPPER = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_CHISELED_COPPER));
+ public static final Item WAXED_CUT_COPPER = register(new BlockItem(builder(), Blocks.WAXED_CUT_COPPER));
+ public static final Item WAXED_EXPOSED_CUT_COPPER = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_CUT_COPPER));
+ public static final Item WAXED_WEATHERED_CUT_COPPER = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_CUT_COPPER));
+ public static final Item WAXED_OXIDIZED_CUT_COPPER = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_CUT_COPPER));
+ public static final Item WAXED_CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.WAXED_CUT_COPPER_STAIRS));
+ public static final Item WAXED_EXPOSED_CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_CUT_COPPER_STAIRS));
+ public static final Item WAXED_WEATHERED_CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_CUT_COPPER_STAIRS));
+ public static final Item WAXED_OXIDIZED_CUT_COPPER_STAIRS = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_CUT_COPPER_STAIRS));
+ public static final Item WAXED_CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.WAXED_CUT_COPPER_SLAB));
+ public static final Item WAXED_EXPOSED_CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_CUT_COPPER_SLAB));
+ public static final Item WAXED_WEATHERED_CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_CUT_COPPER_SLAB));
+ public static final Item WAXED_OXIDIZED_CUT_COPPER_SLAB = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_CUT_COPPER_SLAB));
+ public static final Item OAK_LOG = register(new BlockItem(builder(), Blocks.OAK_LOG));
+ public static final Item SPRUCE_LOG = register(new BlockItem(builder(), Blocks.SPRUCE_LOG));
+ public static final Item BIRCH_LOG = register(new BlockItem(builder(), Blocks.BIRCH_LOG));
+ public static final Item JUNGLE_LOG = register(new BlockItem(builder(), Blocks.JUNGLE_LOG));
+ public static final Item ACACIA_LOG = register(new BlockItem(builder(), Blocks.ACACIA_LOG));
+ public static final Item CHERRY_LOG = register(new BlockItem(builder(), Blocks.CHERRY_LOG));
+ public static final Item DARK_OAK_LOG = register(new BlockItem(builder(), Blocks.DARK_OAK_LOG));
+ public static final Item MANGROVE_LOG = register(new BlockItem(builder(), Blocks.MANGROVE_LOG));
+ public static final Item MANGROVE_ROOTS = register(new BlockItem(builder(), Blocks.MANGROVE_ROOTS));
+ public static final Item MUDDY_MANGROVE_ROOTS = register(new BlockItem(builder(), Blocks.MUDDY_MANGROVE_ROOTS));
+ public static final Item CRIMSON_STEM = register(new BlockItem(builder(), Blocks.CRIMSON_STEM));
+ public static final Item WARPED_STEM = register(new BlockItem(builder(), Blocks.WARPED_STEM));
+ public static final Item BAMBOO_BLOCK = register(new BlockItem(builder(), Blocks.BAMBOO_BLOCK));
+ public static final Item STRIPPED_OAK_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_OAK_LOG));
+ public static final Item STRIPPED_SPRUCE_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_SPRUCE_LOG));
+ public static final Item STRIPPED_BIRCH_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_BIRCH_LOG));
+ public static final Item STRIPPED_JUNGLE_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_JUNGLE_LOG));
+ public static final Item STRIPPED_ACACIA_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_ACACIA_LOG));
+ public static final Item STRIPPED_CHERRY_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_CHERRY_LOG));
+ public static final Item STRIPPED_DARK_OAK_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_DARK_OAK_LOG));
+ public static final Item STRIPPED_MANGROVE_LOG = register(new BlockItem(builder(), Blocks.STRIPPED_MANGROVE_LOG));
+ public static final Item STRIPPED_CRIMSON_STEM = register(new BlockItem(builder(), Blocks.STRIPPED_CRIMSON_STEM));
+ public static final Item STRIPPED_WARPED_STEM = register(new BlockItem(builder(), Blocks.STRIPPED_WARPED_STEM));
+ public static final Item STRIPPED_OAK_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_OAK_WOOD));
+ public static final Item STRIPPED_SPRUCE_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_SPRUCE_WOOD));
+ public static final Item STRIPPED_BIRCH_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_BIRCH_WOOD));
+ public static final Item STRIPPED_JUNGLE_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_JUNGLE_WOOD));
+ public static final Item STRIPPED_ACACIA_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_ACACIA_WOOD));
+ public static final Item STRIPPED_CHERRY_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_CHERRY_WOOD));
+ public static final Item STRIPPED_DARK_OAK_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_DARK_OAK_WOOD));
+ public static final Item STRIPPED_MANGROVE_WOOD = register(new BlockItem(builder(), Blocks.STRIPPED_MANGROVE_WOOD));
+ public static final Item STRIPPED_CRIMSON_HYPHAE = register(new BlockItem(builder(), Blocks.STRIPPED_CRIMSON_HYPHAE));
+ public static final Item STRIPPED_WARPED_HYPHAE = register(new BlockItem(builder(), Blocks.STRIPPED_WARPED_HYPHAE));
+ public static final Item STRIPPED_BAMBOO_BLOCK = register(new BlockItem(builder(), Blocks.STRIPPED_BAMBOO_BLOCK));
+ public static final Item OAK_WOOD = register(new BlockItem(builder(), Blocks.OAK_WOOD));
+ public static final Item SPRUCE_WOOD = register(new BlockItem(builder(), Blocks.SPRUCE_WOOD));
+ public static final Item BIRCH_WOOD = register(new BlockItem(builder(), Blocks.BIRCH_WOOD));
+ public static final Item JUNGLE_WOOD = register(new BlockItem(builder(), Blocks.JUNGLE_WOOD));
+ public static final Item ACACIA_WOOD = register(new BlockItem(builder(), Blocks.ACACIA_WOOD));
+ public static final Item CHERRY_WOOD = register(new BlockItem(builder(), Blocks.CHERRY_WOOD));
+ public static final Item DARK_OAK_WOOD = register(new BlockItem(builder(), Blocks.DARK_OAK_WOOD));
+ public static final Item MANGROVE_WOOD = register(new BlockItem(builder(), Blocks.MANGROVE_WOOD));
+ public static final Item CRIMSON_HYPHAE = register(new BlockItem(builder(), Blocks.CRIMSON_HYPHAE));
+ public static final Item WARPED_HYPHAE = register(new BlockItem(builder(), Blocks.WARPED_HYPHAE));
+ public static final Item OAK_LEAVES = register(new BlockItem(builder(), Blocks.OAK_LEAVES));
+ public static final Item SPRUCE_LEAVES = register(new BlockItem(builder(), Blocks.SPRUCE_LEAVES));
+ public static final Item BIRCH_LEAVES = register(new BlockItem(builder(), Blocks.BIRCH_LEAVES));
+ public static final Item JUNGLE_LEAVES = register(new BlockItem(builder(), Blocks.JUNGLE_LEAVES));
+ public static final Item ACACIA_LEAVES = register(new BlockItem(builder(), Blocks.ACACIA_LEAVES));
+ public static final Item CHERRY_LEAVES = register(new BlockItem(builder(), Blocks.CHERRY_LEAVES));
+ public static final Item DARK_OAK_LEAVES = register(new BlockItem(builder(), Blocks.DARK_OAK_LEAVES));
+ public static final Item MANGROVE_LEAVES = register(new BlockItem(builder(), Blocks.MANGROVE_LEAVES));
+ public static final Item AZALEA_LEAVES = register(new BlockItem(builder(), Blocks.AZALEA_LEAVES));
+ public static final Item FLOWERING_AZALEA_LEAVES = register(new BlockItem(builder(), Blocks.FLOWERING_AZALEA_LEAVES));
+ public static final Item SPONGE = register(new BlockItem(builder(), Blocks.SPONGE));
+ public static final Item WET_SPONGE = register(new BlockItem(builder(), Blocks.WET_SPONGE));
+ public static final Item GLASS = register(new BlockItem(builder(), Blocks.GLASS));
+ public static final Item TINTED_GLASS = register(new BlockItem(builder(), Blocks.TINTED_GLASS));
+ public static final Item LAPIS_BLOCK = register(new BlockItem(builder(), Blocks.LAPIS_BLOCK));
+ public static final Item SANDSTONE = register(new BlockItem(builder(), Blocks.SANDSTONE));
+ public static final Item CHISELED_SANDSTONE = register(new BlockItem(builder(), Blocks.CHISELED_SANDSTONE));
+ public static final Item CUT_SANDSTONE = register(new BlockItem(builder(), Blocks.CUT_SANDSTONE));
+ public static final Item COBWEB = register(new BlockItem(builder(), Blocks.COBWEB));
+ public static final Item SHORT_GRASS = register(new BlockItem(builder(), Blocks.SHORT_GRASS));
+ public static final Item FERN = register(new BlockItem(builder(), Blocks.FERN));
+ public static final Item AZALEA = register(new BlockItem(builder(), Blocks.AZALEA));
+ public static final Item FLOWERING_AZALEA = register(new BlockItem(builder(), Blocks.FLOWERING_AZALEA));
+ public static final Item DEAD_BUSH = register(new BlockItem(builder(), Blocks.DEAD_BUSH));
+ public static final Item SEAGRASS = register(new BlockItem(builder(), Blocks.SEAGRASS));
+ public static final Item SEA_PICKLE = register(new BlockItem(builder(), Blocks.SEA_PICKLE));
+ public static final Item WHITE_WOOL = register(new BlockItem(builder(), Blocks.WHITE_WOOL));
+ public static final Item ORANGE_WOOL = register(new BlockItem(builder(), Blocks.ORANGE_WOOL));
+ public static final Item MAGENTA_WOOL = register(new BlockItem(builder(), Blocks.MAGENTA_WOOL));
+ public static final Item LIGHT_BLUE_WOOL = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_WOOL));
+ public static final Item YELLOW_WOOL = register(new BlockItem(builder(), Blocks.YELLOW_WOOL));
+ public static final Item LIME_WOOL = register(new BlockItem(builder(), Blocks.LIME_WOOL));
+ public static final Item PINK_WOOL = register(new BlockItem(builder(), Blocks.PINK_WOOL));
+ public static final Item GRAY_WOOL = register(new BlockItem(builder(), Blocks.GRAY_WOOL));
+ public static final Item LIGHT_GRAY_WOOL = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_WOOL));
+ public static final Item CYAN_WOOL = register(new BlockItem(builder(), Blocks.CYAN_WOOL));
+ public static final Item PURPLE_WOOL = register(new BlockItem(builder(), Blocks.PURPLE_WOOL));
+ public static final Item BLUE_WOOL = register(new BlockItem(builder(), Blocks.BLUE_WOOL));
+ public static final Item BROWN_WOOL = register(new BlockItem(builder(), Blocks.BROWN_WOOL));
+ public static final Item GREEN_WOOL = register(new BlockItem(builder(), Blocks.GREEN_WOOL));
+ public static final Item RED_WOOL = register(new BlockItem(builder(), Blocks.RED_WOOL));
+ public static final Item BLACK_WOOL = register(new BlockItem(builder(), Blocks.BLACK_WOOL));
+ public static final Item DANDELION = register(new BlockItem(builder(), Blocks.DANDELION));
+ public static final Item POPPY = register(new BlockItem(builder(), Blocks.POPPY));
+ public static final Item BLUE_ORCHID = register(new BlockItem(builder(), Blocks.BLUE_ORCHID));
+ public static final Item ALLIUM = register(new BlockItem(builder(), Blocks.ALLIUM));
+ public static final Item AZURE_BLUET = register(new BlockItem(builder(), Blocks.AZURE_BLUET));
+ public static final Item RED_TULIP = register(new BlockItem(builder(), Blocks.RED_TULIP));
+ public static final Item ORANGE_TULIP = register(new BlockItem(builder(), Blocks.ORANGE_TULIP));
+ public static final Item WHITE_TULIP = register(new BlockItem(builder(), Blocks.WHITE_TULIP));
+ public static final Item PINK_TULIP = register(new BlockItem(builder(), Blocks.PINK_TULIP));
+ public static final Item OXEYE_DAISY = register(new BlockItem(builder(), Blocks.OXEYE_DAISY));
+ public static final Item CORNFLOWER = register(new BlockItem(builder(), Blocks.CORNFLOWER));
+ public static final Item LILY_OF_THE_VALLEY = register(new BlockItem(builder(), Blocks.LILY_OF_THE_VALLEY));
+ public static final Item WITHER_ROSE = register(new BlockItem(builder(), Blocks.WITHER_ROSE));
+ public static final Item TORCHFLOWER = register(new BlockItem(builder(), Blocks.TORCHFLOWER));
+ public static final Item PITCHER_PLANT = register(new BlockItem(builder(), Blocks.PITCHER_PLANT));
+ public static final Item SPORE_BLOSSOM = register(new BlockItem(builder(), Blocks.SPORE_BLOSSOM));
+ public static final Item BROWN_MUSHROOM = register(new BlockItem(builder(), Blocks.BROWN_MUSHROOM));
+ public static final Item RED_MUSHROOM = register(new BlockItem(builder(), Blocks.RED_MUSHROOM));
+ public static final Item CRIMSON_FUNGUS = register(new BlockItem(builder(), Blocks.CRIMSON_FUNGUS));
+ public static final Item WARPED_FUNGUS = register(new BlockItem(builder(), Blocks.WARPED_FUNGUS));
+ public static final Item CRIMSON_ROOTS = register(new BlockItem(builder(), Blocks.CRIMSON_ROOTS));
+ public static final Item WARPED_ROOTS = register(new BlockItem(builder(), Blocks.WARPED_ROOTS));
+ public static final Item NETHER_SPROUTS = register(new BlockItem(builder(), Blocks.NETHER_SPROUTS));
+ public static final Item WEEPING_VINES = register(new BlockItem(builder(), Blocks.WEEPING_VINES));
+ public static final Item TWISTING_VINES = register(new BlockItem(builder(), Blocks.TWISTING_VINES));
+ public static final Item SUGAR_CANE = register(new BlockItem(builder(), Blocks.SUGAR_CANE));
+ public static final Item KELP = register(new BlockItem(builder(), Blocks.KELP));
+ public static final Item MOSS_CARPET = register(new BlockItem(builder(), Blocks.MOSS_CARPET));
+ public static final Item PINK_PETALS = register(new BlockItem(builder(), Blocks.PINK_PETALS));
+ public static final Item MOSS_BLOCK = register(new BlockItem(builder(), Blocks.MOSS_BLOCK));
+ public static final Item HANGING_ROOTS = register(new BlockItem(builder(), Blocks.HANGING_ROOTS));
+ public static final Item BIG_DRIPLEAF = register(new BlockItem(builder(), Blocks.BIG_DRIPLEAF, Blocks.BIG_DRIPLEAF_STEM));
+ public static final Item SMALL_DRIPLEAF = register(new BlockItem(builder(), Blocks.SMALL_DRIPLEAF));
+ public static final Item BAMBOO = register(new BlockItem(builder(), Blocks.BAMBOO));
+ public static final Item OAK_SLAB = register(new BlockItem(builder(), Blocks.OAK_SLAB));
+ public static final Item SPRUCE_SLAB = register(new BlockItem(builder(), Blocks.SPRUCE_SLAB));
+ public static final Item BIRCH_SLAB = register(new BlockItem(builder(), Blocks.BIRCH_SLAB));
+ public static final Item JUNGLE_SLAB = register(new BlockItem(builder(), Blocks.JUNGLE_SLAB));
+ public static final Item ACACIA_SLAB = register(new BlockItem(builder(), Blocks.ACACIA_SLAB));
+ public static final Item CHERRY_SLAB = register(new BlockItem(builder(), Blocks.CHERRY_SLAB));
+ public static final Item DARK_OAK_SLAB = register(new BlockItem(builder(), Blocks.DARK_OAK_SLAB));
+ public static final Item MANGROVE_SLAB = register(new BlockItem(builder(), Blocks.MANGROVE_SLAB));
+ public static final Item BAMBOO_SLAB = register(new BlockItem(builder(), Blocks.BAMBOO_SLAB));
+ public static final Item BAMBOO_MOSAIC_SLAB = register(new BlockItem(builder(), Blocks.BAMBOO_MOSAIC_SLAB));
+ public static final Item CRIMSON_SLAB = register(new BlockItem(builder(), Blocks.CRIMSON_SLAB));
+ public static final Item WARPED_SLAB = register(new BlockItem(builder(), Blocks.WARPED_SLAB));
+ public static final Item STONE_SLAB = register(new BlockItem(builder(), Blocks.STONE_SLAB));
+ public static final Item SMOOTH_STONE_SLAB = register(new BlockItem(builder(), Blocks.SMOOTH_STONE_SLAB));
+ public static final Item SANDSTONE_SLAB = register(new BlockItem(builder(), Blocks.SANDSTONE_SLAB));
+ public static final Item CUT_SANDSTONE_SLAB = register(new BlockItem(builder(), Blocks.CUT_SANDSTONE_SLAB));
+ public static final Item PETRIFIED_OAK_SLAB = register(new BlockItem(builder(), Blocks.PETRIFIED_OAK_SLAB));
+ public static final Item COBBLESTONE_SLAB = register(new BlockItem(builder(), Blocks.COBBLESTONE_SLAB));
+ public static final Item BRICK_SLAB = register(new BlockItem(builder(), Blocks.BRICK_SLAB));
+ public static final Item STONE_BRICK_SLAB = register(new BlockItem(builder(), Blocks.STONE_BRICK_SLAB));
+ public static final Item MUD_BRICK_SLAB = register(new BlockItem(builder(), Blocks.MUD_BRICK_SLAB));
+ public static final Item NETHER_BRICK_SLAB = register(new BlockItem(builder(), Blocks.NETHER_BRICK_SLAB));
+ public static final Item QUARTZ_SLAB = register(new BlockItem(builder(), Blocks.QUARTZ_SLAB));
+ public static final Item RED_SANDSTONE_SLAB = register(new BlockItem(builder(), Blocks.RED_SANDSTONE_SLAB));
+ public static final Item CUT_RED_SANDSTONE_SLAB = register(new BlockItem(builder(), Blocks.CUT_RED_SANDSTONE_SLAB));
+ public static final Item PURPUR_SLAB = register(new BlockItem(builder(), Blocks.PURPUR_SLAB));
+ public static final Item PRISMARINE_SLAB = register(new BlockItem(builder(), Blocks.PRISMARINE_SLAB));
+ public static final Item PRISMARINE_BRICK_SLAB = register(new BlockItem(builder(), Blocks.PRISMARINE_BRICK_SLAB));
+ public static final Item DARK_PRISMARINE_SLAB = register(new BlockItem(builder(), Blocks.DARK_PRISMARINE_SLAB));
+ public static final Item SMOOTH_QUARTZ = register(new BlockItem(builder(), Blocks.SMOOTH_QUARTZ));
+ public static final Item SMOOTH_RED_SANDSTONE = register(new BlockItem(builder(), Blocks.SMOOTH_RED_SANDSTONE));
+ public static final Item SMOOTH_SANDSTONE = register(new BlockItem(builder(), Blocks.SMOOTH_SANDSTONE));
+ public static final Item SMOOTH_STONE = register(new BlockItem(builder(), Blocks.SMOOTH_STONE));
+ public static final Item BRICKS = register(new BlockItem(builder(), Blocks.BRICKS));
+ public static final Item BOOKSHELF = register(new BlockItem(builder(), Blocks.BOOKSHELF));
+ public static final Item CHISELED_BOOKSHELF = register(new BlockItem(builder(), Blocks.CHISELED_BOOKSHELF));
+ public static final Item DECORATED_POT = register(new DecoratedPotItem(builder(), Blocks.DECORATED_POT));
+ public static final Item MOSSY_COBBLESTONE = register(new BlockItem(builder(), Blocks.MOSSY_COBBLESTONE));
+ public static final Item OBSIDIAN = register(new BlockItem(builder(), Blocks.OBSIDIAN));
+ public static final Item TORCH = register(new BlockItem(builder(), Blocks.TORCH, Blocks.WALL_TORCH));
+ public static final Item END_ROD = register(new BlockItem(builder(), Blocks.END_ROD));
+ public static final Item CHORUS_PLANT = register(new BlockItem(builder(), Blocks.CHORUS_PLANT));
+ public static final Item CHORUS_FLOWER = register(new BlockItem(builder(), Blocks.CHORUS_FLOWER));
+ public static final Item PURPUR_BLOCK = register(new BlockItem(builder(), Blocks.PURPUR_BLOCK));
+ public static final Item PURPUR_PILLAR = register(new BlockItem(builder(), Blocks.PURPUR_PILLAR));
+ public static final Item PURPUR_STAIRS = register(new BlockItem(builder(), Blocks.PURPUR_STAIRS));
+ public static final Item SPAWNER = register(new BlockItem(builder(), Blocks.SPAWNER));
+ public static final Item CHEST = register(new BlockItem(builder(), Blocks.CHEST));
+ public static final Item CRAFTING_TABLE = register(new BlockItem(builder(), Blocks.CRAFTING_TABLE));
+ public static final Item FARMLAND = register(new BlockItem(builder(), Blocks.FARMLAND));
+ public static final Item FURNACE = register(new BlockItem(builder(), Blocks.FURNACE));
+ public static final Item LADDER = register(new BlockItem(builder(), Blocks.LADDER));
+ public static final Item COBBLESTONE_STAIRS = register(new BlockItem(builder(), Blocks.COBBLESTONE_STAIRS));
+ public static final Item SNOW = register(new BlockItem(builder(), Blocks.SNOW));
+ public static final Item ICE = register(new BlockItem(builder(), Blocks.ICE));
+ public static final Item SNOW_BLOCK = register(new BlockItem(builder(), Blocks.SNOW_BLOCK));
+ public static final Item CACTUS = register(new BlockItem(builder(), Blocks.CACTUS));
+ public static final Item CLAY = register(new BlockItem(builder(), Blocks.CLAY));
+ public static final Item JUKEBOX = register(new BlockItem(builder(), Blocks.JUKEBOX));
+ public static final Item OAK_FENCE = register(new BlockItem(builder(), Blocks.OAK_FENCE));
+ public static final Item SPRUCE_FENCE = register(new BlockItem(builder(), Blocks.SPRUCE_FENCE));
+ public static final Item BIRCH_FENCE = register(new BlockItem(builder(), Blocks.BIRCH_FENCE));
+ public static final Item JUNGLE_FENCE = register(new BlockItem(builder(), Blocks.JUNGLE_FENCE));
+ public static final Item ACACIA_FENCE = register(new BlockItem(builder(), Blocks.ACACIA_FENCE));
+ public static final Item CHERRY_FENCE = register(new BlockItem(builder(), Blocks.CHERRY_FENCE));
+ public static final Item DARK_OAK_FENCE = register(new BlockItem(builder(), Blocks.DARK_OAK_FENCE));
+ public static final Item MANGROVE_FENCE = register(new BlockItem(builder(), Blocks.MANGROVE_FENCE));
+ public static final Item BAMBOO_FENCE = register(new BlockItem(builder(), Blocks.BAMBOO_FENCE));
+ public static final Item CRIMSON_FENCE = register(new BlockItem(builder(), Blocks.CRIMSON_FENCE));
+ public static final Item WARPED_FENCE = register(new BlockItem(builder(), Blocks.WARPED_FENCE));
+ public static final Item PUMPKIN = register(new BlockItem(builder(), Blocks.PUMPKIN));
+ public static final Item CARVED_PUMPKIN = register(new BlockItem(builder(), Blocks.CARVED_PUMPKIN));
+ public static final Item JACK_O_LANTERN = register(new BlockItem(builder(), Blocks.JACK_O_LANTERN));
+ public static final Item NETHERRACK = register(new BlockItem(builder(), Blocks.NETHERRACK));
+ public static final Item SOUL_SAND = register(new BlockItem(builder(), Blocks.SOUL_SAND));
+ public static final Item SOUL_SOIL = register(new BlockItem(builder(), Blocks.SOUL_SOIL));
+ public static final Item BASALT = register(new BlockItem(builder(), Blocks.BASALT));
+ public static final Item POLISHED_BASALT = register(new BlockItem(builder(), Blocks.POLISHED_BASALT));
+ public static final Item SMOOTH_BASALT = register(new BlockItem(builder(), Blocks.SMOOTH_BASALT));
+ public static final Item SOUL_TORCH = register(new BlockItem(builder(), Blocks.SOUL_TORCH, Blocks.SOUL_WALL_TORCH));
+ public static final Item GLOWSTONE = register(new BlockItem(builder(), Blocks.GLOWSTONE));
+ public static final Item INFESTED_STONE = register(new BlockItem(builder(), Blocks.INFESTED_STONE));
+ public static final Item INFESTED_COBBLESTONE = register(new BlockItem(builder(), Blocks.INFESTED_COBBLESTONE));
+ public static final Item INFESTED_STONE_BRICKS = register(new BlockItem(builder(), Blocks.INFESTED_STONE_BRICKS));
+ public static final Item INFESTED_MOSSY_STONE_BRICKS = register(new BlockItem(builder(), Blocks.INFESTED_MOSSY_STONE_BRICKS));
+ public static final Item INFESTED_CRACKED_STONE_BRICKS = register(new BlockItem(builder(), Blocks.INFESTED_CRACKED_STONE_BRICKS));
+ public static final Item INFESTED_CHISELED_STONE_BRICKS = register(new BlockItem(builder(), Blocks.INFESTED_CHISELED_STONE_BRICKS));
+ public static final Item INFESTED_DEEPSLATE = register(new BlockItem(builder(), Blocks.INFESTED_DEEPSLATE));
+ public static final Item STONE_BRICKS = register(new BlockItem(builder(), Blocks.STONE_BRICKS));
+ public static final Item MOSSY_STONE_BRICKS = register(new BlockItem(builder(), Blocks.MOSSY_STONE_BRICKS));
+ public static final Item CRACKED_STONE_BRICKS = register(new BlockItem(builder(), Blocks.CRACKED_STONE_BRICKS));
+ public static final Item CHISELED_STONE_BRICKS = register(new BlockItem(builder(), Blocks.CHISELED_STONE_BRICKS));
+ public static final Item PACKED_MUD = register(new BlockItem(builder(), Blocks.PACKED_MUD));
+ public static final Item MUD_BRICKS = register(new BlockItem(builder(), Blocks.MUD_BRICKS));
+ public static final Item DEEPSLATE_BRICKS = register(new BlockItem(builder(), Blocks.DEEPSLATE_BRICKS));
+ public static final Item CRACKED_DEEPSLATE_BRICKS = register(new BlockItem(builder(), Blocks.CRACKED_DEEPSLATE_BRICKS));
+ public static final Item DEEPSLATE_TILES = register(new BlockItem(builder(), Blocks.DEEPSLATE_TILES));
+ public static final Item CRACKED_DEEPSLATE_TILES = register(new BlockItem(builder(), Blocks.CRACKED_DEEPSLATE_TILES));
+ public static final Item CHISELED_DEEPSLATE = register(new BlockItem(builder(), Blocks.CHISELED_DEEPSLATE));
+ public static final Item REINFORCED_DEEPSLATE = register(new BlockItem(builder(), Blocks.REINFORCED_DEEPSLATE));
+ public static final Item BROWN_MUSHROOM_BLOCK = register(new BlockItem(builder(), Blocks.BROWN_MUSHROOM_BLOCK));
+ public static final Item RED_MUSHROOM_BLOCK = register(new BlockItem(builder(), Blocks.RED_MUSHROOM_BLOCK));
+ public static final Item MUSHROOM_STEM = register(new BlockItem(builder(), Blocks.MUSHROOM_STEM));
+ public static final Item IRON_BARS = register(new BlockItem(builder(), Blocks.IRON_BARS));
+ public static final Item CHAIN = register(new BlockItem(builder(), Blocks.CHAIN));
+ public static final Item GLASS_PANE = register(new BlockItem(builder(), Blocks.GLASS_PANE));
+ public static final Item MELON = register(new BlockItem(builder(), Blocks.MELON));
+ public static final Item VINE = register(new BlockItem(builder(), Blocks.VINE));
+ public static final Item GLOW_LICHEN = register(new BlockItem(builder(), Blocks.GLOW_LICHEN));
+ public static final Item BRICK_STAIRS = register(new BlockItem(builder(), Blocks.BRICK_STAIRS));
+ public static final Item STONE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.STONE_BRICK_STAIRS));
+ public static final Item MUD_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.MUD_BRICK_STAIRS));
+ public static final Item MYCELIUM = register(new BlockItem(builder(), Blocks.MYCELIUM));
+ public static final Item LILY_PAD = register(new BlockItem(builder(), Blocks.LILY_PAD));
+ public static final Item NETHER_BRICKS = register(new BlockItem(builder(), Blocks.NETHER_BRICKS));
+ public static final Item CRACKED_NETHER_BRICKS = register(new BlockItem(builder(), Blocks.CRACKED_NETHER_BRICKS));
+ public static final Item CHISELED_NETHER_BRICKS = register(new BlockItem(builder(), Blocks.CHISELED_NETHER_BRICKS));
+ public static final Item NETHER_BRICK_FENCE = register(new BlockItem(builder(), Blocks.NETHER_BRICK_FENCE));
+ public static final Item NETHER_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.NETHER_BRICK_STAIRS));
+ public static final Item SCULK = register(new BlockItem(builder(), Blocks.SCULK));
+ public static final Item SCULK_VEIN = register(new BlockItem(builder(), Blocks.SCULK_VEIN));
+ public static final Item SCULK_CATALYST = register(new BlockItem(builder(), Blocks.SCULK_CATALYST));
+ public static final Item SCULK_SHRIEKER = register(new BlockItem(builder(), Blocks.SCULK_SHRIEKER));
+ public static final Item ENCHANTING_TABLE = register(new BlockItem(builder(), Blocks.ENCHANTING_TABLE));
+ public static final Item END_PORTAL_FRAME = register(new BlockItem(builder(), Blocks.END_PORTAL_FRAME));
+ public static final Item END_STONE = register(new BlockItem(builder(), Blocks.END_STONE));
+ public static final Item END_STONE_BRICKS = register(new BlockItem(builder(), Blocks.END_STONE_BRICKS));
+ public static final Item DRAGON_EGG = register(new BlockItem(builder(), Blocks.DRAGON_EGG));
+ public static final Item SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.SANDSTONE_STAIRS));
+ public static final Item ENDER_CHEST = register(new BlockItem(builder(), Blocks.ENDER_CHEST));
+ public static final Item EMERALD_BLOCK = register(new BlockItem(builder(), Blocks.EMERALD_BLOCK));
+ public static final Item OAK_STAIRS = register(new BlockItem(builder(), Blocks.OAK_STAIRS));
+ public static final Item SPRUCE_STAIRS = register(new BlockItem(builder(), Blocks.SPRUCE_STAIRS));
+ public static final Item BIRCH_STAIRS = register(new BlockItem(builder(), Blocks.BIRCH_STAIRS));
+ public static final Item JUNGLE_STAIRS = register(new BlockItem(builder(), Blocks.JUNGLE_STAIRS));
+ public static final Item ACACIA_STAIRS = register(new BlockItem(builder(), Blocks.ACACIA_STAIRS));
+ public static final Item CHERRY_STAIRS = register(new BlockItem(builder(), Blocks.CHERRY_STAIRS));
+ public static final Item DARK_OAK_STAIRS = register(new BlockItem(builder(), Blocks.DARK_OAK_STAIRS));
+ public static final Item MANGROVE_STAIRS = register(new BlockItem(builder(), Blocks.MANGROVE_STAIRS));
+ public static final Item BAMBOO_STAIRS = register(new BlockItem(builder(), Blocks.BAMBOO_STAIRS));
+ public static final Item BAMBOO_MOSAIC_STAIRS = register(new BlockItem(builder(), Blocks.BAMBOO_MOSAIC_STAIRS));
+ public static final Item CRIMSON_STAIRS = register(new BlockItem(builder(), Blocks.CRIMSON_STAIRS));
+ public static final Item WARPED_STAIRS = register(new BlockItem(builder(), Blocks.WARPED_STAIRS));
+ public static final Item COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.COMMAND_BLOCK));
+ public static final Item BEACON = register(new BlockItem(builder(), Blocks.BEACON));
+ public static final Item COBBLESTONE_WALL = register(new BlockItem(builder(), Blocks.COBBLESTONE_WALL));
+ public static final Item MOSSY_COBBLESTONE_WALL = register(new BlockItem(builder(), Blocks.MOSSY_COBBLESTONE_WALL));
+ public static final Item BRICK_WALL = register(new BlockItem(builder(), Blocks.BRICK_WALL));
+ public static final Item PRISMARINE_WALL = register(new BlockItem(builder(), Blocks.PRISMARINE_WALL));
+ public static final Item RED_SANDSTONE_WALL = register(new BlockItem(builder(), Blocks.RED_SANDSTONE_WALL));
+ public static final Item MOSSY_STONE_BRICK_WALL = register(new BlockItem(builder(), Blocks.MOSSY_STONE_BRICK_WALL));
+ public static final Item GRANITE_WALL = register(new BlockItem(builder(), Blocks.GRANITE_WALL));
+ public static final Item STONE_BRICK_WALL = register(new BlockItem(builder(), Blocks.STONE_BRICK_WALL));
+ public static final Item MUD_BRICK_WALL = register(new BlockItem(builder(), Blocks.MUD_BRICK_WALL));
+ public static final Item NETHER_BRICK_WALL = register(new BlockItem(builder(), Blocks.NETHER_BRICK_WALL));
+ public static final Item ANDESITE_WALL = register(new BlockItem(builder(), Blocks.ANDESITE_WALL));
+ public static final Item RED_NETHER_BRICK_WALL = register(new BlockItem(builder(), Blocks.RED_NETHER_BRICK_WALL));
+ public static final Item SANDSTONE_WALL = register(new BlockItem(builder(), Blocks.SANDSTONE_WALL));
+ public static final Item END_STONE_BRICK_WALL = register(new BlockItem(builder(), Blocks.END_STONE_BRICK_WALL));
+ public static final Item DIORITE_WALL = register(new BlockItem(builder(), Blocks.DIORITE_WALL));
+ public static final Item BLACKSTONE_WALL = register(new BlockItem(builder(), Blocks.BLACKSTONE_WALL));
+ public static final Item POLISHED_BLACKSTONE_WALL = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_WALL));
+ public static final Item POLISHED_BLACKSTONE_BRICK_WALL = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_BRICK_WALL));
+ public static final Item COBBLED_DEEPSLATE_WALL = register(new BlockItem(builder(), Blocks.COBBLED_DEEPSLATE_WALL));
+ public static final Item POLISHED_DEEPSLATE_WALL = register(new BlockItem(builder(), Blocks.POLISHED_DEEPSLATE_WALL));
+ public static final Item DEEPSLATE_BRICK_WALL = register(new BlockItem(builder(), Blocks.DEEPSLATE_BRICK_WALL));
+ public static final Item DEEPSLATE_TILE_WALL = register(new BlockItem(builder(), Blocks.DEEPSLATE_TILE_WALL));
+ public static final Item ANVIL = register(new BlockItem(builder(), Blocks.ANVIL));
+ public static final Item CHIPPED_ANVIL = register(new BlockItem(builder(), Blocks.CHIPPED_ANVIL));
+ public static final Item DAMAGED_ANVIL = register(new BlockItem(builder(), Blocks.DAMAGED_ANVIL));
+ public static final Item CHISELED_QUARTZ_BLOCK = register(new BlockItem(builder(), Blocks.CHISELED_QUARTZ_BLOCK));
+ public static final Item QUARTZ_BLOCK = register(new BlockItem(builder(), Blocks.QUARTZ_BLOCK));
+ public static final Item QUARTZ_BRICKS = register(new BlockItem(builder(), Blocks.QUARTZ_BRICKS));
+ public static final Item QUARTZ_PILLAR = register(new BlockItem(builder(), Blocks.QUARTZ_PILLAR));
+ public static final Item QUARTZ_STAIRS = register(new BlockItem(builder(), Blocks.QUARTZ_STAIRS));
+ public static final Item WHITE_TERRACOTTA = register(new BlockItem(builder(), Blocks.WHITE_TERRACOTTA));
+ public static final Item ORANGE_TERRACOTTA = register(new BlockItem(builder(), Blocks.ORANGE_TERRACOTTA));
+ public static final Item MAGENTA_TERRACOTTA = register(new BlockItem(builder(), Blocks.MAGENTA_TERRACOTTA));
+ public static final Item LIGHT_BLUE_TERRACOTTA = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_TERRACOTTA));
+ public static final Item YELLOW_TERRACOTTA = register(new BlockItem(builder(), Blocks.YELLOW_TERRACOTTA));
+ public static final Item LIME_TERRACOTTA = register(new BlockItem(builder(), Blocks.LIME_TERRACOTTA));
+ public static final Item PINK_TERRACOTTA = register(new BlockItem(builder(), Blocks.PINK_TERRACOTTA));
+ public static final Item GRAY_TERRACOTTA = register(new BlockItem(builder(), Blocks.GRAY_TERRACOTTA));
+ public static final Item LIGHT_GRAY_TERRACOTTA = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_TERRACOTTA));
+ public static final Item CYAN_TERRACOTTA = register(new BlockItem(builder(), Blocks.CYAN_TERRACOTTA));
+ public static final Item PURPLE_TERRACOTTA = register(new BlockItem(builder(), Blocks.PURPLE_TERRACOTTA));
+ public static final Item BLUE_TERRACOTTA = register(new BlockItem(builder(), Blocks.BLUE_TERRACOTTA));
+ public static final Item BROWN_TERRACOTTA = register(new BlockItem(builder(), Blocks.BROWN_TERRACOTTA));
+ public static final Item GREEN_TERRACOTTA = register(new BlockItem(builder(), Blocks.GREEN_TERRACOTTA));
+ public static final Item RED_TERRACOTTA = register(new BlockItem(builder(), Blocks.RED_TERRACOTTA));
+ public static final Item BLACK_TERRACOTTA = register(new BlockItem(builder(), Blocks.BLACK_TERRACOTTA));
+ public static final Item BARRIER = register(new BlockItem(builder(), Blocks.BARRIER));
+ public static final Item LIGHT = register(new BlockItem(builder(), Blocks.LIGHT));
+ public static final Item HAY_BLOCK = register(new BlockItem(builder(), Blocks.HAY_BLOCK));
+ public static final Item WHITE_CARPET = register(new BlockItem(builder(), Blocks.WHITE_CARPET));
+ public static final Item ORANGE_CARPET = register(new BlockItem(builder(), Blocks.ORANGE_CARPET));
+ public static final Item MAGENTA_CARPET = register(new BlockItem(builder(), Blocks.MAGENTA_CARPET));
+ public static final Item LIGHT_BLUE_CARPET = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_CARPET));
+ public static final Item YELLOW_CARPET = register(new BlockItem(builder(), Blocks.YELLOW_CARPET));
+ public static final Item LIME_CARPET = register(new BlockItem(builder(), Blocks.LIME_CARPET));
+ public static final Item PINK_CARPET = register(new BlockItem(builder(), Blocks.PINK_CARPET));
+ public static final Item GRAY_CARPET = register(new BlockItem(builder(), Blocks.GRAY_CARPET));
+ public static final Item LIGHT_GRAY_CARPET = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_CARPET));
+ public static final Item CYAN_CARPET = register(new BlockItem(builder(), Blocks.CYAN_CARPET));
+ public static final Item PURPLE_CARPET = register(new BlockItem(builder(), Blocks.PURPLE_CARPET));
+ public static final Item BLUE_CARPET = register(new BlockItem(builder(), Blocks.BLUE_CARPET));
+ public static final Item BROWN_CARPET = register(new BlockItem(builder(), Blocks.BROWN_CARPET));
+ public static final Item GREEN_CARPET = register(new BlockItem(builder(), Blocks.GREEN_CARPET));
+ public static final Item RED_CARPET = register(new BlockItem(builder(), Blocks.RED_CARPET));
+ public static final Item BLACK_CARPET = register(new BlockItem(builder(), Blocks.BLACK_CARPET));
+ public static final Item TERRACOTTA = register(new BlockItem(builder(), Blocks.TERRACOTTA));
+ public static final Item PACKED_ICE = register(new BlockItem(builder(), Blocks.PACKED_ICE));
+ public static final Item DIRT_PATH = register(new BlockItem(builder(), Blocks.DIRT_PATH));
+ public static final Item SUNFLOWER = register(new BlockItem(builder(), Blocks.SUNFLOWER));
+ public static final Item LILAC = register(new BlockItem(builder(), Blocks.LILAC));
+ public static final Item ROSE_BUSH = register(new BlockItem(builder(), Blocks.ROSE_BUSH));
+ public static final Item PEONY = register(new BlockItem(builder(), Blocks.PEONY));
+ public static final Item TALL_GRASS = register(new BlockItem(builder(), Blocks.TALL_GRASS));
+ public static final Item LARGE_FERN = register(new BlockItem(builder(), Blocks.LARGE_FERN));
+ public static final Item WHITE_STAINED_GLASS = register(new BlockItem(builder(), Blocks.WHITE_STAINED_GLASS));
+ public static final Item ORANGE_STAINED_GLASS = register(new BlockItem(builder(), Blocks.ORANGE_STAINED_GLASS));
+ public static final Item MAGENTA_STAINED_GLASS = register(new BlockItem(builder(), Blocks.MAGENTA_STAINED_GLASS));
+ public static final Item LIGHT_BLUE_STAINED_GLASS = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_STAINED_GLASS));
+ public static final Item YELLOW_STAINED_GLASS = register(new BlockItem(builder(), Blocks.YELLOW_STAINED_GLASS));
+ public static final Item LIME_STAINED_GLASS = register(new BlockItem(builder(), Blocks.LIME_STAINED_GLASS));
+ public static final Item PINK_STAINED_GLASS = register(new BlockItem(builder(), Blocks.PINK_STAINED_GLASS));
+ public static final Item GRAY_STAINED_GLASS = register(new BlockItem(builder(), Blocks.GRAY_STAINED_GLASS));
+ public static final Item LIGHT_GRAY_STAINED_GLASS = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_STAINED_GLASS));
+ public static final Item CYAN_STAINED_GLASS = register(new BlockItem(builder(), Blocks.CYAN_STAINED_GLASS));
+ public static final Item PURPLE_STAINED_GLASS = register(new BlockItem(builder(), Blocks.PURPLE_STAINED_GLASS));
+ public static final Item BLUE_STAINED_GLASS = register(new BlockItem(builder(), Blocks.BLUE_STAINED_GLASS));
+ public static final Item BROWN_STAINED_GLASS = register(new BlockItem(builder(), Blocks.BROWN_STAINED_GLASS));
+ public static final Item GREEN_STAINED_GLASS = register(new BlockItem(builder(), Blocks.GREEN_STAINED_GLASS));
+ public static final Item RED_STAINED_GLASS = register(new BlockItem(builder(), Blocks.RED_STAINED_GLASS));
+ public static final Item BLACK_STAINED_GLASS = register(new BlockItem(builder(), Blocks.BLACK_STAINED_GLASS));
+ public static final Item WHITE_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.WHITE_STAINED_GLASS_PANE));
+ public static final Item ORANGE_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.ORANGE_STAINED_GLASS_PANE));
+ public static final Item MAGENTA_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.MAGENTA_STAINED_GLASS_PANE));
+ public static final Item LIGHT_BLUE_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_STAINED_GLASS_PANE));
+ public static final Item YELLOW_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.YELLOW_STAINED_GLASS_PANE));
+ public static final Item LIME_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.LIME_STAINED_GLASS_PANE));
+ public static final Item PINK_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.PINK_STAINED_GLASS_PANE));
+ public static final Item GRAY_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.GRAY_STAINED_GLASS_PANE));
+ public static final Item LIGHT_GRAY_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_STAINED_GLASS_PANE));
+ public static final Item CYAN_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.CYAN_STAINED_GLASS_PANE));
+ public static final Item PURPLE_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.PURPLE_STAINED_GLASS_PANE));
+ public static final Item BLUE_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.BLUE_STAINED_GLASS_PANE));
+ public static final Item BROWN_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.BROWN_STAINED_GLASS_PANE));
+ public static final Item GREEN_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.GREEN_STAINED_GLASS_PANE));
+ public static final Item RED_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.RED_STAINED_GLASS_PANE));
+ public static final Item BLACK_STAINED_GLASS_PANE = register(new BlockItem(builder(), Blocks.BLACK_STAINED_GLASS_PANE));
+ public static final Item PRISMARINE = register(new BlockItem(builder(), Blocks.PRISMARINE));
+ public static final Item PRISMARINE_BRICKS = register(new BlockItem(builder(), Blocks.PRISMARINE_BRICKS));
+ public static final Item DARK_PRISMARINE = register(new BlockItem(builder(), Blocks.DARK_PRISMARINE));
+ public static final Item PRISMARINE_STAIRS = register(new BlockItem(builder(), Blocks.PRISMARINE_STAIRS));
+ public static final Item PRISMARINE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.PRISMARINE_BRICK_STAIRS));
+ public static final Item DARK_PRISMARINE_STAIRS = register(new BlockItem(builder(), Blocks.DARK_PRISMARINE_STAIRS));
+ public static final Item SEA_LANTERN = register(new BlockItem(builder(), Blocks.SEA_LANTERN));
+ public static final Item RED_SANDSTONE = register(new BlockItem(builder(), Blocks.RED_SANDSTONE));
+ public static final Item CHISELED_RED_SANDSTONE = register(new BlockItem(builder(), Blocks.CHISELED_RED_SANDSTONE));
+ public static final Item CUT_RED_SANDSTONE = register(new BlockItem(builder(), Blocks.CUT_RED_SANDSTONE));
+ public static final Item RED_SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.RED_SANDSTONE_STAIRS));
+ public static final Item REPEATING_COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.REPEATING_COMMAND_BLOCK));
+ public static final Item CHAIN_COMMAND_BLOCK = register(new BlockItem(builder(), Blocks.CHAIN_COMMAND_BLOCK));
+ public static final Item MAGMA_BLOCK = register(new BlockItem(builder(), Blocks.MAGMA_BLOCK));
+ public static final Item NETHER_WART_BLOCK = register(new BlockItem(builder(), Blocks.NETHER_WART_BLOCK));
+ public static final Item WARPED_WART_BLOCK = register(new BlockItem(builder(), Blocks.WARPED_WART_BLOCK));
+ public static final Item RED_NETHER_BRICKS = register(new BlockItem(builder(), Blocks.RED_NETHER_BRICKS));
+ public static final Item BONE_BLOCK = register(new BlockItem(builder(), Blocks.BONE_BLOCK));
+ public static final Item STRUCTURE_VOID = register(new BlockItem(builder(), Blocks.STRUCTURE_VOID));
+ public static final Item SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.SHULKER_BOX));
+ public static final Item WHITE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.WHITE_SHULKER_BOX));
+ public static final Item ORANGE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.ORANGE_SHULKER_BOX));
+ public static final Item MAGENTA_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.MAGENTA_SHULKER_BOX));
+ public static final Item LIGHT_BLUE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.LIGHT_BLUE_SHULKER_BOX));
+ public static final Item YELLOW_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.YELLOW_SHULKER_BOX));
+ public static final Item LIME_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.LIME_SHULKER_BOX));
+ public static final Item PINK_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.PINK_SHULKER_BOX));
+ public static final Item GRAY_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.GRAY_SHULKER_BOX));
+ public static final Item LIGHT_GRAY_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.LIGHT_GRAY_SHULKER_BOX));
+ public static final Item CYAN_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.CYAN_SHULKER_BOX));
+ public static final Item PURPLE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.PURPLE_SHULKER_BOX));
+ public static final Item BLUE_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.BLUE_SHULKER_BOX));
+ public static final Item BROWN_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.BROWN_SHULKER_BOX));
+ public static final Item GREEN_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.GREEN_SHULKER_BOX));
+ public static final Item RED_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.RED_SHULKER_BOX));
+ public static final Item BLACK_SHULKER_BOX = register(new ShulkerBoxItem(builder().stackSize(1), Blocks.BLACK_SHULKER_BOX));
+ public static final Item WHITE_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.WHITE_GLAZED_TERRACOTTA));
+ public static final Item ORANGE_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.ORANGE_GLAZED_TERRACOTTA));
+ public static final Item MAGENTA_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.MAGENTA_GLAZED_TERRACOTTA));
+ public static final Item LIGHT_BLUE_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_GLAZED_TERRACOTTA));
+ public static final Item YELLOW_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.YELLOW_GLAZED_TERRACOTTA));
+ public static final Item LIME_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.LIME_GLAZED_TERRACOTTA));
+ public static final Item PINK_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.PINK_GLAZED_TERRACOTTA));
+ public static final Item GRAY_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.GRAY_GLAZED_TERRACOTTA));
+ public static final Item LIGHT_GRAY_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_GLAZED_TERRACOTTA));
+ public static final Item CYAN_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.CYAN_GLAZED_TERRACOTTA));
+ public static final Item PURPLE_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.PURPLE_GLAZED_TERRACOTTA));
+ public static final Item BLUE_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.BLUE_GLAZED_TERRACOTTA));
+ public static final Item BROWN_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.BROWN_GLAZED_TERRACOTTA));
+ public static final Item GREEN_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.GREEN_GLAZED_TERRACOTTA));
+ public static final Item RED_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.RED_GLAZED_TERRACOTTA));
+ public static final Item BLACK_GLAZED_TERRACOTTA = register(new BlockItem(builder(), Blocks.BLACK_GLAZED_TERRACOTTA));
+ public static final Item WHITE_CONCRETE = register(new BlockItem(builder(), Blocks.WHITE_CONCRETE));
+ public static final Item ORANGE_CONCRETE = register(new BlockItem(builder(), Blocks.ORANGE_CONCRETE));
+ public static final Item MAGENTA_CONCRETE = register(new BlockItem(builder(), Blocks.MAGENTA_CONCRETE));
+ public static final Item LIGHT_BLUE_CONCRETE = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_CONCRETE));
+ public static final Item YELLOW_CONCRETE = register(new BlockItem(builder(), Blocks.YELLOW_CONCRETE));
+ public static final Item LIME_CONCRETE = register(new BlockItem(builder(), Blocks.LIME_CONCRETE));
+ public static final Item PINK_CONCRETE = register(new BlockItem(builder(), Blocks.PINK_CONCRETE));
+ public static final Item GRAY_CONCRETE = register(new BlockItem(builder(), Blocks.GRAY_CONCRETE));
+ public static final Item LIGHT_GRAY_CONCRETE = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_CONCRETE));
+ public static final Item CYAN_CONCRETE = register(new BlockItem(builder(), Blocks.CYAN_CONCRETE));
+ public static final Item PURPLE_CONCRETE = register(new BlockItem(builder(), Blocks.PURPLE_CONCRETE));
+ public static final Item BLUE_CONCRETE = register(new BlockItem(builder(), Blocks.BLUE_CONCRETE));
+ public static final Item BROWN_CONCRETE = register(new BlockItem(builder(), Blocks.BROWN_CONCRETE));
+ public static final Item GREEN_CONCRETE = register(new BlockItem(builder(), Blocks.GREEN_CONCRETE));
+ public static final Item RED_CONCRETE = register(new BlockItem(builder(), Blocks.RED_CONCRETE));
+ public static final Item BLACK_CONCRETE = register(new BlockItem(builder(), Blocks.BLACK_CONCRETE));
+ public static final Item WHITE_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.WHITE_CONCRETE_POWDER));
+ public static final Item ORANGE_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.ORANGE_CONCRETE_POWDER));
+ public static final Item MAGENTA_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.MAGENTA_CONCRETE_POWDER));
+ public static final Item LIGHT_BLUE_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_CONCRETE_POWDER));
+ public static final Item YELLOW_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.YELLOW_CONCRETE_POWDER));
+ public static final Item LIME_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.LIME_CONCRETE_POWDER));
+ public static final Item PINK_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.PINK_CONCRETE_POWDER));
+ public static final Item GRAY_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.GRAY_CONCRETE_POWDER));
+ public static final Item LIGHT_GRAY_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_CONCRETE_POWDER));
+ public static final Item CYAN_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.CYAN_CONCRETE_POWDER));
+ public static final Item PURPLE_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.PURPLE_CONCRETE_POWDER));
+ public static final Item BLUE_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.BLUE_CONCRETE_POWDER));
+ public static final Item BROWN_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.BROWN_CONCRETE_POWDER));
+ public static final Item GREEN_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.GREEN_CONCRETE_POWDER));
+ public static final Item RED_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.RED_CONCRETE_POWDER));
+ public static final Item BLACK_CONCRETE_POWDER = register(new BlockItem(builder(), Blocks.BLACK_CONCRETE_POWDER));
+ public static final Item TURTLE_EGG = register(new BlockItem(builder(), Blocks.TURTLE_EGG));
+ public static final Item SNIFFER_EGG = register(new BlockItem(builder(), Blocks.SNIFFER_EGG));
+ public static final Item DEAD_TUBE_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.DEAD_TUBE_CORAL_BLOCK));
+ public static final Item DEAD_BRAIN_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.DEAD_BRAIN_CORAL_BLOCK));
+ public static final Item DEAD_BUBBLE_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.DEAD_BUBBLE_CORAL_BLOCK));
+ public static final Item DEAD_FIRE_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.DEAD_FIRE_CORAL_BLOCK));
+ public static final Item DEAD_HORN_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.DEAD_HORN_CORAL_BLOCK));
+ public static final Item TUBE_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.TUBE_CORAL_BLOCK));
+ public static final Item BRAIN_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.BRAIN_CORAL_BLOCK));
+ public static final Item BUBBLE_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.BUBBLE_CORAL_BLOCK));
+ public static final Item FIRE_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.FIRE_CORAL_BLOCK));
+ public static final Item HORN_CORAL_BLOCK = register(new BlockItem(builder(), Blocks.HORN_CORAL_BLOCK));
+ public static final Item TUBE_CORAL = register(new BlockItem(builder(), Blocks.TUBE_CORAL));
+ public static final Item BRAIN_CORAL = register(new BlockItem(builder(), Blocks.BRAIN_CORAL));
+ public static final Item BUBBLE_CORAL = register(new BlockItem(builder(), Blocks.BUBBLE_CORAL));
+ public static final Item FIRE_CORAL = register(new BlockItem(builder(), Blocks.FIRE_CORAL));
+ public static final Item HORN_CORAL = register(new BlockItem(builder(), Blocks.HORN_CORAL));
+ public static final Item DEAD_BRAIN_CORAL = register(new BlockItem(builder(), Blocks.DEAD_BRAIN_CORAL));
+ public static final Item DEAD_BUBBLE_CORAL = register(new BlockItem(builder(), Blocks.DEAD_BUBBLE_CORAL));
+ public static final Item DEAD_FIRE_CORAL = register(new BlockItem(builder(), Blocks.DEAD_FIRE_CORAL));
+ public static final Item DEAD_HORN_CORAL = register(new BlockItem(builder(), Blocks.DEAD_HORN_CORAL));
+ public static final Item DEAD_TUBE_CORAL = register(new BlockItem(builder(), Blocks.DEAD_TUBE_CORAL));
+ public static final Item TUBE_CORAL_FAN = register(new BlockItem(builder(), Blocks.TUBE_CORAL_FAN, Blocks.TUBE_CORAL_WALL_FAN));
+ public static final Item BRAIN_CORAL_FAN = register(new BlockItem(builder(), Blocks.BRAIN_CORAL_FAN, Blocks.BRAIN_CORAL_WALL_FAN));
+ public static final Item BUBBLE_CORAL_FAN = register(new BlockItem(builder(), Blocks.BUBBLE_CORAL_FAN, Blocks.BUBBLE_CORAL_WALL_FAN));
+ public static final Item FIRE_CORAL_FAN = register(new BlockItem(builder(), Blocks.FIRE_CORAL_FAN, Blocks.FIRE_CORAL_WALL_FAN));
+ public static final Item HORN_CORAL_FAN = register(new BlockItem(builder(), Blocks.HORN_CORAL_FAN, Blocks.HORN_CORAL_WALL_FAN));
+ public static final Item DEAD_TUBE_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_TUBE_CORAL_FAN, Blocks.DEAD_TUBE_CORAL_WALL_FAN));
+ public static final Item DEAD_BRAIN_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_BRAIN_CORAL_FAN, Blocks.DEAD_BRAIN_CORAL_WALL_FAN));
+ public static final Item DEAD_BUBBLE_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_BUBBLE_CORAL_FAN, Blocks.DEAD_BUBBLE_CORAL_WALL_FAN));
+ public static final Item DEAD_FIRE_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_FIRE_CORAL_FAN, Blocks.DEAD_FIRE_CORAL_WALL_FAN));
+ public static final Item DEAD_HORN_CORAL_FAN = register(new BlockItem(builder(), Blocks.DEAD_HORN_CORAL_FAN, Blocks.DEAD_HORN_CORAL_WALL_FAN));
+ public static final Item BLUE_ICE = register(new BlockItem(builder(), Blocks.BLUE_ICE));
+ public static final Item CONDUIT = register(new BlockItem(builder(), Blocks.CONDUIT));
+ public static final Item POLISHED_GRANITE_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_GRANITE_STAIRS));
+ public static final Item SMOOTH_RED_SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.SMOOTH_RED_SANDSTONE_STAIRS));
+ public static final Item MOSSY_STONE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.MOSSY_STONE_BRICK_STAIRS));
+ public static final Item POLISHED_DIORITE_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_DIORITE_STAIRS));
+ public static final Item MOSSY_COBBLESTONE_STAIRS = register(new BlockItem(builder(), Blocks.MOSSY_COBBLESTONE_STAIRS));
+ public static final Item END_STONE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.END_STONE_BRICK_STAIRS));
+ public static final Item STONE_STAIRS = register(new BlockItem(builder(), Blocks.STONE_STAIRS));
+ public static final Item SMOOTH_SANDSTONE_STAIRS = register(new BlockItem(builder(), Blocks.SMOOTH_SANDSTONE_STAIRS));
+ public static final Item SMOOTH_QUARTZ_STAIRS = register(new BlockItem(builder(), Blocks.SMOOTH_QUARTZ_STAIRS));
+ public static final Item GRANITE_STAIRS = register(new BlockItem(builder(), Blocks.GRANITE_STAIRS));
+ public static final Item ANDESITE_STAIRS = register(new BlockItem(builder(), Blocks.ANDESITE_STAIRS));
+ public static final Item RED_NETHER_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.RED_NETHER_BRICK_STAIRS));
+ public static final Item POLISHED_ANDESITE_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_ANDESITE_STAIRS));
+ public static final Item DIORITE_STAIRS = register(new BlockItem(builder(), Blocks.DIORITE_STAIRS));
+ public static final Item COBBLED_DEEPSLATE_STAIRS = register(new BlockItem(builder(), Blocks.COBBLED_DEEPSLATE_STAIRS));
+ public static final Item POLISHED_DEEPSLATE_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_DEEPSLATE_STAIRS));
+ public static final Item DEEPSLATE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.DEEPSLATE_BRICK_STAIRS));
+ public static final Item DEEPSLATE_TILE_STAIRS = register(new BlockItem(builder(), Blocks.DEEPSLATE_TILE_STAIRS));
+ public static final Item POLISHED_GRANITE_SLAB = register(new BlockItem(builder(), Blocks.POLISHED_GRANITE_SLAB));
+ public static final Item SMOOTH_RED_SANDSTONE_SLAB = register(new BlockItem(builder(), Blocks.SMOOTH_RED_SANDSTONE_SLAB));
+ public static final Item MOSSY_STONE_BRICK_SLAB = register(new BlockItem(builder(), Blocks.MOSSY_STONE_BRICK_SLAB));
+ public static final Item POLISHED_DIORITE_SLAB = register(new BlockItem(builder(), Blocks.POLISHED_DIORITE_SLAB));
+ public static final Item MOSSY_COBBLESTONE_SLAB = register(new BlockItem(builder(), Blocks.MOSSY_COBBLESTONE_SLAB));
+ public static final Item END_STONE_BRICK_SLAB = register(new BlockItem(builder(), Blocks.END_STONE_BRICK_SLAB));
+ public static final Item SMOOTH_SANDSTONE_SLAB = register(new BlockItem(builder(), Blocks.SMOOTH_SANDSTONE_SLAB));
+ public static final Item SMOOTH_QUARTZ_SLAB = register(new BlockItem(builder(), Blocks.SMOOTH_QUARTZ_SLAB));
+ public static final Item GRANITE_SLAB = register(new BlockItem(builder(), Blocks.GRANITE_SLAB));
+ public static final Item ANDESITE_SLAB = register(new BlockItem(builder(), Blocks.ANDESITE_SLAB));
+ public static final Item RED_NETHER_BRICK_SLAB = register(new BlockItem(builder(), Blocks.RED_NETHER_BRICK_SLAB));
+ public static final Item POLISHED_ANDESITE_SLAB = register(new BlockItem(builder(), Blocks.POLISHED_ANDESITE_SLAB));
+ public static final Item DIORITE_SLAB = register(new BlockItem(builder(), Blocks.DIORITE_SLAB));
+ public static final Item COBBLED_DEEPSLATE_SLAB = register(new BlockItem(builder(), Blocks.COBBLED_DEEPSLATE_SLAB));
+ public static final Item POLISHED_DEEPSLATE_SLAB = register(new BlockItem(builder(), Blocks.POLISHED_DEEPSLATE_SLAB));
+ public static final Item DEEPSLATE_BRICK_SLAB = register(new BlockItem(builder(), Blocks.DEEPSLATE_BRICK_SLAB));
+ public static final Item DEEPSLATE_TILE_SLAB = register(new BlockItem(builder(), Blocks.DEEPSLATE_TILE_SLAB));
+ public static final Item SCAFFOLDING = register(new BlockItem(builder(), Blocks.SCAFFOLDING));
+ public static final Item REDSTONE = register(new BlockItem("redstone", builder(), Blocks.REDSTONE_WIRE));
+ public static final Item REDSTONE_TORCH = register(new BlockItem(builder(), Blocks.REDSTONE_TORCH, Blocks.REDSTONE_WALL_TORCH));
+ public static final Item REDSTONE_BLOCK = register(new BlockItem(builder(), Blocks.REDSTONE_BLOCK));
+ public static final Item REPEATER = register(new BlockItem(builder(), Blocks.REPEATER));
+ public static final Item COMPARATOR = register(new BlockItem(builder(), Blocks.COMPARATOR));
+ public static final Item PISTON = register(new BlockItem(builder(), Blocks.PISTON));
+ public static final Item STICKY_PISTON = register(new BlockItem(builder(), Blocks.STICKY_PISTON));
+ public static final Item SLIME_BLOCK = register(new BlockItem(builder(), Blocks.SLIME_BLOCK));
+ public static final Item HONEY_BLOCK = register(new BlockItem(builder(), Blocks.HONEY_BLOCK));
+ public static final Item OBSERVER = register(new BlockItem(builder(), Blocks.OBSERVER));
+ public static final Item HOPPER = register(new BlockItem(builder(), Blocks.HOPPER));
+ public static final Item DISPENSER = register(new BlockItem(builder(), Blocks.DISPENSER));
+ public static final Item DROPPER = register(new BlockItem(builder(), Blocks.DROPPER));
+ public static final Item LECTERN = register(new BlockItem(builder(), Blocks.LECTERN));
+ public static final Item TARGET = register(new BlockItem(builder(), Blocks.TARGET));
+ public static final Item LEVER = register(new BlockItem(builder(), Blocks.LEVER));
+ public static final Item LIGHTNING_ROD = register(new BlockItem(builder(), Blocks.LIGHTNING_ROD));
+ public static final Item DAYLIGHT_DETECTOR = register(new BlockItem(builder(), Blocks.DAYLIGHT_DETECTOR));
+ public static final Item SCULK_SENSOR = register(new BlockItem(builder(), Blocks.SCULK_SENSOR));
+ public static final Item CALIBRATED_SCULK_SENSOR = register(new BlockItem(builder(), Blocks.CALIBRATED_SCULK_SENSOR));
+ public static final Item TRIPWIRE_HOOK = register(new BlockItem(builder(), Blocks.TRIPWIRE_HOOK));
+ public static final Item TRAPPED_CHEST = register(new BlockItem(builder(), Blocks.TRAPPED_CHEST));
+ public static final Item TNT = register(new BlockItem(builder(), Blocks.TNT));
+ public static final Item REDSTONE_LAMP = register(new BlockItem(builder(), Blocks.REDSTONE_LAMP));
+ public static final Item NOTE_BLOCK = register(new BlockItem(builder(), Blocks.NOTE_BLOCK));
+ public static final Item STONE_BUTTON = register(new BlockItem(builder(), Blocks.STONE_BUTTON));
+ public static final Item POLISHED_BLACKSTONE_BUTTON = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_BUTTON));
+ public static final Item OAK_BUTTON = register(new BlockItem(builder(), Blocks.OAK_BUTTON));
+ public static final Item SPRUCE_BUTTON = register(new BlockItem(builder(), Blocks.SPRUCE_BUTTON));
+ public static final Item BIRCH_BUTTON = register(new BlockItem(builder(), Blocks.BIRCH_BUTTON));
+ public static final Item JUNGLE_BUTTON = register(new BlockItem(builder(), Blocks.JUNGLE_BUTTON));
+ public static final Item ACACIA_BUTTON = register(new BlockItem(builder(), Blocks.ACACIA_BUTTON));
+ public static final Item CHERRY_BUTTON = register(new BlockItem(builder(), Blocks.CHERRY_BUTTON));
+ public static final Item DARK_OAK_BUTTON = register(new BlockItem(builder(), Blocks.DARK_OAK_BUTTON));
+ public static final Item MANGROVE_BUTTON = register(new BlockItem(builder(), Blocks.MANGROVE_BUTTON));
+ public static final Item BAMBOO_BUTTON = register(new BlockItem(builder(), Blocks.BAMBOO_BUTTON));
+ public static final Item CRIMSON_BUTTON = register(new BlockItem(builder(), Blocks.CRIMSON_BUTTON));
+ public static final Item WARPED_BUTTON = register(new BlockItem(builder(), Blocks.WARPED_BUTTON));
+ public static final Item STONE_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.STONE_PRESSURE_PLATE));
+ public static final Item POLISHED_BLACKSTONE_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_PRESSURE_PLATE));
+ public static final Item LIGHT_WEIGHTED_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.LIGHT_WEIGHTED_PRESSURE_PLATE));
+ public static final Item HEAVY_WEIGHTED_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.HEAVY_WEIGHTED_PRESSURE_PLATE));
+ public static final Item OAK_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.OAK_PRESSURE_PLATE));
+ public static final Item SPRUCE_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.SPRUCE_PRESSURE_PLATE));
+ public static final Item BIRCH_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.BIRCH_PRESSURE_PLATE));
+ public static final Item JUNGLE_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.JUNGLE_PRESSURE_PLATE));
+ public static final Item ACACIA_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.ACACIA_PRESSURE_PLATE));
+ public static final Item CHERRY_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.CHERRY_PRESSURE_PLATE));
+ public static final Item DARK_OAK_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.DARK_OAK_PRESSURE_PLATE));
+ public static final Item MANGROVE_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.MANGROVE_PRESSURE_PLATE));
+ public static final Item BAMBOO_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.BAMBOO_PRESSURE_PLATE));
+ public static final Item CRIMSON_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.CRIMSON_PRESSURE_PLATE));
+ public static final Item WARPED_PRESSURE_PLATE = register(new BlockItem(builder(), Blocks.WARPED_PRESSURE_PLATE));
+ public static final Item IRON_DOOR = register(new BlockItem(builder(), Blocks.IRON_DOOR));
+ public static final Item OAK_DOOR = register(new BlockItem(builder(), Blocks.OAK_DOOR));
+ public static final Item SPRUCE_DOOR = register(new BlockItem(builder(), Blocks.SPRUCE_DOOR));
+ public static final Item BIRCH_DOOR = register(new BlockItem(builder(), Blocks.BIRCH_DOOR));
+ public static final Item JUNGLE_DOOR = register(new BlockItem(builder(), Blocks.JUNGLE_DOOR));
+ public static final Item ACACIA_DOOR = register(new BlockItem(builder(), Blocks.ACACIA_DOOR));
+ public static final Item CHERRY_DOOR = register(new BlockItem(builder(), Blocks.CHERRY_DOOR));
+ public static final Item DARK_OAK_DOOR = register(new BlockItem(builder(), Blocks.DARK_OAK_DOOR));
+ public static final Item MANGROVE_DOOR = register(new BlockItem(builder(), Blocks.MANGROVE_DOOR));
+ public static final Item BAMBOO_DOOR = register(new BlockItem(builder(), Blocks.BAMBOO_DOOR));
+ public static final Item CRIMSON_DOOR = register(new BlockItem(builder(), Blocks.CRIMSON_DOOR));
+ public static final Item WARPED_DOOR = register(new BlockItem(builder(), Blocks.WARPED_DOOR));
+ public static final Item COPPER_DOOR = register(new BlockItem(builder(), Blocks.COPPER_DOOR));
+ public static final Item EXPOSED_COPPER_DOOR = register(new BlockItem(builder(), Blocks.EXPOSED_COPPER_DOOR));
+ public static final Item WEATHERED_COPPER_DOOR = register(new BlockItem(builder(), Blocks.WEATHERED_COPPER_DOOR));
+ public static final Item OXIDIZED_COPPER_DOOR = register(new BlockItem(builder(), Blocks.OXIDIZED_COPPER_DOOR));
+ public static final Item WAXED_COPPER_DOOR = register(new BlockItem(builder(), Blocks.WAXED_COPPER_DOOR));
+ public static final Item WAXED_EXPOSED_COPPER_DOOR = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_COPPER_DOOR));
+ public static final Item WAXED_WEATHERED_COPPER_DOOR = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_COPPER_DOOR));
+ public static final Item WAXED_OXIDIZED_COPPER_DOOR = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_COPPER_DOOR));
+ public static final Item IRON_TRAPDOOR = register(new BlockItem(builder(), Blocks.IRON_TRAPDOOR));
+ public static final Item OAK_TRAPDOOR = register(new BlockItem(builder(), Blocks.OAK_TRAPDOOR));
+ public static final Item SPRUCE_TRAPDOOR = register(new BlockItem(builder(), Blocks.SPRUCE_TRAPDOOR));
+ public static final Item BIRCH_TRAPDOOR = register(new BlockItem(builder(), Blocks.BIRCH_TRAPDOOR));
+ public static final Item JUNGLE_TRAPDOOR = register(new BlockItem(builder(), Blocks.JUNGLE_TRAPDOOR));
+ public static final Item ACACIA_TRAPDOOR = register(new BlockItem(builder(), Blocks.ACACIA_TRAPDOOR));
+ public static final Item CHERRY_TRAPDOOR = register(new BlockItem(builder(), Blocks.CHERRY_TRAPDOOR));
+ public static final Item DARK_OAK_TRAPDOOR = register(new BlockItem(builder(), Blocks.DARK_OAK_TRAPDOOR));
+ public static final Item MANGROVE_TRAPDOOR = register(new BlockItem(builder(), Blocks.MANGROVE_TRAPDOOR));
+ public static final Item BAMBOO_TRAPDOOR = register(new BlockItem(builder(), Blocks.BAMBOO_TRAPDOOR));
+ public static final Item CRIMSON_TRAPDOOR = register(new BlockItem(builder(), Blocks.CRIMSON_TRAPDOOR));
+ public static final Item WARPED_TRAPDOOR = register(new BlockItem(builder(), Blocks.WARPED_TRAPDOOR));
+ public static final Item COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.COPPER_TRAPDOOR));
+ public static final Item EXPOSED_COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.EXPOSED_COPPER_TRAPDOOR));
+ public static final Item WEATHERED_COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.WEATHERED_COPPER_TRAPDOOR));
+ public static final Item OXIDIZED_COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.OXIDIZED_COPPER_TRAPDOOR));
+ public static final Item WAXED_COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.WAXED_COPPER_TRAPDOOR));
+ public static final Item WAXED_EXPOSED_COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_COPPER_TRAPDOOR));
+ public static final Item WAXED_WEATHERED_COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_COPPER_TRAPDOOR));
+ public static final Item WAXED_OXIDIZED_COPPER_TRAPDOOR = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_COPPER_TRAPDOOR));
+ public static final Item OAK_FENCE_GATE = register(new BlockItem(builder(), Blocks.OAK_FENCE_GATE));
+ public static final Item SPRUCE_FENCE_GATE = register(new BlockItem(builder(), Blocks.SPRUCE_FENCE_GATE));
+ public static final Item BIRCH_FENCE_GATE = register(new BlockItem(builder(), Blocks.BIRCH_FENCE_GATE));
+ public static final Item JUNGLE_FENCE_GATE = register(new BlockItem(builder(), Blocks.JUNGLE_FENCE_GATE));
+ public static final Item ACACIA_FENCE_GATE = register(new BlockItem(builder(), Blocks.ACACIA_FENCE_GATE));
+ public static final Item CHERRY_FENCE_GATE = register(new BlockItem(builder(), Blocks.CHERRY_FENCE_GATE));
+ public static final Item DARK_OAK_FENCE_GATE = register(new BlockItem(builder(), Blocks.DARK_OAK_FENCE_GATE));
+ public static final Item MANGROVE_FENCE_GATE = register(new BlockItem(builder(), Blocks.MANGROVE_FENCE_GATE));
+ public static final Item BAMBOO_FENCE_GATE = register(new BlockItem(builder(), Blocks.BAMBOO_FENCE_GATE));
+ public static final Item CRIMSON_FENCE_GATE = register(new BlockItem(builder(), Blocks.CRIMSON_FENCE_GATE));
+ public static final Item WARPED_FENCE_GATE = register(new BlockItem(builder(), Blocks.WARPED_FENCE_GATE));
+ public static final Item POWERED_RAIL = register(new BlockItem(builder(), Blocks.POWERED_RAIL));
+ public static final Item DETECTOR_RAIL = register(new BlockItem(builder(), Blocks.DETECTOR_RAIL));
+ public static final Item RAIL = register(new BlockItem(builder(), Blocks.RAIL));
+ public static final Item ACTIVATOR_RAIL = register(new BlockItem(builder(), Blocks.ACTIVATOR_RAIL));
public static final Item SADDLE = register(new Item("saddle", builder().stackSize(1)));
public static final Item MINECART = register(new Item("minecart", builder().stackSize(1)));
public static final Item CHEST_MINECART = register(new Item("chest_minecart", builder().stackSize(1)));
@@ -829,11 +829,14 @@ public final class Items {
public static final Item MANGROVE_CHEST_BOAT = register(new BoatItem("mangrove_chest_boat", builder().stackSize(1)));
public static final Item BAMBOO_RAFT = register(new BoatItem("bamboo_raft", builder().stackSize(1)));
public static final Item BAMBOO_CHEST_RAFT = register(new BoatItem("bamboo_chest_raft", builder().stackSize(1)));
- public static final Item STRUCTURE_BLOCK = register(new BlockItem("structure_block", builder()));
- public static final Item JIGSAW = register(new BlockItem("jigsaw", builder()));
+ public static final Item STRUCTURE_BLOCK = register(new BlockItem(builder(), Blocks.STRUCTURE_BLOCK));
+ public static final Item JIGSAW = register(new BlockItem(builder(), Blocks.JIGSAW));
public static final Item TURTLE_HELMET = register(new ArmorItem("turtle_helmet", ArmorMaterial.TURTLE, builder().stackSize(1).maxDamage(275)));
- public static final Item SCUTE = register(new Item("scute", builder()));
+ public static final Item TURTLE_SCUTE = register(new Item("turtle_scute", builder()));
+ public static final Item ARMADILLO_SCUTE = register(new Item("armadillo_scute", builder()));
+ public static final Item WOLF_ARMOR = register(new WolfArmorItem("wolf_armor", ArmorMaterial.ARMADILLO, builder().stackSize(1).maxDamage(64)));
public static final Item FLINT_AND_STEEL = register(new Item("flint_and_steel", builder().stackSize(1).maxDamage(64)));
+ public static final Item BOWL = register(new Item("bowl", builder()));
public static final Item APPLE = register(new Item("apple", builder()));
public static final Item BOW = register(new Item("bow", builder().stackSize(1).maxDamage(384)));
public static final Item ARROW = register(new ArrowItem("arrow", builder()));
@@ -852,53 +855,52 @@ public final class Items {
public static final Item GOLD_INGOT = register(new Item("gold_ingot", builder()));
public static final Item NETHERITE_INGOT = register(new Item("netherite_ingot", builder()));
public static final Item NETHERITE_SCRAP = register(new Item("netherite_scrap", builder()));
- public static final Item WOODEN_SWORD = register(new TieredItem("wooden_sword", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59)));
- public static final Item WOODEN_SHOVEL = register(new TieredItem("wooden_shovel", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59)));
- public static final Item WOODEN_PICKAXE = register(new TieredItem("wooden_pickaxe", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59)));
- public static final Item WOODEN_AXE = register(new TieredItem("wooden_axe", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59)));
- public static final Item WOODEN_HOE = register(new TieredItem("wooden_hoe", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59)));
- public static final Item STONE_SWORD = register(new TieredItem("stone_sword", ToolTier.STONE, builder().stackSize(1).maxDamage(131)));
- public static final Item STONE_SHOVEL = register(new TieredItem("stone_shovel", ToolTier.STONE, builder().stackSize(1).maxDamage(131)));
- public static final Item STONE_PICKAXE = register(new TieredItem("stone_pickaxe", ToolTier.STONE, builder().stackSize(1).maxDamage(131)));
- public static final Item STONE_AXE = register(new TieredItem("stone_axe", ToolTier.STONE, builder().stackSize(1).maxDamage(131)));
- public static final Item STONE_HOE = register(new TieredItem("stone_hoe", ToolTier.STONE, builder().stackSize(1).maxDamage(131)));
- public static final Item GOLDEN_SWORD = register(new TieredItem("golden_sword", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32)));
- public static final Item GOLDEN_SHOVEL = register(new TieredItem("golden_shovel", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32)));
- public static final Item GOLDEN_PICKAXE = register(new TieredItem("golden_pickaxe", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32)));
- public static final Item GOLDEN_AXE = register(new TieredItem("golden_axe", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32)));
- public static final Item GOLDEN_HOE = register(new TieredItem("golden_hoe", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32)));
- public static final Item IRON_SWORD = register(new TieredItem("iron_sword", ToolTier.IRON, builder().stackSize(1).maxDamage(250)));
- public static final Item IRON_SHOVEL = register(new TieredItem("iron_shovel", ToolTier.IRON, builder().stackSize(1).maxDamage(250)));
- public static final Item IRON_PICKAXE = register(new TieredItem("iron_pickaxe", ToolTier.IRON, builder().stackSize(1).maxDamage(250)));
- public static final Item IRON_AXE = register(new TieredItem("iron_axe", ToolTier.IRON, builder().stackSize(1).maxDamage(250)));
- public static final Item IRON_HOE = register(new TieredItem("iron_hoe", ToolTier.IRON, builder().stackSize(1).maxDamage(250)));
- public static final Item DIAMOND_SWORD = register(new TieredItem("diamond_sword", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561)));
- public static final Item DIAMOND_SHOVEL = register(new TieredItem("diamond_shovel", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561)));
- public static final Item DIAMOND_PICKAXE = register(new TieredItem("diamond_pickaxe", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561)));
- public static final Item DIAMOND_AXE = register(new TieredItem("diamond_axe", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561)));
- public static final Item DIAMOND_HOE = register(new TieredItem("diamond_hoe", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561)));
- public static final Item NETHERITE_SWORD = register(new TieredItem("netherite_sword", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031)));
- public static final Item NETHERITE_SHOVEL = register(new TieredItem("netherite_shovel", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031)));
- public static final Item NETHERITE_PICKAXE = register(new TieredItem("netherite_pickaxe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031)));
- public static final Item NETHERITE_AXE = register(new TieredItem("netherite_axe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031)));
- public static final Item NETHERITE_HOE = register(new TieredItem("netherite_hoe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031)));
+ public static final Item WOODEN_SWORD = register(new TieredItem("wooden_sword", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(4.0)));
+ public static final Item WOODEN_SHOVEL = register(new TieredItem("wooden_shovel", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(2.5)));
+ public static final Item WOODEN_PICKAXE = register(new TieredItem("wooden_pickaxe", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(2.0)));
+ public static final Item WOODEN_AXE = register(new TieredItem("wooden_axe", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(7.0)));
+ public static final Item WOODEN_HOE = register(new TieredItem("wooden_hoe", ToolTier.WOODEN, builder().stackSize(1).maxDamage(59).attackDamage(1.0)));
+ public static final Item STONE_SWORD = register(new TieredItem("stone_sword", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(5.0)));
+ public static final Item STONE_SHOVEL = register(new TieredItem("stone_shovel", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(3.5)));
+ public static final Item STONE_PICKAXE = register(new TieredItem("stone_pickaxe", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(3.0)));
+ public static final Item STONE_AXE = register(new TieredItem("stone_axe", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(9.0)));
+ public static final Item STONE_HOE = register(new TieredItem("stone_hoe", ToolTier.STONE, builder().stackSize(1).maxDamage(131).attackDamage(1.0)));
+ public static final Item GOLDEN_SWORD = register(new TieredItem("golden_sword", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(4.0)));
+ public static final Item GOLDEN_SHOVEL = register(new TieredItem("golden_shovel", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(2.5)));
+ public static final Item GOLDEN_PICKAXE = register(new TieredItem("golden_pickaxe", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(2.0)));
+ public static final Item GOLDEN_AXE = register(new TieredItem("golden_axe", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(7.0)));
+ public static final Item GOLDEN_HOE = register(new TieredItem("golden_hoe", ToolTier.GOLDEN, builder().stackSize(1).maxDamage(32).attackDamage(1.0)));
+ public static final Item IRON_SWORD = register(new TieredItem("iron_sword", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(6.0)));
+ public static final Item IRON_SHOVEL = register(new TieredItem("iron_shovel", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(4.5)));
+ public static final Item IRON_PICKAXE = register(new TieredItem("iron_pickaxe", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(4.0)));
+ public static final Item IRON_AXE = register(new TieredItem("iron_axe", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(9.0)));
+ public static final Item IRON_HOE = register(new TieredItem("iron_hoe", ToolTier.IRON, builder().stackSize(1).maxDamage(250).attackDamage(1.0)));
+ public static final Item DIAMOND_SWORD = register(new TieredItem("diamond_sword", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(7.0)));
+ public static final Item DIAMOND_SHOVEL = register(new TieredItem("diamond_shovel", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(5.5)));
+ public static final Item DIAMOND_PICKAXE = register(new TieredItem("diamond_pickaxe", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(5.0)));
+ public static final Item DIAMOND_AXE = register(new TieredItem("diamond_axe", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(9.0)));
+ public static final Item DIAMOND_HOE = register(new TieredItem("diamond_hoe", ToolTier.DIAMOND, builder().stackSize(1).maxDamage(1561).attackDamage(1.0)));
+ public static final Item NETHERITE_SWORD = register(new TieredItem("netherite_sword", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(8.0)));
+ public static final Item NETHERITE_SHOVEL = register(new TieredItem("netherite_shovel", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(6.5)));
+ public static final Item NETHERITE_PICKAXE = register(new TieredItem("netherite_pickaxe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(6.0)));
+ public static final Item NETHERITE_AXE = register(new TieredItem("netherite_axe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(10.0)));
+ public static final Item NETHERITE_HOE = register(new TieredItem("netherite_hoe", ToolTier.NETHERITE, builder().stackSize(1).maxDamage(2031).attackDamage(1.0)));
public static final Item STICK = register(new Item("stick", builder()));
- public static final Item BOWL = register(new Item("bowl", builder()));
public static final Item MUSHROOM_STEW = register(new Item("mushroom_stew", builder().stackSize(1)));
- public static final Item STRING = register(new BlockItem("string", builder()));
+ public static final Item STRING = register(new BlockItem("string", builder(), Blocks.TRIPWIRE));
public static final Item FEATHER = register(new Item("feather", builder()));
public static final Item GUNPOWDER = register(new Item("gunpowder", builder()));
- public static final Item WHEAT_SEEDS = register(new BlockItem("wheat_seeds", builder()));
+ public static final Item WHEAT_SEEDS = register(new BlockItem("wheat_seeds", builder(), Blocks.WHEAT));
public static final Item WHEAT = register(new Item("wheat", builder()));
public static final Item BREAD = register(new Item("bread", builder()));
public static final Item LEATHER_HELMET = register(new DyeableArmorItem("leather_helmet", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(55)));
public static final Item LEATHER_CHESTPLATE = register(new DyeableArmorItem("leather_chestplate", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(80)));
public static final Item LEATHER_LEGGINGS = register(new DyeableArmorItem("leather_leggings", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(75)));
public static final Item LEATHER_BOOTS = register(new DyeableArmorItem("leather_boots", ArmorMaterial.LEATHER, builder().stackSize(1).maxDamage(65)));
- public static final Item CHAINMAIL_HELMET = register(new ArmorItem("chainmail_helmet", ArmorMaterial.CHAIN, builder().stackSize(1).maxDamage(165)));
- public static final Item CHAINMAIL_CHESTPLATE = register(new ArmorItem("chainmail_chestplate", ArmorMaterial.CHAIN, builder().stackSize(1).maxDamage(240)));
- public static final Item CHAINMAIL_LEGGINGS = register(new ArmorItem("chainmail_leggings", ArmorMaterial.CHAIN, builder().stackSize(1).maxDamage(225)));
- public static final Item CHAINMAIL_BOOTS = register(new ArmorItem("chainmail_boots", ArmorMaterial.CHAIN, builder().stackSize(1).maxDamage(195)));
+ public static final Item CHAINMAIL_HELMET = register(new ArmorItem("chainmail_helmet", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(165)));
+ public static final Item CHAINMAIL_CHESTPLATE = register(new ArmorItem("chainmail_chestplate", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(240)));
+ public static final Item CHAINMAIL_LEGGINGS = register(new ArmorItem("chainmail_leggings", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(225)));
+ public static final Item CHAINMAIL_BOOTS = register(new ArmorItem("chainmail_boots", ArmorMaterial.CHAINMAIL, builder().stackSize(1).maxDamage(195)));
public static final Item IRON_HELMET = register(new ArmorItem("iron_helmet", ArmorMaterial.IRON, builder().stackSize(1).maxDamage(165)));
public static final Item IRON_CHESTPLATE = register(new ArmorItem("iron_chestplate", ArmorMaterial.IRON, builder().stackSize(1).maxDamage(240)));
public static final Item IRON_LEGGINGS = register(new ArmorItem("iron_leggings", ArmorMaterial.IRON, builder().stackSize(1).maxDamage(225)));
@@ -921,32 +923,32 @@ public final class Items {
public static final Item PAINTING = register(new Item("painting", builder()));
public static final Item GOLDEN_APPLE = register(new Item("golden_apple", builder()));
public static final Item ENCHANTED_GOLDEN_APPLE = register(new Item("enchanted_golden_apple", builder()));
- public static final Item OAK_SIGN = register(new BlockItem("oak_sign", builder().stackSize(16)));
- public static final Item SPRUCE_SIGN = register(new BlockItem("spruce_sign", builder().stackSize(16)));
- public static final Item BIRCH_SIGN = register(new BlockItem("birch_sign", builder().stackSize(16)));
- public static final Item JUNGLE_SIGN = register(new BlockItem("jungle_sign", builder().stackSize(16)));
- public static final Item ACACIA_SIGN = register(new BlockItem("acacia_sign", builder().stackSize(16)));
- public static final Item CHERRY_SIGN = register(new BlockItem("cherry_sign", builder().stackSize(16)));
- public static final Item DARK_OAK_SIGN = register(new BlockItem("dark_oak_sign", builder().stackSize(16)));
- public static final Item MANGROVE_SIGN = register(new BlockItem("mangrove_sign", builder().stackSize(16)));
- public static final Item BAMBOO_SIGN = register(new BlockItem("bamboo_sign", builder().stackSize(16)));
- public static final Item CRIMSON_SIGN = register(new BlockItem("crimson_sign", builder().stackSize(16)));
- public static final Item WARPED_SIGN = register(new BlockItem("warped_sign", builder().stackSize(16)));
- public static final Item OAK_HANGING_SIGN = register(new BlockItem("oak_hanging_sign", builder().stackSize(16)));
- public static final Item SPRUCE_HANGING_SIGN = register(new BlockItem("spruce_hanging_sign", builder().stackSize(16)));
- public static final Item BIRCH_HANGING_SIGN = register(new BlockItem("birch_hanging_sign", builder().stackSize(16)));
- public static final Item JUNGLE_HANGING_SIGN = register(new BlockItem("jungle_hanging_sign", builder().stackSize(16)));
- public static final Item ACACIA_HANGING_SIGN = register(new BlockItem("acacia_hanging_sign", builder().stackSize(16)));
- public static final Item CHERRY_HANGING_SIGN = register(new BlockItem("cherry_hanging_sign", builder().stackSize(16)));
- public static final Item DARK_OAK_HANGING_SIGN = register(new BlockItem("dark_oak_hanging_sign", builder().stackSize(16)));
- public static final Item MANGROVE_HANGING_SIGN = register(new BlockItem("mangrove_hanging_sign", builder().stackSize(16)));
- public static final Item BAMBOO_HANGING_SIGN = register(new BlockItem("bamboo_hanging_sign", builder().stackSize(16)));
- public static final Item CRIMSON_HANGING_SIGN = register(new BlockItem("crimson_hanging_sign", builder().stackSize(16)));
- public static final Item WARPED_HANGING_SIGN = register(new BlockItem("warped_hanging_sign", builder().stackSize(16)));
+ public static final Item OAK_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.OAK_SIGN, Blocks.OAK_WALL_SIGN));
+ public static final Item SPRUCE_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.SPRUCE_SIGN, Blocks.SPRUCE_WALL_SIGN));
+ public static final Item BIRCH_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BIRCH_SIGN, Blocks.BIRCH_WALL_SIGN));
+ public static final Item JUNGLE_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.JUNGLE_SIGN, Blocks.JUNGLE_WALL_SIGN));
+ public static final Item ACACIA_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.ACACIA_SIGN, Blocks.ACACIA_WALL_SIGN));
+ public static final Item CHERRY_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CHERRY_SIGN, Blocks.CHERRY_WALL_SIGN));
+ public static final Item DARK_OAK_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.DARK_OAK_SIGN, Blocks.DARK_OAK_WALL_SIGN));
+ public static final Item MANGROVE_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.MANGROVE_SIGN, Blocks.MANGROVE_WALL_SIGN));
+ public static final Item BAMBOO_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BAMBOO_SIGN, Blocks.BAMBOO_WALL_SIGN));
+ public static final Item CRIMSON_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CRIMSON_SIGN, Blocks.CRIMSON_WALL_SIGN));
+ public static final Item WARPED_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.WARPED_SIGN, Blocks.WARPED_WALL_SIGN));
+ public static final Item OAK_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.OAK_HANGING_SIGN, Blocks.OAK_WALL_HANGING_SIGN));
+ public static final Item SPRUCE_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.SPRUCE_HANGING_SIGN, Blocks.SPRUCE_WALL_HANGING_SIGN));
+ public static final Item BIRCH_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BIRCH_HANGING_SIGN, Blocks.BIRCH_WALL_HANGING_SIGN));
+ public static final Item JUNGLE_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.JUNGLE_HANGING_SIGN, Blocks.JUNGLE_WALL_HANGING_SIGN));
+ public static final Item ACACIA_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.ACACIA_HANGING_SIGN, Blocks.ACACIA_WALL_HANGING_SIGN));
+ public static final Item CHERRY_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CHERRY_HANGING_SIGN, Blocks.CHERRY_WALL_HANGING_SIGN));
+ public static final Item DARK_OAK_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.DARK_OAK_HANGING_SIGN, Blocks.DARK_OAK_WALL_HANGING_SIGN));
+ public static final Item MANGROVE_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.MANGROVE_HANGING_SIGN, Blocks.MANGROVE_WALL_HANGING_SIGN));
+ public static final Item BAMBOO_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.BAMBOO_HANGING_SIGN, Blocks.BAMBOO_WALL_HANGING_SIGN));
+ public static final Item CRIMSON_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.CRIMSON_HANGING_SIGN, Blocks.CRIMSON_WALL_HANGING_SIGN));
+ public static final Item WARPED_HANGING_SIGN = register(new BlockItem(builder().stackSize(16), Blocks.WARPED_HANGING_SIGN, Blocks.WARPED_WALL_HANGING_SIGN));
public static final Item BUCKET = register(new Item("bucket", builder().stackSize(16)));
public static final Item WATER_BUCKET = register(new Item("water_bucket", builder().stackSize(1)));
public static final Item LAVA_BUCKET = register(new Item("lava_bucket", builder().stackSize(1)));
- public static final Item POWDER_SNOW_BUCKET = register(new BlockItem("powder_snow_bucket", builder().stackSize(1)));
+ public static final Item POWDER_SNOW_BUCKET = register(new BlockItem("powder_snow_bucket", builder().stackSize(1), Blocks.POWDER_SNOW));
public static final Item SNOWBALL = register(new Item("snowball", builder().stackSize(16)));
public static final Item LEATHER = register(new Item("leather", builder()));
public static final Item MILK_BUCKET = register(new Item("milk_bucket", builder().stackSize(1)));
@@ -958,7 +960,7 @@ public final class Items {
public static final Item TADPOLE_BUCKET = register(new Item("tadpole_bucket", builder().stackSize(1)));
public static final Item BRICK = register(new Item("brick", builder()));
public static final Item CLAY_BALL = register(new Item("clay_ball", builder()));
- public static final Item DRIED_KELP_BLOCK = register(new BlockItem("dried_kelp_block", builder()));
+ public static final Item DRIED_KELP_BLOCK = register(new BlockItem(builder(), Blocks.DRIED_KELP_BLOCK));
public static final Item PAPER = register(new Item("paper", builder()));
public static final Item BOOK = register(new Item("book", builder()));
public static final Item SLIME_BALL = register(new Item("slime_ball", builder()));
@@ -978,7 +980,7 @@ public final class Items {
public static final Item COOKED_SALMON = register(new Item("cooked_salmon", builder()));
public static final Item INK_SAC = register(new Item("ink_sac", builder()));
public static final Item GLOW_INK_SAC = register(new Item("glow_ink_sac", builder()));
- public static final Item COCOA_BEANS = register(new BlockItem("cocoa_beans", builder()));
+ public static final Item COCOA_BEANS = register(new BlockItem("cocoa_beans", builder(), Blocks.COCOA));
public static final Item WHITE_DYE = register(new DyeItem("white_dye", 0, builder()));
public static final Item ORANGE_DYE = register(new DyeItem("orange_dye", 1, builder()));
public static final Item MAGENTA_DYE = register(new DyeItem("magenta_dye", 2, builder()));
@@ -998,31 +1000,31 @@ public final class Items {
public static final Item BONE_MEAL = register(new Item("bone_meal", builder()));
public static final Item BONE = register(new Item("bone", builder()));
public static final Item SUGAR = register(new Item("sugar", builder()));
- public static final Item CAKE = register(new BlockItem("cake", builder().stackSize(1)));
- public static final Item WHITE_BED = register(new BlockItem("white_bed", builder().stackSize(1)));
- public static final Item ORANGE_BED = register(new BlockItem("orange_bed", builder().stackSize(1)));
- public static final Item MAGENTA_BED = register(new BlockItem("magenta_bed", builder().stackSize(1)));
- public static final Item LIGHT_BLUE_BED = register(new BlockItem("light_blue_bed", builder().stackSize(1)));
- public static final Item YELLOW_BED = register(new BlockItem("yellow_bed", builder().stackSize(1)));
- public static final Item LIME_BED = register(new BlockItem("lime_bed", builder().stackSize(1)));
- public static final Item PINK_BED = register(new BlockItem("pink_bed", builder().stackSize(1)));
- public static final Item GRAY_BED = register(new BlockItem("gray_bed", builder().stackSize(1)));
- public static final Item LIGHT_GRAY_BED = register(new BlockItem("light_gray_bed", builder().stackSize(1)));
- public static final Item CYAN_BED = register(new BlockItem("cyan_bed", builder().stackSize(1)));
- public static final Item PURPLE_BED = register(new BlockItem("purple_bed", builder().stackSize(1)));
- public static final Item BLUE_BED = register(new BlockItem("blue_bed", builder().stackSize(1)));
- public static final Item BROWN_BED = register(new BlockItem("brown_bed", builder().stackSize(1)));
- public static final Item GREEN_BED = register(new BlockItem("green_bed", builder().stackSize(1)));
- public static final Item RED_BED = register(new BlockItem("red_bed", builder().stackSize(1)));
- public static final Item BLACK_BED = register(new BlockItem("black_bed", builder().stackSize(1)));
+ public static final Item CAKE = register(new BlockItem(builder().stackSize(1), Blocks.CAKE));
+ public static final Item WHITE_BED = register(new BlockItem(builder().stackSize(1), Blocks.WHITE_BED));
+ public static final Item ORANGE_BED = register(new BlockItem(builder().stackSize(1), Blocks.ORANGE_BED));
+ public static final Item MAGENTA_BED = register(new BlockItem(builder().stackSize(1), Blocks.MAGENTA_BED));
+ public static final Item LIGHT_BLUE_BED = register(new BlockItem(builder().stackSize(1), Blocks.LIGHT_BLUE_BED));
+ public static final Item YELLOW_BED = register(new BlockItem(builder().stackSize(1), Blocks.YELLOW_BED));
+ public static final Item LIME_BED = register(new BlockItem(builder().stackSize(1), Blocks.LIME_BED));
+ public static final Item PINK_BED = register(new BlockItem(builder().stackSize(1), Blocks.PINK_BED));
+ public static final Item GRAY_BED = register(new BlockItem(builder().stackSize(1), Blocks.GRAY_BED));
+ public static final Item LIGHT_GRAY_BED = register(new BlockItem(builder().stackSize(1), Blocks.LIGHT_GRAY_BED));
+ public static final Item CYAN_BED = register(new BlockItem(builder().stackSize(1), Blocks.CYAN_BED));
+ public static final Item PURPLE_BED = register(new BlockItem(builder().stackSize(1), Blocks.PURPLE_BED));
+ public static final Item BLUE_BED = register(new BlockItem(builder().stackSize(1), Blocks.BLUE_BED));
+ public static final Item BROWN_BED = register(new BlockItem(builder().stackSize(1), Blocks.BROWN_BED));
+ public static final Item GREEN_BED = register(new BlockItem(builder().stackSize(1), Blocks.GREEN_BED));
+ public static final Item RED_BED = register(new BlockItem(builder().stackSize(1), Blocks.RED_BED));
+ public static final Item BLACK_BED = register(new BlockItem(builder().stackSize(1), Blocks.BLACK_BED));
public static final Item COOKIE = register(new Item("cookie", builder()));
- public static final Item CRAFTER = register(new BlockItem("crafter", builder()));
+ public static final Item CRAFTER = register(new BlockItem(builder(), Blocks.CRAFTER));
public static final Item FILLED_MAP = register(new FilledMapItem("filled_map", builder()));
public static final Item SHEARS = register(new Item("shears", builder().stackSize(1).maxDamage(238)));
public static final Item MELON_SLICE = register(new Item("melon_slice", builder()));
public static final Item DRIED_KELP = register(new Item("dried_kelp", builder()));
- public static final Item PUMPKIN_SEEDS = register(new BlockItem("pumpkin_seeds", builder()));
- public static final Item MELON_SEEDS = register(new BlockItem("melon_seeds", builder()));
+ public static final Item PUMPKIN_SEEDS = register(new BlockItem("pumpkin_seeds", builder(), Blocks.PUMPKIN_STEM));
+ public static final Item MELON_SEEDS = register(new BlockItem("melon_seeds", builder(), Blocks.MELON_STEM));
public static final Item BEEF = register(new Item("beef", builder()));
public static final Item COOKED_BEEF = register(new Item("cooked_beef", builder()));
public static final Item CHICKEN = register(new Item("chicken", builder()));
@@ -1032,22 +1034,24 @@ public final class Items {
public static final Item BLAZE_ROD = register(new Item("blaze_rod", builder()));
public static final Item GHAST_TEAR = register(new Item("ghast_tear", builder()));
public static final Item GOLD_NUGGET = register(new Item("gold_nugget", builder()));
- public static final Item NETHER_WART = register(new BlockItem("nether_wart", builder()));
+ public static final Item NETHER_WART = register(new BlockItem(builder(), Blocks.NETHER_WART));
public static final Item POTION = register(new PotionItem("potion", builder().stackSize(1)));
public static final Item GLASS_BOTTLE = register(new Item("glass_bottle", builder()));
public static final Item SPIDER_EYE = register(new Item("spider_eye", builder()));
public static final Item FERMENTED_SPIDER_EYE = register(new Item("fermented_spider_eye", builder()));
public static final Item BLAZE_POWDER = register(new Item("blaze_powder", builder()));
public static final Item MAGMA_CREAM = register(new Item("magma_cream", builder()));
- public static final Item BREWING_STAND = register(new BlockItem("brewing_stand", builder()));
- public static final Item CAULDRON = register(new BlockItem("cauldron", builder()));
+ public static final Item BREWING_STAND = register(new BlockItem(builder(), Blocks.BREWING_STAND));
+ public static final Item CAULDRON = register(new BlockItem(builder(), Blocks.CAULDRON, Blocks.WATER_CAULDRON, Blocks.LAVA_CAULDRON, Blocks.POWDER_SNOW_CAULDRON));
public static final Item ENDER_EYE = register(new Item("ender_eye", builder()));
public static final Item GLISTERING_MELON_SLICE = register(new Item("glistering_melon_slice", builder()));
+ public static final Item ARMADILLO_SPAWN_EGG = register(new SpawnEggItem("armadillo_spawn_egg", builder()));
public static final Item ALLAY_SPAWN_EGG = register(new SpawnEggItem("allay_spawn_egg", builder()));
public static final Item AXOLOTL_SPAWN_EGG = register(new SpawnEggItem("axolotl_spawn_egg", builder()));
public static final Item BAT_SPAWN_EGG = register(new SpawnEggItem("bat_spawn_egg", builder()));
public static final Item BEE_SPAWN_EGG = register(new SpawnEggItem("bee_spawn_egg", builder()));
public static final Item BLAZE_SPAWN_EGG = register(new SpawnEggItem("blaze_spawn_egg", builder()));
+ public static final Item BOGGED_SPAWN_EGG = register(new SpawnEggItem("bogged_spawn_egg", builder()));
public static final Item BREEZE_SPAWN_EGG = register(new SpawnEggItem("breeze_spawn_egg", builder()));
public static final Item CAT_SPAWN_EGG = register(new SpawnEggItem("cat_spawn_egg", builder()));
public static final Item CAMEL_SPAWN_EGG = register(new SpawnEggItem("camel_spawn_egg", builder()));
@@ -1123,24 +1127,26 @@ public final class Items {
public static final Item ZOMBIFIED_PIGLIN_SPAWN_EGG = register(new SpawnEggItem("zombified_piglin_spawn_egg", builder()));
public static final Item EXPERIENCE_BOTTLE = register(new Item("experience_bottle", builder()));
public static final Item FIRE_CHARGE = register(new Item("fire_charge", builder()));
+ public static final Item WIND_CHARGE = register(new Item("wind_charge", builder()));
public static final Item WRITABLE_BOOK = register(new WritableBookItem("writable_book", builder().stackSize(1)));
public static final Item WRITTEN_BOOK = register(new WrittenBookItem("written_book", builder().stackSize(16)));
+ public static final Item MACE = register(new MaceItem("mace", builder().stackSize(1).maxDamage(500)));
public static final Item ITEM_FRAME = register(new Item("item_frame", builder()));
public static final Item GLOW_ITEM_FRAME = register(new Item("glow_item_frame", builder()));
- public static final Item FLOWER_POT = register(new BlockItem("flower_pot", builder()));
- public static final Item CARROT = register(new BlockItem("carrot", builder()));
- public static final Item POTATO = register(new BlockItem("potato", builder()));
+ public static final Item FLOWER_POT = register(new BlockItem(builder(), Blocks.FLOWER_POT));
+ public static final Item CARROT = register(new BlockItem("carrot", builder(), Blocks.CARROTS));
+ public static final Item POTATO = register(new BlockItem("potato", builder(), Blocks.POTATOES));
public static final Item BAKED_POTATO = register(new Item("baked_potato", builder()));
public static final Item POISONOUS_POTATO = register(new Item("poisonous_potato", builder()));
public static final Item MAP = register(new MapItem("map", builder()));
public static final Item GOLDEN_CARROT = register(new Item("golden_carrot", builder()));
- public static final Item SKELETON_SKULL = register(new BlockItem("skeleton_skull", builder()));
- public static final Item WITHER_SKELETON_SKULL = register(new BlockItem("wither_skeleton_skull", builder()));
- public static final Item PLAYER_HEAD = register(new PlayerHeadItem("player_head", builder()));
- public static final Item ZOMBIE_HEAD = register(new BlockItem("zombie_head", builder()));
- public static final Item CREEPER_HEAD = register(new BlockItem("creeper_head", builder()));
- public static final Item DRAGON_HEAD = register(new BlockItem("dragon_head", builder()));
- public static final Item PIGLIN_HEAD = register(new BlockItem("piglin_head", builder()));
+ public static final Item SKELETON_SKULL = register(new BlockItem(builder(), Blocks.SKELETON_SKULL, Blocks.SKELETON_WALL_SKULL));
+ public static final Item WITHER_SKELETON_SKULL = register(new BlockItem(builder(), Blocks.WITHER_SKELETON_SKULL, Blocks.WITHER_SKELETON_WALL_SKULL));
+ public static final Item PLAYER_HEAD = register(new PlayerHeadItem(builder(), Blocks.PLAYER_HEAD, Blocks.PLAYER_WALL_HEAD));
+ public static final Item ZOMBIE_HEAD = register(new BlockItem(builder(), Blocks.ZOMBIE_HEAD, Blocks.ZOMBIE_WALL_HEAD));
+ public static final Item CREEPER_HEAD = register(new BlockItem(builder(), Blocks.CREEPER_HEAD, Blocks.CREEPER_WALL_HEAD));
+ public static final Item DRAGON_HEAD = register(new BlockItem(builder(), Blocks.DRAGON_HEAD, Blocks.DRAGON_WALL_HEAD));
+ public static final Item PIGLIN_HEAD = register(new BlockItem(builder(), Blocks.PIGLIN_HEAD, Blocks.PIGLIN_WALL_HEAD));
public static final Item NETHER_STAR = register(new Item("nether_star", builder()));
public static final Item PUMPKIN_PIE = register(new Item("pumpkin_pie", builder()));
public static final Item FIREWORK_ROCKET = register(new FireworkRocketItem("firework_rocket", builder()));
@@ -1155,38 +1161,38 @@ public final class Items {
public static final Item RABBIT_FOOT = register(new Item("rabbit_foot", builder()));
public static final Item RABBIT_HIDE = register(new Item("rabbit_hide", builder()));
public static final Item ARMOR_STAND = register(new Item("armor_stand", builder().stackSize(16)));
- public static final Item IRON_HORSE_ARMOR = register(new Item("iron_horse_armor", builder().stackSize(1)));
- public static final Item GOLDEN_HORSE_ARMOR = register(new Item("golden_horse_armor", builder().stackSize(1)));
- public static final Item DIAMOND_HORSE_ARMOR = register(new Item("diamond_horse_armor", builder().stackSize(1)));
- public static final Item LEATHER_HORSE_ARMOR = register(new DyeableHorseArmorItem("leather_horse_armor", builder().stackSize(1)));
+ public static final Item IRON_HORSE_ARMOR = register(new ArmorItem("iron_horse_armor", ArmorMaterial.IRON, builder().stackSize(1)));
+ public static final Item GOLDEN_HORSE_ARMOR = register(new ArmorItem("golden_horse_armor", ArmorMaterial.GOLD, builder().stackSize(1)));
+ public static final Item DIAMOND_HORSE_ARMOR = register(new ArmorItem("diamond_horse_armor", ArmorMaterial.DIAMOND, builder().stackSize(1)));
+ public static final Item LEATHER_HORSE_ARMOR = register(new DyeableArmorItem("leather_horse_armor", ArmorMaterial.LEATHER, builder().stackSize(1)));
public static final Item LEAD = register(new Item("lead", builder()));
public static final Item NAME_TAG = register(new Item("name_tag", builder()));
public static final Item COMMAND_BLOCK_MINECART = register(new Item("command_block_minecart", builder().stackSize(1)));
public static final Item MUTTON = register(new Item("mutton", builder()));
public static final Item COOKED_MUTTON = register(new Item("cooked_mutton", builder()));
- public static final Item WHITE_BANNER = register(new BannerItem("white_banner", builder().stackSize(16)));
- public static final Item ORANGE_BANNER = register(new BannerItem("orange_banner", builder().stackSize(16)));
- public static final Item MAGENTA_BANNER = register(new BannerItem("magenta_banner", builder().stackSize(16)));
- public static final Item LIGHT_BLUE_BANNER = register(new BannerItem("light_blue_banner", builder().stackSize(16)));
- public static final Item YELLOW_BANNER = register(new BannerItem("yellow_banner", builder().stackSize(16)));
- public static final Item LIME_BANNER = register(new BannerItem("lime_banner", builder().stackSize(16)));
- public static final Item PINK_BANNER = register(new BannerItem("pink_banner", builder().stackSize(16)));
- public static final Item GRAY_BANNER = register(new BannerItem("gray_banner", builder().stackSize(16)));
- public static final Item LIGHT_GRAY_BANNER = register(new BannerItem("light_gray_banner", builder().stackSize(16)));
- public static final Item CYAN_BANNER = register(new BannerItem("cyan_banner", builder().stackSize(16)));
- public static final Item PURPLE_BANNER = register(new BannerItem("purple_banner", builder().stackSize(16)));
- public static final Item BLUE_BANNER = register(new BannerItem("blue_banner", builder().stackSize(16)));
- public static final Item BROWN_BANNER = register(new BannerItem("brown_banner", builder().stackSize(16)));
- public static final Item GREEN_BANNER = register(new BannerItem("green_banner", builder().stackSize(16)));
- public static final Item RED_BANNER = register(new BannerItem("red_banner", builder().stackSize(16)));
- public static final Item BLACK_BANNER = register(new BannerItem("black_banner", builder().stackSize(16)));
+ public static final Item WHITE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.WHITE_BANNER, Blocks.WHITE_WALL_BANNER));
+ public static final Item ORANGE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.ORANGE_BANNER, Blocks.ORANGE_WALL_BANNER));
+ public static final Item MAGENTA_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.MAGENTA_BANNER, Blocks.MAGENTA_WALL_BANNER));
+ public static final Item LIGHT_BLUE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.LIGHT_BLUE_BANNER, Blocks.LIGHT_BLUE_WALL_BANNER));
+ public static final Item YELLOW_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.YELLOW_BANNER, Blocks.YELLOW_WALL_BANNER));
+ public static final Item LIME_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.LIME_BANNER, Blocks.LIME_WALL_BANNER));
+ public static final Item PINK_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.PINK_BANNER, Blocks.PINK_WALL_BANNER));
+ public static final Item GRAY_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.GRAY_BANNER, Blocks.GRAY_WALL_BANNER));
+ public static final Item LIGHT_GRAY_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.LIGHT_GRAY_BANNER, Blocks.LIGHT_GRAY_WALL_BANNER));
+ public static final Item CYAN_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.CYAN_BANNER, Blocks.CYAN_WALL_BANNER));
+ public static final Item PURPLE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.PURPLE_BANNER, Blocks.PURPLE_WALL_BANNER));
+ public static final Item BLUE_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.BLUE_BANNER, Blocks.BLUE_WALL_BANNER));
+ public static final Item BROWN_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.BROWN_BANNER, Blocks.BROWN_WALL_BANNER));
+ public static final Item GREEN_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.GREEN_BANNER, Blocks.GREEN_WALL_BANNER));
+ public static final Item RED_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.RED_BANNER, Blocks.RED_WALL_BANNER));
+ public static final Item BLACK_BANNER = register(new BannerItem(builder().stackSize(16), Blocks.BLACK_BANNER, Blocks.BLACK_WALL_BANNER));
public static final Item END_CRYSTAL = register(new Item("end_crystal", builder()));
public static final Item CHORUS_FRUIT = register(new Item("chorus_fruit", builder()));
public static final Item POPPED_CHORUS_FRUIT = register(new Item("popped_chorus_fruit", builder()));
- public static final Item TORCHFLOWER_SEEDS = register(new BlockItem("torchflower_seeds", builder()));
- public static final Item PITCHER_POD = register(new BlockItem("pitcher_pod", builder()));
+ public static final Item TORCHFLOWER_SEEDS = register(new BlockItem("torchflower_seeds", builder(), Blocks.TORCHFLOWER_CROP));
+ public static final Item PITCHER_POD = register(new BlockItem("pitcher_pod", builder(), Blocks.PITCHER_CROP));
public static final Item BEETROOT = register(new Item("beetroot", builder()));
- public static final Item BEETROOT_SEEDS = register(new BlockItem("beetroot_seeds", builder()));
+ public static final Item BEETROOT_SEEDS = register(new BlockItem("beetroot_seeds", builder(), Blocks.BEETROOTS));
public static final Item BEETROOT_SOUP = register(new Item("beetroot_soup", builder().stackSize(1)));
public static final Item DRAGON_BREATH = register(new Item("dragon_breath", builder()));
public static final Item SPLASH_POTION = register(new PotionItem("splash_potion", builder().stackSize(1)));
@@ -1203,6 +1209,8 @@ public final class Items {
public static final Item MUSIC_DISC_CAT = register(new Item("music_disc_cat", builder().stackSize(1)));
public static final Item MUSIC_DISC_BLOCKS = register(new Item("music_disc_blocks", builder().stackSize(1)));
public static final Item MUSIC_DISC_CHIRP = register(new Item("music_disc_chirp", builder().stackSize(1)));
+ public static final Item MUSIC_DISC_CREATOR = register(new Item("music_disc_creator", builder().stackSize(1)));
+ public static final Item MUSIC_DISC_CREATOR_MUSIC_BOX = register(new Item("music_disc_creator_music_box", builder().stackSize(1)));
public static final Item MUSIC_DISC_FAR = register(new Item("music_disc_far", builder().stackSize(1)));
public static final Item MUSIC_DISC_MALL = register(new Item("music_disc_mall", builder().stackSize(1)));
public static final Item MUSIC_DISC_MELLOHI = register(new Item("music_disc_mellohi", builder().stackSize(1)));
@@ -1215,84 +1223,87 @@ public final class Items {
public static final Item MUSIC_DISC_RELIC = register(new Item("music_disc_relic", builder().stackSize(1)));
public static final Item MUSIC_DISC_5 = register(new Item("music_disc_5", builder().stackSize(1)));
public static final Item MUSIC_DISC_PIGSTEP = register(new Item("music_disc_pigstep", builder().stackSize(1)));
+ public static final Item MUSIC_DISC_PRECIPICE = register(new Item("music_disc_precipice", builder().stackSize(1)));
public static final Item DISC_FRAGMENT_5 = register(new Item("disc_fragment_5", builder()));
- public static final Item TRIDENT = register(new Item("trident", builder().stackSize(1).maxDamage(250)));
+ public static final Item TRIDENT = register(new Item("trident", builder().stackSize(1).maxDamage(250).attackDamage(9.0)));
public static final Item PHANTOM_MEMBRANE = register(new Item("phantom_membrane", builder()));
public static final Item NAUTILUS_SHELL = register(new Item("nautilus_shell", builder()));
public static final Item HEART_OF_THE_SEA = register(new Item("heart_of_the_sea", builder()));
public static final Item CROSSBOW = register(new CrossbowItem("crossbow", builder().stackSize(1).maxDamage(465)));
public static final Item SUSPICIOUS_STEW = register(new Item("suspicious_stew", builder().stackSize(1)));
- public static final Item LOOM = register(new BlockItem("loom", builder()));
+ public static final Item LOOM = register(new BlockItem(builder(), Blocks.LOOM));
public static final Item FLOWER_BANNER_PATTERN = register(new Item("flower_banner_pattern", builder().stackSize(1)));
public static final Item CREEPER_BANNER_PATTERN = register(new Item("creeper_banner_pattern", builder().stackSize(1)));
public static final Item SKULL_BANNER_PATTERN = register(new Item("skull_banner_pattern", builder().stackSize(1)));
public static final Item MOJANG_BANNER_PATTERN = register(new Item("mojang_banner_pattern", builder().stackSize(1)));
public static final Item GLOBE_BANNER_PATTERN = register(new Item("globe_banner_pattern", builder().stackSize(1)));
public static final Item PIGLIN_BANNER_PATTERN = register(new Item("piglin_banner_pattern", builder().stackSize(1)));
+ public static final Item FLOW_BANNER_PATTERN = register(new Item("flow_banner_pattern", builder().stackSize(1)));
+ public static final Item GUSTER_BANNER_PATTERN = register(new Item("guster_banner_pattern", builder().stackSize(1)));
public static final Item GOAT_HORN = register(new GoatHornItem("goat_horn", builder().stackSize(1)));
- public static final Item COMPOSTER = register(new BlockItem("composter", builder()));
- public static final Item BARREL = register(new ChestItem("barrel", builder()));
- public static final Item SMOKER = register(new BlockItem("smoker", builder()));
- public static final Item BLAST_FURNACE = register(new BlockItem("blast_furnace", builder()));
- public static final Item CARTOGRAPHY_TABLE = register(new BlockItem("cartography_table", builder()));
- public static final Item FLETCHING_TABLE = register(new BlockItem("fletching_table", builder()));
- public static final Item GRINDSTONE = register(new BlockItem("grindstone", builder()));
- public static final Item SMITHING_TABLE = register(new BlockItem("smithing_table", builder()));
- public static final Item STONECUTTER = register(new BlockItem("stonecutter", builder()));
- public static final Item BELL = register(new BlockItem("bell", builder()));
- public static final Item LANTERN = register(new BlockItem("lantern", builder()));
- public static final Item SOUL_LANTERN = register(new BlockItem("soul_lantern", builder()));
- public static final Item SWEET_BERRIES = register(new BlockItem("sweet_berries", builder()));
- public static final Item GLOW_BERRIES = register(new BlockItem("glow_berries", builder()));
- public static final Item CAMPFIRE = register(new BlockItem("campfire", builder()));
- public static final Item SOUL_CAMPFIRE = register(new BlockItem("soul_campfire", builder()));
- public static final Item SHROOMLIGHT = register(new BlockItem("shroomlight", builder()));
+ public static final Item COMPOSTER = register(new BlockItem(builder(), Blocks.COMPOSTER));
+ public static final Item BARREL = register(new BlockItem(builder(), Blocks.BARREL));
+ public static final Item SMOKER = register(new BlockItem(builder(), Blocks.SMOKER));
+ public static final Item BLAST_FURNACE = register(new BlockItem(builder(), Blocks.BLAST_FURNACE));
+ public static final Item CARTOGRAPHY_TABLE = register(new BlockItem(builder(), Blocks.CARTOGRAPHY_TABLE));
+ public static final Item FLETCHING_TABLE = register(new BlockItem(builder(), Blocks.FLETCHING_TABLE));
+ public static final Item GRINDSTONE = register(new BlockItem(builder(), Blocks.GRINDSTONE));
+ public static final Item SMITHING_TABLE = register(new BlockItem(builder(), Blocks.SMITHING_TABLE));
+ public static final Item STONECUTTER = register(new BlockItem(builder(), Blocks.STONECUTTER));
+ public static final Item BELL = register(new BlockItem(builder(), Blocks.BELL));
+ public static final Item LANTERN = register(new BlockItem(builder(), Blocks.LANTERN));
+ public static final Item SOUL_LANTERN = register(new BlockItem(builder(), Blocks.SOUL_LANTERN));
+ public static final Item SWEET_BERRIES = register(new BlockItem("sweet_berries", builder(), Blocks.SWEET_BERRY_BUSH));
+ public static final Item GLOW_BERRIES = register(new BlockItem("glow_berries", builder(), Blocks.CAVE_VINES));
+ public static final Item CAMPFIRE = register(new BlockItem(builder(), Blocks.CAMPFIRE));
+ public static final Item SOUL_CAMPFIRE = register(new BlockItem(builder(), Blocks.SOUL_CAMPFIRE));
+ public static final Item SHROOMLIGHT = register(new BlockItem(builder(), Blocks.SHROOMLIGHT));
public static final Item HONEYCOMB = register(new Item("honeycomb", builder()));
- public static final Item BEE_NEST = register(new BlockItem("bee_nest", builder()));
- public static final Item BEEHIVE = register(new BlockItem("beehive", builder()));
+ public static final Item BEE_NEST = register(new BlockItem(builder(), Blocks.BEE_NEST));
+ public static final Item BEEHIVE = register(new BlockItem(builder(), Blocks.BEEHIVE));
public static final Item HONEY_BOTTLE = register(new Item("honey_bottle", builder().stackSize(16)));
- public static final Item HONEYCOMB_BLOCK = register(new BlockItem("honeycomb_block", builder()));
- public static final Item LODESTONE = register(new BlockItem("lodestone", builder()));
- public static final Item CRYING_OBSIDIAN = register(new BlockItem("crying_obsidian", builder()));
- public static final Item BLACKSTONE = register(new BlockItem("blackstone", builder()));
- public static final Item BLACKSTONE_SLAB = register(new BlockItem("blackstone_slab", builder()));
- public static final Item BLACKSTONE_STAIRS = register(new BlockItem("blackstone_stairs", builder()));
- public static final Item GILDED_BLACKSTONE = register(new BlockItem("gilded_blackstone", builder()));
- public static final Item POLISHED_BLACKSTONE = register(new BlockItem("polished_blackstone", builder()));
- public static final Item POLISHED_BLACKSTONE_SLAB = register(new BlockItem("polished_blackstone_slab", builder()));
- public static final Item POLISHED_BLACKSTONE_STAIRS = register(new BlockItem("polished_blackstone_stairs", builder()));
- public static final Item CHISELED_POLISHED_BLACKSTONE = register(new BlockItem("chiseled_polished_blackstone", builder()));
- public static final Item POLISHED_BLACKSTONE_BRICKS = register(new BlockItem("polished_blackstone_bricks", builder()));
- public static final Item POLISHED_BLACKSTONE_BRICK_SLAB = register(new BlockItem("polished_blackstone_brick_slab", builder()));
- public static final Item POLISHED_BLACKSTONE_BRICK_STAIRS = register(new BlockItem("polished_blackstone_brick_stairs", builder()));
- public static final Item CRACKED_POLISHED_BLACKSTONE_BRICKS = register(new BlockItem("cracked_polished_blackstone_bricks", builder()));
- public static final Item RESPAWN_ANCHOR = register(new BlockItem("respawn_anchor", builder()));
- public static final Item CANDLE = register(new BlockItem("candle", builder()));
- public static final Item WHITE_CANDLE = register(new BlockItem("white_candle", builder()));
- public static final Item ORANGE_CANDLE = register(new BlockItem("orange_candle", builder()));
- public static final Item MAGENTA_CANDLE = register(new BlockItem("magenta_candle", builder()));
- public static final Item LIGHT_BLUE_CANDLE = register(new BlockItem("light_blue_candle", builder()));
- public static final Item YELLOW_CANDLE = register(new BlockItem("yellow_candle", builder()));
- public static final Item LIME_CANDLE = register(new BlockItem("lime_candle", builder()));
- public static final Item PINK_CANDLE = register(new BlockItem("pink_candle", builder()));
- public static final Item GRAY_CANDLE = register(new BlockItem("gray_candle", builder()));
- public static final Item LIGHT_GRAY_CANDLE = register(new BlockItem("light_gray_candle", builder()));
- public static final Item CYAN_CANDLE = register(new BlockItem("cyan_candle", builder()));
- public static final Item PURPLE_CANDLE = register(new BlockItem("purple_candle", builder()));
- public static final Item BLUE_CANDLE = register(new BlockItem("blue_candle", builder()));
- public static final Item BROWN_CANDLE = register(new BlockItem("brown_candle", builder()));
- public static final Item GREEN_CANDLE = register(new BlockItem("green_candle", builder()));
- public static final Item RED_CANDLE = register(new BlockItem("red_candle", builder()));
- public static final Item BLACK_CANDLE = register(new BlockItem("black_candle", builder()));
- public static final Item SMALL_AMETHYST_BUD = register(new BlockItem("small_amethyst_bud", builder()));
- public static final Item MEDIUM_AMETHYST_BUD = register(new BlockItem("medium_amethyst_bud", builder()));
- public static final Item LARGE_AMETHYST_BUD = register(new BlockItem("large_amethyst_bud", builder()));
- public static final Item AMETHYST_CLUSTER = register(new BlockItem("amethyst_cluster", builder()));
- public static final Item POINTED_DRIPSTONE = register(new BlockItem("pointed_dripstone", builder()));
- public static final Item OCHRE_FROGLIGHT = register(new BlockItem("ochre_froglight", builder()));
- public static final Item VERDANT_FROGLIGHT = register(new BlockItem("verdant_froglight", builder()));
- public static final Item PEARLESCENT_FROGLIGHT = register(new BlockItem("pearlescent_froglight", builder()));
- public static final Item FROGSPAWN = register(new BlockItem("frogspawn", builder()));
+ public static final Item HONEYCOMB_BLOCK = register(new BlockItem(builder(), Blocks.HONEYCOMB_BLOCK));
+ public static final Item LODESTONE = register(new BlockItem(builder(), Blocks.LODESTONE));
+ public static final Item CRYING_OBSIDIAN = register(new BlockItem(builder(), Blocks.CRYING_OBSIDIAN));
+ public static final Item BLACKSTONE = register(new BlockItem(builder(), Blocks.BLACKSTONE));
+ public static final Item BLACKSTONE_SLAB = register(new BlockItem(builder(), Blocks.BLACKSTONE_SLAB));
+ public static final Item BLACKSTONE_STAIRS = register(new BlockItem(builder(), Blocks.BLACKSTONE_STAIRS));
+ public static final Item GILDED_BLACKSTONE = register(new BlockItem(builder(), Blocks.GILDED_BLACKSTONE));
+ public static final Item POLISHED_BLACKSTONE = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE));
+ public static final Item POLISHED_BLACKSTONE_SLAB = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_SLAB));
+ public static final Item POLISHED_BLACKSTONE_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_STAIRS));
+ public static final Item CHISELED_POLISHED_BLACKSTONE = register(new BlockItem(builder(), Blocks.CHISELED_POLISHED_BLACKSTONE));
+ public static final Item POLISHED_BLACKSTONE_BRICKS = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_BRICKS));
+ public static final Item POLISHED_BLACKSTONE_BRICK_SLAB = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_BRICK_SLAB));
+ public static final Item POLISHED_BLACKSTONE_BRICK_STAIRS = register(new BlockItem(builder(), Blocks.POLISHED_BLACKSTONE_BRICK_STAIRS));
+ public static final Item CRACKED_POLISHED_BLACKSTONE_BRICKS = register(new BlockItem(builder(), Blocks.CRACKED_POLISHED_BLACKSTONE_BRICKS));
+ public static final Item RESPAWN_ANCHOR = register(new BlockItem(builder(), Blocks.RESPAWN_ANCHOR));
+ public static final Item CANDLE = register(new BlockItem(builder(), Blocks.CANDLE));
+ public static final Item WHITE_CANDLE = register(new BlockItem(builder(), Blocks.WHITE_CANDLE));
+ public static final Item ORANGE_CANDLE = register(new BlockItem(builder(), Blocks.ORANGE_CANDLE));
+ public static final Item MAGENTA_CANDLE = register(new BlockItem(builder(), Blocks.MAGENTA_CANDLE));
+ public static final Item LIGHT_BLUE_CANDLE = register(new BlockItem(builder(), Blocks.LIGHT_BLUE_CANDLE));
+ public static final Item YELLOW_CANDLE = register(new BlockItem(builder(), Blocks.YELLOW_CANDLE));
+ public static final Item LIME_CANDLE = register(new BlockItem(builder(), Blocks.LIME_CANDLE));
+ public static final Item PINK_CANDLE = register(new BlockItem(builder(), Blocks.PINK_CANDLE));
+ public static final Item GRAY_CANDLE = register(new BlockItem(builder(), Blocks.GRAY_CANDLE));
+ public static final Item LIGHT_GRAY_CANDLE = register(new BlockItem(builder(), Blocks.LIGHT_GRAY_CANDLE));
+ public static final Item CYAN_CANDLE = register(new BlockItem(builder(), Blocks.CYAN_CANDLE));
+ public static final Item PURPLE_CANDLE = register(new BlockItem(builder(), Blocks.PURPLE_CANDLE));
+ public static final Item BLUE_CANDLE = register(new BlockItem(builder(), Blocks.BLUE_CANDLE));
+ public static final Item BROWN_CANDLE = register(new BlockItem(builder(), Blocks.BROWN_CANDLE));
+ public static final Item GREEN_CANDLE = register(new BlockItem(builder(), Blocks.GREEN_CANDLE));
+ public static final Item RED_CANDLE = register(new BlockItem(builder(), Blocks.RED_CANDLE));
+ public static final Item BLACK_CANDLE = register(new BlockItem(builder(), Blocks.BLACK_CANDLE));
+ public static final Item SMALL_AMETHYST_BUD = register(new BlockItem(builder(), Blocks.SMALL_AMETHYST_BUD));
+ public static final Item MEDIUM_AMETHYST_BUD = register(new BlockItem(builder(), Blocks.MEDIUM_AMETHYST_BUD));
+ public static final Item LARGE_AMETHYST_BUD = register(new BlockItem(builder(), Blocks.LARGE_AMETHYST_BUD));
+ public static final Item AMETHYST_CLUSTER = register(new BlockItem(builder(), Blocks.AMETHYST_CLUSTER));
+ public static final Item POINTED_DRIPSTONE = register(new BlockItem(builder(), Blocks.POINTED_DRIPSTONE));
+ public static final Item OCHRE_FROGLIGHT = register(new BlockItem(builder(), Blocks.OCHRE_FROGLIGHT));
+ public static final Item VERDANT_FROGLIGHT = register(new BlockItem(builder(), Blocks.VERDANT_FROGLIGHT));
+ public static final Item PEARLESCENT_FROGLIGHT = register(new BlockItem(builder(), Blocks.PEARLESCENT_FROGLIGHT));
+ public static final Item FROGSPAWN = register(new BlockItem(builder(), Blocks.FROGSPAWN));
public static final Item ECHO_SHARD = register(new Item("echo_shard", builder()));
public static final Item BRUSH = register(new Item("brush", builder().stackSize(1).maxDamage(64)));
public static final Item NETHERITE_UPGRADE_SMITHING_TEMPLATE = register(new Item("netherite_upgrade_smithing_template", builder()));
@@ -1312,6 +1323,8 @@ public final class Items {
public static final Item SILENCE_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("silence_armor_trim_smithing_template", builder()));
public static final Item RAISER_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("raiser_armor_trim_smithing_template", builder()));
public static final Item HOST_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("host_armor_trim_smithing_template", builder()));
+ public static final Item FLOW_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("flow_armor_trim_smithing_template", builder()));
+ public static final Item BOLT_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("bolt_armor_trim_smithing_template", builder()));
public static final Item ANGLER_POTTERY_SHERD = register(new Item("angler_pottery_sherd", builder()));
public static final Item ARCHER_POTTERY_SHERD = register(new Item("archer_pottery_sherd", builder()));
public static final Item ARMS_UP_POTTERY_SHERD = register(new Item("arms_up_pottery_sherd", builder()));
@@ -1320,7 +1333,9 @@ public final class Items {
public static final Item BURN_POTTERY_SHERD = register(new Item("burn_pottery_sherd", builder()));
public static final Item DANGER_POTTERY_SHERD = register(new Item("danger_pottery_sherd", builder()));
public static final Item EXPLORER_POTTERY_SHERD = register(new Item("explorer_pottery_sherd", builder()));
+ public static final Item FLOW_POTTERY_SHERD = register(new Item("flow_pottery_sherd", builder()));
public static final Item FRIEND_POTTERY_SHERD = register(new Item("friend_pottery_sherd", builder()));
+ public static final Item GUSTER_POTTERY_SHERD = register(new Item("guster_pottery_sherd", builder()));
public static final Item HEART_POTTERY_SHERD = register(new Item("heart_pottery_sherd", builder()));
public static final Item HEARTBREAK_POTTERY_SHERD = register(new Item("heartbreak_pottery_sherd", builder()));
public static final Item HOWL_POTTERY_SHERD = register(new Item("howl_pottery_sherd", builder()));
@@ -1328,28 +1343,33 @@ public final class Items {
public static final Item MOURNER_POTTERY_SHERD = register(new Item("mourner_pottery_sherd", builder()));
public static final Item PLENTY_POTTERY_SHERD = register(new Item("plenty_pottery_sherd", builder()));
public static final Item PRIZE_POTTERY_SHERD = register(new Item("prize_pottery_sherd", builder()));
+ public static final Item SCRAPE_POTTERY_SHERD = register(new Item("scrape_pottery_sherd", builder()));
public static final Item SHEAF_POTTERY_SHERD = register(new Item("sheaf_pottery_sherd", builder()));
public static final Item SHELTER_POTTERY_SHERD = register(new Item("shelter_pottery_sherd", builder()));
public static final Item SKULL_POTTERY_SHERD = register(new Item("skull_pottery_sherd", builder()));
public static final Item SNORT_POTTERY_SHERD = register(new Item("snort_pottery_sherd", builder()));
- public static final Item COPPER_GRATE = register(new BlockItem("copper_grate", builder()));
- public static final Item EXPOSED_COPPER_GRATE = register(new BlockItem("exposed_copper_grate", builder()));
- public static final Item WEATHERED_COPPER_GRATE = register(new BlockItem("weathered_copper_grate", builder()));
- public static final Item OXIDIZED_COPPER_GRATE = register(new BlockItem("oxidized_copper_grate", builder()));
- public static final Item WAXED_COPPER_GRATE = register(new BlockItem("waxed_copper_grate", builder()));
- public static final Item WAXED_EXPOSED_COPPER_GRATE = register(new BlockItem("waxed_exposed_copper_grate", builder()));
- public static final Item WAXED_WEATHERED_COPPER_GRATE = register(new BlockItem("waxed_weathered_copper_grate", builder()));
- public static final Item WAXED_OXIDIZED_COPPER_GRATE = register(new BlockItem("waxed_oxidized_copper_grate", builder()));
- public static final Item COPPER_BULB = register(new BlockItem("copper_bulb", builder()));
- public static final Item EXPOSED_COPPER_BULB = register(new BlockItem("exposed_copper_bulb", builder()));
- public static final Item WEATHERED_COPPER_BULB = register(new BlockItem("weathered_copper_bulb", builder()));
- public static final Item OXIDIZED_COPPER_BULB = register(new BlockItem("oxidized_copper_bulb", builder()));
- public static final Item WAXED_COPPER_BULB = register(new BlockItem("waxed_copper_bulb", builder()));
- public static final Item WAXED_EXPOSED_COPPER_BULB = register(new BlockItem("waxed_exposed_copper_bulb", builder()));
- public static final Item WAXED_WEATHERED_COPPER_BULB = register(new BlockItem("waxed_weathered_copper_bulb", builder()));
- public static final Item WAXED_OXIDIZED_COPPER_BULB = register(new BlockItem("waxed_oxidized_copper_bulb", builder()));
- public static final Item TRIAL_SPAWNER = register(new BlockItem("trial_spawner", builder()));
+ public static final Item COPPER_GRATE = register(new BlockItem(builder(), Blocks.COPPER_GRATE));
+ public static final Item EXPOSED_COPPER_GRATE = register(new BlockItem(builder(), Blocks.EXPOSED_COPPER_GRATE));
+ public static final Item WEATHERED_COPPER_GRATE = register(new BlockItem(builder(), Blocks.WEATHERED_COPPER_GRATE));
+ public static final Item OXIDIZED_COPPER_GRATE = register(new BlockItem(builder(), Blocks.OXIDIZED_COPPER_GRATE));
+ public static final Item WAXED_COPPER_GRATE = register(new BlockItem(builder(), Blocks.WAXED_COPPER_GRATE));
+ public static final Item WAXED_EXPOSED_COPPER_GRATE = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_COPPER_GRATE));
+ public static final Item WAXED_WEATHERED_COPPER_GRATE = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_COPPER_GRATE));
+ public static final Item WAXED_OXIDIZED_COPPER_GRATE = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_COPPER_GRATE));
+ public static final Item COPPER_BULB = register(new BlockItem(builder(), Blocks.COPPER_BULB));
+ public static final Item EXPOSED_COPPER_BULB = register(new BlockItem(builder(), Blocks.EXPOSED_COPPER_BULB));
+ public static final Item WEATHERED_COPPER_BULB = register(new BlockItem(builder(), Blocks.WEATHERED_COPPER_BULB));
+ public static final Item OXIDIZED_COPPER_BULB = register(new BlockItem(builder(), Blocks.OXIDIZED_COPPER_BULB));
+ public static final Item WAXED_COPPER_BULB = register(new BlockItem(builder(), Blocks.WAXED_COPPER_BULB));
+ public static final Item WAXED_EXPOSED_COPPER_BULB = register(new BlockItem(builder(), Blocks.WAXED_EXPOSED_COPPER_BULB));
+ public static final Item WAXED_WEATHERED_COPPER_BULB = register(new BlockItem(builder(), Blocks.WAXED_WEATHERED_COPPER_BULB));
+ public static final Item WAXED_OXIDIZED_COPPER_BULB = register(new BlockItem(builder(), Blocks.WAXED_OXIDIZED_COPPER_BULB));
+ public static final Item TRIAL_SPAWNER = register(new BlockItem(builder(), Blocks.TRIAL_SPAWNER));
public static final Item TRIAL_KEY = register(new Item("trial_key", builder()));
+ public static final Item OMINOUS_TRIAL_KEY = register(new Item("ominous_trial_key", builder()));
+ public static final Item VAULT = register(new BlockItem(builder(), Blocks.VAULT));
+ public static final Item OMINOUS_BOTTLE = register(new OminousBottleItem("ominous_bottle", builder()));
+ public static final Item BREEZE_ROD = register(new Item("breeze_rod", builder()));
public static final int AIR_ID = AIR.javaId();
@@ -1359,11 +1379,7 @@ public final class Items {
public static T register(T item, int id) {
item.setJavaId(id);
- // This makes sure that the array is large enough to put the java item at the correct location
- if (Registries.JAVA_ITEMS.get().size() <= id) {
- Registries.JAVA_ITEMS.get().addAll(Collections.nCopies(id - Registries.JAVA_ITEMS.get().size() + 1, AIR));
- }
- Registries.JAVA_ITEMS.get().set(id, item);
+ Registries.JAVA_ITEMS.registerWithAnyIndex(id, item, AIR);
Registries.JAVA_ITEM_IDENTIFIERS.register(item.javaIdentifier(), item);
return item;
}
diff --git a/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java b/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java
index 8484eb185..a8832df1e 100644
--- a/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java
+++ b/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java
@@ -53,10 +53,6 @@ public enum ToolTier {
this.repairIngredients = Suppliers.memoize(repairIngredients::get);
}
- public int getSpeed() {
- return speed;
- }
-
public Set getRepairIngredients() {
return repairIngredients.get();
}
diff --git a/core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java b/core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java
new file mode 100644
index 000000000..c5c0d2611
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.item.enchantment;
+
+import org.checkerframework.checker.nullness.qual.Nullable;
+import org.cloudburstmc.nbt.NbtMap;
+import org.geysermc.geyser.inventory.item.BedrockEnchantment;
+import org.geysermc.geyser.session.cache.tags.EnchantmentTag;
+import org.geysermc.geyser.session.cache.tags.ItemTag;
+import org.geysermc.geyser.translator.text.MessageTranslator;
+import org.geysermc.geyser.util.MinecraftKey;
+import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @param description only populated if {@link #bedrockEnchantment()} is not null.
+ * @param anvilCost also as a rarity multiplier
+ */
+public record Enchantment(String identifier,
+ Set effects,
+ ItemTag supportedItems,
+ int maxLevel,
+ String description,
+ int anvilCost,
+ @Nullable EnchantmentTag exclusiveSet,
+ @Nullable BedrockEnchantment bedrockEnchantment) {
+
+ // Implementation note: I have a feeling the tags can be a list of items, because in vanilla they're HolderSet classes.
+ // I'm not sure how that's wired over the network, so we'll put it off.
+ public static Enchantment read(RegistryEntry entry) {
+ NbtMap data = entry.getData();
+ Set effects = readEnchantmentComponents(data.getCompound("effects"));
+ String supportedItems = data.getString("supported_items").substring(1); // Remove '#' at beginning that indicates tag
+ int maxLevel = data.getInt("max_level");
+ int anvilCost = data.getInt("anvil_cost");
+ String exclusiveSet = data.getString("exclusive_set", null);
+ EnchantmentTag exclusiveSetTag = exclusiveSet == null ? null : EnchantmentTag.ALL_ENCHANTMENT_TAGS.get(MinecraftKey.key(exclusiveSet.substring(1)));
+ BedrockEnchantment bedrockEnchantment = BedrockEnchantment.getByJavaIdentifier(entry.getId().asString());
+ String description = bedrockEnchantment == null ? MessageTranslator.deserializeDescription(data) : null;
+
+ return new Enchantment(entry.getId().asString(), effects, ItemTag.ALL_ITEM_TAGS.get(MinecraftKey.key(supportedItems)), maxLevel,
+ description, anvilCost, exclusiveSetTag, bedrockEnchantment);
+ }
+
+ private static Set readEnchantmentComponents(NbtMap effects) {
+ Set components = new HashSet<>();
+ for (Map.Entry entry : effects.entrySet()) {
+ switch (entry.getKey()) {
+ case "minecraft:prevent_armor_change" -> components.add(EnchantmentComponent.PREVENT_ARMOR_CHANGE);
+ }
+ }
+ return Set.copyOf(components); // Also ensures any empty sets are consolidated
+ }
+}
diff --git a/core/src/main/java/org/geysermc/geyser/item/enchantment/EnchantmentComponent.java b/core/src/main/java/org/geysermc/geyser/item/enchantment/EnchantmentComponent.java
new file mode 100644
index 000000000..66d110f98
--- /dev/null
+++ b/core/src/main/java/org/geysermc/geyser/item/enchantment/EnchantmentComponent.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2024 GeyserMC. http://geysermc.org
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @author GeyserMC
+ * @link https://github.com/GeyserMC/Geyser
+ */
+
+package org.geysermc.geyser.item.enchantment;
+
+public class EnchantmentComponent {
+ /**
+ * Singleton with no additional data
+ */
+ public static final EnchantmentComponent PREVENT_ARMOR_CHANGE = new EnchantmentComponent();
+}
diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java
index 38144f318..0a25a8d4f 100644
--- a/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java
+++ b/core/src/main/java/org/geysermc/geyser/item/type/ArmorItem.java
@@ -25,12 +25,17 @@
package org.geysermc.geyser.item.type;
-import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
-import com.github.steveice10.opennbt.tag.builtin.StringTag;
import org.checkerframework.checker.nullness.qual.NonNull;
+import org.cloudburstmc.nbt.NbtMap;
+import org.cloudburstmc.nbt.NbtMapBuilder;
+import org.cloudburstmc.protocol.bedrock.data.TrimMaterial;
+import org.cloudburstmc.protocol.bedrock.data.TrimPattern;
import org.geysermc.geyser.item.ArmorMaterial;
-import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.translator.item.BedrockItemBuilder;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.ArmorTrim;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
public class ArmorItem extends Item {
private final ArmorMaterial material;
@@ -41,28 +46,25 @@ public class ArmorItem extends Item {
}
@Override
- public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) {
- super.translateNbtToBedrock(session, tag);
+ public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) {
+ super.translateComponentsToBedrock(session, components, builder);
- if (tag.get("Trim") instanceof CompoundTag trim) {
- StringTag material = trim.remove("material");
- StringTag pattern = trim.remove("pattern");
+ ArmorTrim trim = components.get(DataComponentType.TRIM);
+ if (trim != null) {
+ TrimMaterial material = session.getRegistryCache().trimMaterials().byId(trim.material().id());
+ TrimPattern pattern = session.getRegistryCache().trimPatterns().byId(trim.pattern().id());
+
+ // discard custom trim patterns/materials to prevent visual glitches on bedrock
+ if (!getNamespace(material.getMaterialId()).equals("minecraft")
+ || !getNamespace(pattern.getPatternId()).equals("minecraft")) {
+ return;
+ }
+
+ NbtMapBuilder trimBuilder = NbtMap.builder();
// bedrock has an uppercase first letter key, and the value is not namespaced
- trim.put(new StringTag("Material", stripNamespace(material.getValue())));
- trim.put(new StringTag("Pattern", stripNamespace(pattern.getValue())));
- }
- }
-
- @Override
- public void translateNbtToJava(@NonNull CompoundTag tag, @NonNull ItemMapping mapping) {
- super.translateNbtToJava(tag, mapping);
-
- if (tag.get("Trim") instanceof CompoundTag trim) {
- StringTag material = trim.remove("Material");
- StringTag pattern = trim.remove("Pattern");
- // java has a lowercase key, and namespaced value
- trim.put(new StringTag("material", "minecraft:" + material.getValue()));
- trim.put(new StringTag("pattern", "minecraft:" + pattern.getValue()));
+ trimBuilder.put("Material", material.getMaterialId());
+ trimBuilder.put("Pattern", pattern.getPatternId());
+ builder.putCompound("Trim", trimBuilder.build());
}
}
@@ -71,11 +73,12 @@ public class ArmorItem extends Item {
return material.getRepairIngredient() == other;
}
- private static String stripNamespace(String identifier) {
+ // TODO maybe some kind of namespace util?
+ private static String getNamespace(String identifier) {
int i = identifier.indexOf(':');
if (i >= 0) {
- return identifier.substring(i + 1);
+ return identifier.substring(0, i);
}
- return identifier;
+ return "minecraft";
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/item/type/ArrowItem.java b/core/src/main/java/org/geysermc/geyser/item/type/ArrowItem.java
index 938d4a79a..4e4f1830e 100644
--- a/core/src/main/java/org/geysermc/geyser/item/type/ArrowItem.java
+++ b/core/src/main/java/org/geysermc/geyser/item/type/ArrowItem.java
@@ -25,14 +25,15 @@
package org.geysermc.geyser.item.type;
-import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack;
-import com.github.steveice10.opennbt.tag.builtin.StringTag;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
-import org.geysermc.geyser.inventory.item.TippedArrowPotion;
+import org.geysermc.geyser.inventory.GeyserItemStack;
+import org.geysermc.geyser.inventory.item.Potion;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.registry.type.ItemMappings;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents;
public class ArrowItem extends Item {
public ArrowItem(String javaIdentifier, Builder builder) {
@@ -40,14 +41,19 @@ public class ArrowItem extends Item {
}
@Override
- public @NonNull ItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
- TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByBedrockId(itemData.getDamage());
- ItemStack itemStack = super.translateToJava(itemData, mapping, mappings);
- if (tippedArrowPotion != null) {
- itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getNbt());
- StringTag potionTag = new StringTag("Potion", tippedArrowPotion.getJavaIdentifier());
- itemStack.getNbt().put(potionTag);
+ public @NonNull GeyserItemStack translateToJava(@NonNull ItemData itemData, @NonNull ItemMapping mapping, @NonNull ItemMappings mappings) {
+ Potion potion = Potion.getByTippedArrowDamage(itemData.getDamage());
+ GeyserItemStack itemStack = super.translateToJava(itemData, mapping, mappings);
+ if (potion != null) {
+ itemStack = Items.TIPPED_ARROW.newItemStack(itemStack.getAmount(), itemStack.getComponents());
+ PotionContents contents = potion.toComponent();
+ itemStack.getOrCreateComponents().put(DataComponentType.POTION_CONTENTS, contents);
}
return itemStack;
}
+
+ @Override
+ public boolean ignoreDamage() {
+ return true;
+ }
}
diff --git a/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java b/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java
index 81d7bf116..8895d45a8 100644
--- a/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java
+++ b/core/src/main/java/org/geysermc/geyser/item/type/AxolotlBucketItem.java
@@ -25,12 +25,11 @@
package org.geysermc.geyser.item.type;
-import com.github.steveice10.opennbt.tag.builtin.ByteTag;
-import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
-import com.github.steveice10.opennbt.tag.builtin.StringTag;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.MinecraftLocale;
+import org.geysermc.geyser.translator.item.BedrockItemBuilder;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
public class AxolotlBucketItem extends Item {
public AxolotlBucketItem(String javaIdentifier, Builder builder) {
@@ -38,15 +37,15 @@ public class AxolotlBucketItem extends Item {
}
@Override
- public void translateNbtToBedrock(@NonNull GeyserSession session, @NonNull CompoundTag tag) {
- super.translateNbtToBedrock(session, tag);
+ public void translateComponentsToBedrock(@NonNull GeyserSession session, @NonNull DataComponents components, @NonNull BedrockItemBuilder builder) {
+ super.translateComponentsToBedrock(session, components, builder);
// Bedrock Edition displays the properties of the axolotl. Java does not.
// To work around this, set the custom name to the Axolotl translation and it's displayed correctly
- tag.put(new ByteTag("AppendCustomName", (byte) 1));
- tag.put(new StringTag("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.axolotl", session.locale())));
+ builder.putByte("AppendCustomName", 1);
+ builder.putString("CustomName", MinecraftLocale.getLocaleString("entity.minecraft.axolotl", session.locale()));
// Boilerplate required so the nametag does not appear as "Bucket of "
- tag.put(new StringTag("ColorID", ""));
- tag.put(new StringTag("BodyID", ""));
+ builder.putString("ColorID", "");
+ builder.putString("BodyID", "");
}
}
diff --git a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java
index 344668836..6ec0da8ed 100644
--- a/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java
+++ b/core/src/main/java/org/geysermc/geyser/item/type/BannerItem.java
@@ -25,22 +25,32 @@
package org.geysermc.geyser.item.type;
-import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
-import com.github.steveice10.opennbt.tag.builtin.IntTag;
-import com.github.steveice10.opennbt.tag.builtin.ListTag;
-import com.github.steveice10.opennbt.tag.builtin.Tag;
+import it.unimi.dsi.fastutil.Pair;
+import net.kyori.adventure.key.Key;
+import net.kyori.adventure.text.Component;
+import net.kyori.adventure.text.format.Style;
+import net.kyori.adventure.text.format.TextColor;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.nbt.NbtList;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtType;
+import org.geysermc.geyser.inventory.item.BannerPattern;
+import org.geysermc.geyser.inventory.item.DyeColor;
+import org.geysermc.geyser.level.block.type.Block;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.session.cache.registry.JavaRegistry;
+import org.geysermc.geyser.translator.item.BedrockItemBuilder;
+import org.geysermc.geyser.util.MinecraftKey;
+import org.geysermc.mcprotocollib.protocol.data.game.Holder;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
+import org.geysermc.mcprotocollib.protocol.data.game.item.component.Unit;
import java.util.ArrayList;
import java.util.List;
-import static org.geysermc.erosion.util.BannerUtils.getJavaPatternTag;
-
public class BannerItem extends BlockItem {
/**
* Holds what a Java ominous banner pattern looks like.
@@ -49,19 +59,61 @@ public class BannerItem extends BlockItem {
* ominous banners that we set instead. This variable is used to detect Java ominous banner patterns, and apply
* the correct ominous banner pattern if Bedrock pulls the item from creative.
*/
- public static final ListTag OMINOUS_BANNER_PATTERN;
+ private static final List> OMINOUS_BANNER_PATTERN;
static {
- OMINOUS_BANNER_PATTERN = new ListTag("Patterns");
// Construct what an ominous banner is supposed to look like
- OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("mr", 9));
- OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("bs", 8));
- OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("cs", 7));
- OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("bo", 8));
- OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("ms", 15));
- OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("hh", 8));
- OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("mc", 8));
- OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("bo", 15));
+ OMINOUS_BANNER_PATTERN = List.of(
+ Pair.of(BannerPattern.RHOMBUS, DyeColor.CYAN),
+ Pair.of(BannerPattern.STRIPE_BOTTOM, DyeColor.LIGHT_GRAY),
+ Pair.of(BannerPattern.STRIPE_CENTER, DyeColor.GRAY),
+ Pair.of(BannerPattern.BORDER, DyeColor.LIGHT_GRAY),
+ Pair.of(BannerPattern.STRIPE_MIDDLE, DyeColor.BLACK),
+ Pair.of(BannerPattern.HALF_HORIZONTAL, DyeColor.LIGHT_GRAY),
+ Pair.of(BannerPattern.CIRCLE, DyeColor.LIGHT_GRAY),
+ Pair.of(BannerPattern.BORDER, DyeColor.BLACK)
+ );
+ }
+
+ public static boolean isOminous(GeyserSession session, List patternLayers) {
+ if (OMINOUS_BANNER_PATTERN.size() != patternLayers.size()) {
+ return false;
+ }
+ for (int i = 0; i < OMINOUS_BANNER_PATTERN.size(); i++) {
+ BannerPatternLayer patternLayer = patternLayers.get(i);
+ Pair pair = OMINOUS_BANNER_PATTERN.get(i);
+ if (patternLayer.getColorId() != pair.right().ordinal() ||
+ !patternLayer.getPattern().isId()) {
+ return false;
+ }
+ BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().byId(patternLayer.getPattern().id());
+ if (bannerPattern != pair.left()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static boolean isOminous(List blockEntityPatterns) {
+ // Cannot do a simple NBT equals check here because the IDs may not be full resource locations
+ // ViaVersion's fault, 1.20.4 -> 1.20.5, but it works on Java so we need to support it.
+ if (OMINOUS_BANNER_PATTERN.size() != blockEntityPatterns.size()) {
+ return false;
+ }
+ for (int i = 0; i < OMINOUS_BANNER_PATTERN.size(); i++) {
+ NbtMap patternLayer = blockEntityPatterns.get(i);
+ Pair