Compare commits

..
Author SHA1 Message Date
Nassim Jahnke 065a01eb16 Move event down a little 2025-05-28 16:41:29 +02:00
Nassim Jahnke 3c257d3639 give up 2025-05-25 10:16:05 +02:00
Nassim Jahnke eb180d5aeb move early checks 2025-05-25 09:47:57 +02:00
Nassim Jahnke 5f210bb2d6 Put signed message decoding through the message chain
While this disrupts signed command handling a bit, general behavior stays the same, and most importantly chat can continue to be handled off-main. It is necessary for the message decoding to happen in order, which previously was not guaranteed with the method call being in the netty event loop for chat and on main for signed commands.
2025-05-25 09:47:56 +02:00
41 changed files with 907 additions and 445 deletions

No files matched your search

+9 -14
View File
@@ -19,16 +19,18 @@ jobs:
# The goal of the build workflow is split into multiple requirements.
# 1. Run on pushes to same repo.
# 2. Run on PR open/reopen/syncs from repos that are not the same (PRs from the same repo are covered by 1)
# 3. Run on labeled PRs that have the publish-pr flag.
# 3. Run on labeled PRs that have the build-pr-jar flag.
if: >
(
(github.event_name == 'push')
|| (github.event_name == 'pull_request' && github.repository != github.event.pull_request.head.repo.full_name && contains(fromJSON('["opened", "reopened", "synchronize"]'), github.event.action))
|| (github.event_name == 'pull_request' && github.event.action == 'labeled' && github.event.label.name == 'publish-pr')
|| (github.event_name == 'pull_request' && github.event.action == 'labeled' && github.event.label.name == 'build-pr-jar')
)
runs-on: ubuntu-latest
strategy:
matrix:
java: [21]
fail-fast: true
steps:
- if: ${{ github.event_name == 'push' }}
@@ -41,10 +43,10 @@ jobs:
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: JDK 21
- name: JDK ${{ matrix.java }}
uses: actions/setup-java@v4
with:
java-version: 21
java-version: ${{ matrix.java }}
distribution: 'zulu'
- name: Setup Gradle
@@ -71,14 +73,14 @@ jobs:
if (event_name === "push" && ref_type === "branch") {
const {data: pulls} = await github.rest.pulls.list({ owner, repo, head: `${owner}:${ref_name}`, state: "open" });
const pull = pulls.find((pr) => !!pr.labels.find((l) => l.name === "publish-pr"));
const pull = pulls.find((pr) => !!pr.labels.find((l) => l.name === "build-pr-jar"));
if (pull) {
result["pr"] = pull.number;
result["action"] = "paperclip";
core.notice(`This is a push action but to a branch with an open PR with the build paperclip label (${JSON.stringify(result)})`);
return result;
}
} else if (event_name === "pull_request" && event.pull_request.labels.find((l) => l.name === "publish-pr")) {
} else if (event_name === "pull_request" && event.pull_request.labels.find((l) => l.name === "build-pr-jar")) {
result["pr"] = event.pull_request.number;
result["action"] = "paperclip";
core.notice(`This is a pull request action with a build paperclip label (${JSON.stringify(result)})`);
@@ -100,7 +102,7 @@ jobs:
if: always()
uses: actions/upload-artifact@v4
with:
name: Test Results
name: Test Results (${{ matrix.java }})
path: |
**/build/test-results/test/TEST-*.xml
@@ -114,13 +116,6 @@ jobs:
with:
name: paper-${{ fromJSON(steps.determine.outputs.result).pr }}
path: paper-server/build/libs/paper-paperclip-*-mojmap.jar
- name: Publish Artifacts
if: fromJSON(steps.determine.outputs.result).action == 'paperclip'
uses: PaperMC/action-pr-publishing/upload@paper
with:
# TODO fallback for failing javadoc
publishing-task: ":paper-api:publishAllPublicationsTo_githubPackages_PRsRepository publishDevBundlePublicationTo_githubPackages_PRsRepository -PpublishDevBundle"
event_file:
name: "Event File"
# Only run on PRs if the source branch is on someone else's repo
+84
View File
@@ -0,0 +1,84 @@
# This workflow run on the completion of the
# build workflow but only does anything if the
# triggering workflow uploaded an artifact.
#
# Do note that it is then the trigger workflow that
# determines if this will update the PR text body. All
# this workflow does is check if an uploaded artifact
# exists and there is a PR tied to the previous workflow.
name: Comment on pull request
on:
workflow_run:
workflows: ['Build Paper']
types: [completed]
jobs:
pr_comment:
if: github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v7
env:
BRANCH_NAME: "${{ github.event.workflow_run.head_branch }}"
PR_OWNER: "${{ github.event.workflow_run.head_repository.owner.login }}"
PR_SHA: "${{ github.event.workflow_run.head_sha }}"
RUN_ID: "${{ github.event.workflow_run.id }}"
REPO_ID: "${{ github.event.repository.id }}"
EVENT_TYPE: "${{ github.event.workflow_run.event}}"
PULL_REQUESTS: "${{ toJSON(github.event.workflow_run.pull_requests) }}"
with:
# This snippet is public-domain, taken from
# https://github.com/oprypin/nightly.link/blob/master/.github/workflows/pr-comment.yml
# Modified extensively by Machine_Maker
script: |
async function updatePR(owner, repo, issue_number, purpose, body) {
const { data } = await github.rest.issues.get({ owner, repo, issue_number });
core.debug(JSON.stringify(data, null, 2));
const marker = `<!-- bot: ${purpose} -->`;
let new_body = data.body ? data.body.trim().split(marker)[0].trim() : "";
new_body += `\n${marker}\n---\n${body}`;
core.info(`Updating the text body of PR #${issue_number} in ${owner}/${repo}`);
await github.rest.issues.update({ owner, repo, issue_number, body: new_body });
}
const { owner, repo } = context.repo;
const run_id = `${process.env.RUN_ID}`;
const repo_id = `${process.env.REPO_ID}`;
let pulls = [];
const event_type = `${process.env.EVENT_TYPE}`;
if (event_type === "push") { // if push, it's from the same repo which means `pull_requests` is populated
pulls = JSON.parse(`${process.env.PULL_REQUESTS}`);
} else {
const pr_branch = `${process.env.BRANCH_NAME}`;
const pr_sha = `${process.env.PR_SHA}`;
const pr_owner = `${process.env.PR_OWNER}`;
const { data } = await github.rest.pulls.list({ owner, repo, head: `${pr_owner}:${pr_branch}`, state: "open" });
core.debug(JSON.stringify(data, null, 2));
pulls = data.filter((pr) => pr.head.sha === pr_sha && pr.labels.find((l) => l.name === "build-pr-jar"));
}
if (!pulls.length) {
return core.notice("This workflow doesn't have any pull requests!");
} else if (pulls.length > 1) {
core.info(JSON.stringify(pulls, null, 2));
return core.error("Found multiple matching PRs");
}
const pull_request = pulls[0];
const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, { owner, repo, run_id });
if (!artifacts.length) {
return core.info("Skipping comment due to no artifact found");
}
const artifact = artifacts.find((art) => art.name === `paper-${pull_request.number}`);
if (!artifact) {
return core.info("Skipping comment to no matching artifact found");
}
const link = `https://nightly.link/${owner}/${repo}/actions/artifacts/${artifact.id}.zip`;
const body = `Download the paperclip jar for this pull request: [${artifact.name}.zip](${link})`;
core.info(`Adding a link to ${link}`);
await updatePR(owner, repo, pull_request.number, "paperclip-pr-build", body);
-36
View File
@@ -1,36 +0,0 @@
name: Publish PR
on:
workflow_run:
workflows: [ "Build Paper" ]
types:
- completed
permissions:
packages: write # To upload the PR
actions: write # To get information about the uploading workflow run and to delete the run artifacts
contents: write # To download the `maven-publish` artifact, and to be able to create commit comments
issues: write # To be able to create PR comments
pull-requests: write # To be able to create PR comments
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Generate an Application repository access token
id: gen_repo_token
uses: kattecon/gh-app-access-token-gen@v1
with:
app_id: 1408328
private_key: ${{ secrets.PR_PUBLISHING_GH_APP_KEY }}
repository: ${{ github.repository }}
- name: Publish PR
uses: PaperMC/action-pr-publishing@paper
env:
GITHUB_TOKEN: ${{ steps.gen_repo_token.outputs.token }}
with:
publishing-token: ${{ github.token }}
uploader-workflow-name: Build Paper
artifacts-base-path: io/papermc/paper
base-maven-url: 'https://maven-prs.papermc.io'
self-name: 'papermc-pr-publishing[bot]'
+3 -4
View File
@@ -21,13 +21,12 @@ jobs:
uses: dawidd6/action-download-artifact@v6
with:
run_id: ${{ github.event.workflow_run.id }}
path: test_artifacts
name: Test Results
path: artifacts
- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action@v2
with:
commit: ${{ github.event.workflow_run.head_sha }}
event_file: test_artifacts/Event File/event.json
event_file: artifacts/Event File/event.json
event_name: ${{ github.event.workflow_run.event }}
files: "test_artifacts/**/*.xml"
files: "artifacts/**/*.xml"
comment_mode: off
-1
View File
@@ -419,7 +419,6 @@ public net.minecraft.world.entity.npc.Villager increaseMerchantCareer()V
public net.minecraft.world.entity.npc.Villager numberOfRestocksToday
public net.minecraft.world.entity.npc.Villager releaseAllPois()V
public net.minecraft.world.entity.npc.Villager setUnhappy()V
public net.minecraft.world.entity.npc.Villager updateDemand()V
public net.minecraft.world.entity.npc.WanderingTrader getWanderTarget()Lnet/minecraft/core/BlockPos;
public net.minecraft.world.entity.player.Abilities flyingSpeed
public net.minecraft.world.entity.player.Abilities walkingSpeed
+1 -1
View File
@@ -184,7 +184,7 @@ tasks.withType<Javadoc> {
"https://jd.advntr.dev/text-serializer-plain/$adventureVersion/",
"https://jd.advntr.dev/text-logger-slf4j/$adventureVersion/",
"https://javadoc.io/doc/org.slf4j/slf4j-api/$slf4jVersion/",
// "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/", // TODO: Broken
"https://logging.apache.org/log4j/2.x/javadoc/log4j-api/",
"https://javadoc.io/doc/org.apache.maven.resolver/maven-resolver-api/1.7.3",
)
options.tags("apiNote:a:API Note:")
@@ -3,7 +3,6 @@ package io.papermc.paper.registry.set;
import io.papermc.paper.registry.TypedKey;
import java.util.Collection;
import java.util.Iterator;
import io.papermc.paper.registry.tag.TagKey;
import org.bukkit.Keyed;
import org.bukkit.Registry;
import org.jetbrains.annotations.ApiStatus;
@@ -34,7 +33,6 @@ public non-sealed interface RegistryKeySet<T extends Keyed> extends Iterable<Typ
* @param registry the registry to resolve the values from (must match {@link #registryKey()})
* @return the resolved values
* @see RegistryKeySet#values()
* @see Registry#getTagValues(TagKey)
*/
@Unmodifiable Collection<T> resolve(final Registry<T> registry);
@@ -491,27 +491,10 @@ public interface Registry<T extends Keyed> extends Iterable<T> {
* @throws NoSuchElementException if no tag with the given key is found
* @throws UnsupportedOperationException if this registry doesn't have or support tags
* @see #hasTag(TagKey)
* @see #getTagValues(TagKey)
*/
@ApiStatus.Experimental
Tag<T> getTag(TagKey<T> key);
/**
* Gets the named registry set (tag) for the given key and resolves it with this registry.
*
* @param key the key to get the tag for
* @return the resolved values
* @throws NoSuchElementException if no tag with the given key is found
* @throws UnsupportedOperationException if this registry doesn't have or support tags
* @see #getTag(TagKey)
* @see Tag#resolve(Registry)
*/
@ApiStatus.Experimental
default Collection<T> getTagValues(TagKey<T> key) {
Tag<T> tag = getTag(key);
return tag.resolve(this);
}
/**
* Gets all the tags in this registry.
*
@@ -391,21 +391,4 @@ public interface Villager extends AbstractVillager {
* reputation regardless of its impact and the player associated.
*/
public void clearReputations();
/**
* Updates the demand for Villager offers.
* Demand can rise and fall based on how often offers are traded.
* They can fall when an item is not traded for a while, or rise when the item is resupplied next.
* Demand is used to calculate the price of items in the Villager's offers.
* <br>
* <b>Note: Demand is stored per item and not per Villager.</b>
*/
public void updateDemand();
/**
* Resets uses of all offers for the Villager. This also internally calls {@link #updateDemand()}.
* Calling this will trigger a {@link org.bukkit.event.entity.VillagerReplenishTradeEvent} for each offer that is restocked.
* Demand is still updated even if all events are canceled.
*/
public void restock();
}
@@ -155,7 +155,7 @@ public final class RegistryEntries {
entry(Registries.VILLAGER_TYPE, VillagerType.class, Villager.Type.class),
entry(Registries.MAP_DECORATION_TYPE, MapDecorationTypes.class, MapCursor.Type.class),
entry(Registries.MENU, net.minecraft.world.inventory.MenuType.class, MenuType.class),
entry(Registries.ATTRIBUTE, Attributes.class, Attribute.class).serializationUpdater("ATTRIBUTE_RENAME"),
entry(Registries.ATTRIBUTE, Attributes.class, Attribute.class),
entry(Registries.FLUID, Fluids.class, Fluid.class),
entry(Registries.SOUND_EVENT, SoundEvents.class, Sound.class).allowDirect().apiRegistryField("SOUNDS"),
entry(Registries.DATA_COMPONENT_TYPE, DataComponents.class, DataComponentType.class, "Paper").preload(DataComponentTypes.class).apiAccessName("of")
@@ -358,7 +358,7 @@ index 88b81a5fbc88e6240f86c1e780d80eb4b601df8c..00a5ed09caa2689543bd47bcd93d5a61
import java.io.Writer;
import java.nio.file.Path;
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 81c615d00323bdf86bdb76db17bb47288cf3feba..6b67cc939851745718f919488c997eb6719a16fc 100644
index 156f7ddc2fdc96b762598bad2a2b21f433518dc0..ef201f4add358fbf1818f3b2ec9e75fe2cce4c8b 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -544,6 +544,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -468,7 +468,7 @@ index bf44f6b9c8710e0c9a85d44f6217501abc98a7b1..bfd904e468bbf2cc1a5b3353d3a69ad5
public void tick() {
super.tick();
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index a63873a0fe4335813cafe84cae2b2030c8f0e627..f0c72465a71dc5a51c22af5e614af744b0434e94 100644
index fd0cc1bf9e4425a0924ed77854907deec1a7348e..1c9e5f61d182cf60caa885135abddc879d602c48 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -388,6 +388,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -487,7 +487,7 @@ index a63873a0fe4335813cafe84cae2b2030c8f0e627..f0c72465a71dc5a51c22af5e614af744
// CraftBukkit end
// Paper start
@@ -407,6 +416,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -403,6 +412,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.position = Vec3.ZERO;
this.blockPosition = BlockPos.ZERO;
this.chunkPosition = ChunkPos.ZERO;
@@ -501,7 +501,7 @@ index a63873a0fe4335813cafe84cae2b2030c8f0e627..f0c72465a71dc5a51c22af5e614af744
SynchedEntityData.Builder builder = new SynchedEntityData.Builder(this);
builder.define(DATA_SHARED_FLAGS_ID, (byte)0);
builder.define(DATA_AIR_SUPPLY_ID, this.getMaxAirSupply());
@@ -962,6 +978,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -958,6 +974,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z);
} else {
if (type == MoverType.PISTON) {
@@ -512,7 +512,7 @@ index a63873a0fe4335813cafe84cae2b2030c8f0e627..f0c72465a71dc5a51c22af5e614af744
movement = this.limitPistonMovement(movement);
if (movement.equals(Vec3.ZERO)) {
return;
@@ -975,6 +995,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -971,6 +991,13 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.stuckSpeedMultiplier = Vec3.ZERO;
this.setDeltaMovement(Vec3.ZERO);
}
@@ -527,7 +527,7 @@ index a63873a0fe4335813cafe84cae2b2030c8f0e627..f0c72465a71dc5a51c22af5e614af744
movement = this.maybeBackOffFromEdge(movement, type);
Vec3 vec3 = this.collide(movement);
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
index 267544f50fafd914566df1c4b2327bc64d673165..3e8f4f3c3d43c6875108295187023c48eece2788 100644
index 4123354a660f85905c8c2db1c5377201c2b8267e..7ba7a00b8dee651ca7a3cab5b64b4ae11aa66da9 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -3163,6 +3163,14 @@ public abstract class LivingEntity extends Entity implements Attackable {
@@ -822,7 +822,7 @@ index 6162415095b030b4cc47364c56fa66236b3b0535..a56d9cdeb6589a053ffaaf2cd599a98a
+
}
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index fff4914de57dff26f66259a145d662ff5c96d840..1bb40f18b671d63719d96a58ff283767c2cfe383 100644
index 1aa98e4f70627632d3e676395c28fa0ecca72f56..1f26826b2161cfeb27e5b2060e178b493e9142d9 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -143,6 +143,12 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
@@ -1138,7 +1138,7 @@ index 0000000000000000000000000000000000000000..a814512fcfb85312474ae2c2c2144384
+}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
new file mode 100644
index 0000000000000000000000000000000000000000..25bceb88f7d040034a740c18ed5a3aab50b0c72b
index 0000000000000000000000000000000000000000..1acea58838f057ab87efd103cbecb6f5aeaef393
--- /dev/null
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
@@ -0,0 +1,1700 @@
@@ -2287,7 +2287,7 @@ index 0000000000000000000000000000000000000000..25bceb88f7d040034a740c18ed5a3aab
+ LOGGER.error("Failed to decompress chunk data for task: " + this.toString(), thr);
+ }
+
+ if (throwable == null && compoundTag == null) {
+ if (compoundTag == null) {
+ // need to re-try from the start
+ this.scheduleReadIO();
+ return;
@@ -28601,7 +28601,7 @@ index 8cc5c0716392ba06501542ff5cbe71ee43979e5d..09fd99c9cbd23b5f3c899bfb00c9b896
+ // Paper end - block counting
}
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index bcac0c25acb8c5176c2ca6bffbae118d83fb63f7..4057431072cd1ca159b25576969908ed30ad0868 100644
index 663fb13233afb51f935c30ac2acae808809754c6..81a18b8e605bd4c28b48a32c80be231609182970 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -140,7 +140,7 @@ import net.minecraft.world.scores.ScoreHolder;
@@ -28695,8 +28695,8 @@ index bcac0c25acb8c5176c2ca6bffbae118d83fb63f7..4057431072cd1ca159b25576969908ed
}
// Paper end - Share random for entities to make them more random
public @Nullable org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason
@@ -409,6 +365,156 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.movementThisTick.clear();
@@ -405,6 +361,156 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
return this.dimensions.makeBoundingBox(x, y, z);
}
// Paper end
+ // Paper start - rewrite chunk system
@@ -28852,7 +28852,7 @@ index bcac0c25acb8c5176c2ca6bffbae118d83fb63f7..4057431072cd1ca159b25576969908ed
public Entity(EntityType<?> entityType, Level level) {
this.type = entityType;
@@ -1349,35 +1455,77 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -1345,35 +1451,77 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
return distance;
}
@@ -28954,7 +28954,7 @@ index bcac0c25acb8c5176c2ca6bffbae118d83fb63f7..4057431072cd1ca159b25576969908ed
}
private static float[] collectCandidateStepUpHeights(AABB box, List<VoxelShape> colliders, float deltaY, float maxUpStep) {
@@ -2620,21 +2768,110 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -2616,21 +2764,110 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
public boolean isInWall() {
@@ -29076,7 +29076,7 @@ index bcac0c25acb8c5176c2ca6bffbae118d83fb63f7..4057431072cd1ca159b25576969908ed
}
public InteractionResult interact(Player player, InteractionHand hand) {
@@ -4082,15 +4319,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4078,15 +4315,17 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
public Iterable<Entity> getIndirectPassengers() {
@@ -29102,7 +29102,7 @@ index bcac0c25acb8c5176c2ca6bffbae118d83fb63f7..4057431072cd1ca159b25576969908ed
}
public int countPlayerPassengers() {
@@ -4233,77 +4472,136 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4229,77 +4468,136 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
return Mth.lerp(partialTick, this.yRotO, this.yRot);
}
@@ -29293,7 +29293,7 @@ index bcac0c25acb8c5176c2ca6bffbae118d83fb63f7..4057431072cd1ca159b25576969908ed
public boolean touchingUnloadedChunk() {
AABB aabb = this.getBoundingBox().inflate(1.0);
@@ -4458,6 +4756,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4454,6 +4752,15 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
public final void setPosRaw(double x, double y, double z, boolean forceBoundingBoxUpdate) {
@@ -29309,7 +29309,7 @@ index bcac0c25acb8c5176c2ca6bffbae118d83fb63f7..4057431072cd1ca159b25576969908ed
if (!checkPosition(this, x, y, z)) {
return;
}
@@ -4591,6 +4898,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4587,6 +4894,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@Override
public final void setRemoved(Entity.RemovalReason removalReason, @Nullable org.bukkit.event.entity.EntityRemoveEvent.Cause cause) { // CraftBukkit - add Bukkit remove cause
@@ -29322,7 +29322,7 @@ index bcac0c25acb8c5176c2ca6bffbae118d83fb63f7..4057431072cd1ca159b25576969908ed
org.bukkit.craftbukkit.event.CraftEventFactory.callEntityRemoveEvent(this, cause); // CraftBukkit
final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers
if (this.removalReason == null) {
@@ -4601,7 +4914,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4597,7 +4910,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
this.stopRiding();
}
@@ -29331,7 +29331,7 @@ index bcac0c25acb8c5176c2ca6bffbae118d83fb63f7..4057431072cd1ca159b25576969908ed
this.levelCallback.onRemove(removalReason);
this.onRemoval(removalReason);
// Paper start - Folia schedulers
@@ -4635,7 +4948,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -4631,7 +4944,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
public boolean shouldBeSaved() {
return (this.removalReason == null || this.removalReason.shouldSave())
&& !this.isPassenger()
@@ -8,24 +8,6 @@
int maxStackSize = itemStack.getMaxStackSize();
int i = maxStackSize * 100;
if (count > i) {
@@ -66,7 +_,7 @@
ItemStack itemStack1 = item.createItemStack(min, false);
boolean flag = serverPlayer.getInventory().add(itemStack1);
if (flag && itemStack1.isEmpty()) {
- ItemEntity itemEntity = serverPlayer.drop(itemStack, false);
+ ItemEntity itemEntity = serverPlayer.drop(itemStack, false, false, false, null); // Paper - do not fire PlayerDropItemEvent for /give command
if (itemEntity != null) {
itemEntity.makeFakeItem();
}
@@ -84,7 +_,7 @@
);
serverPlayer.containerMenu.broadcastChanges();
} else {
- ItemEntity itemEntity = serverPlayer.drop(itemStack1, false);
+ ItemEntity itemEntity = serverPlayer.drop(itemStack1, false, false, false, null); // Paper - do not fire PlayerDropItemEvent for /give command
if (itemEntity != null) {
itemEntity.setNoPickUpDelay();
itemEntity.setTarget(serverPlayer.getUUID());
@@ -95,11 +_,11 @@
if (targets.size() == 1) {
@@ -1395,7 +1395,7 @@
throw new IllegalArgumentException("Expected packet sequence nr >= 0");
} else {
this.ackBlockChangesUpTo = Math.max(sequence, this.ackBlockChangesUpTo);
@@ -1356,20 +_,38 @@
@@ -1356,23 +_,37 @@
@Override
public void handleSetCarriedItem(ServerboundSetCarriedItemPacket packet) {
PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel());
@@ -1425,16 +1425,15 @@
@Override
public void handleChat(ServerboundChatPacket packet) {
+ // CraftBukkit start - async chat
+ // SPIGOT-3638
+ if (this.server.isStopped()) {
+ return;
+ }
+ // CraftBukkit end
+ if (this.server.isStopped()) return; // CraftBukkit - SPIGOT-3638
Optional<LastSeenMessages> optional = this.unpackAndApplyLastSeen(packet.lastSeenMessages());
if (!optional.isEmpty()) {
this.tryHandleChat(packet.message(), () -> {
@@ -1381,25 +_,45 @@
+ if (this.player.hasDisconnected()) return; // CraftBukkit
PlayerChatMessage signedMessage;
try {
signedMessage = this.getSignedMessage(packet, optional.get());
@@ -1381,10 +_,14 @@
return;
}
@@ -1442,31 +1441,30 @@
- Component component = this.server.getChatDecorator().decorate(this.player, signedMessage.decoratedContent());
- this.chatMessageChain.append(completableFuture, filteredText -> {
- PlayerChatMessage playerChatMessage = signedMessage.withUnsignedContent(component).filter(filteredText.mask());
+ CompletableFuture<FilteredText> completableFuture = this.filterTextPacket(signedMessage.signedContent()).thenApplyAsync(java.util.function.Function.identity(), this.server.chatExecutor); // CraftBukkit - async chat
+ CompletableFuture<Component> componentFuture = this.server.getChatDecorator().decorate(this.player, null, signedMessage.decoratedContent()); // Paper - Adventure
+ // Paper start - Adventure
+ // Make decoration async too, just message decoding has to stay in order, unfortunately blocked by commands
+ CompletableFuture<FilteredText> completableFuture = this.filterTextPacket(signedMessage.signedContent()).thenApplyAsync(java.util.function.Function.identity(), this.server.chatExecutor);
+ CompletableFuture<Component> componentFuture = this.server.getChatDecorator().decorate(this.player, null, signedMessage.decoratedContent());
+
+ this.chatMessageChain.append(CompletableFuture.allOf(completableFuture, componentFuture), ($) -> { // Paper - Adventure
+ PlayerChatMessage playerChatMessage = signedMessage.withUnsignedContent(componentFuture.join()).filter(completableFuture.join().mask()); // Paper - Adventure
+ this.chatMessageChain.append(CompletableFuture.allOf(completableFuture, componentFuture), ($) -> {
+ PlayerChatMessage playerChatMessage = signedMessage.withUnsignedContent(componentFuture.join()).filter(completableFuture.join().mask());
+ // Paper end - Adventure
this.broadcastChatMessage(playerChatMessage);
});
- });
+ }, false); // CraftBukkit - async chat
}
}
});
@@ -1394,12 +_,31 @@
@Override
public void handleChatCommand(ServerboundChatCommandPacket packet) {
this.tryHandleChat(packet.command(), () -> {
+ // CraftBukkit start - SPIGOT-7346: Prevent disconnected players from executing commands
+ if (this.player.hasDisconnected()) {
+ if (this.player.hasDisconnected() || this.player.isRemoved()) {
+ return;
+ }
+ // CraftBukkit end
this.performUnsignedChatCommand(packet.command());
- this.detectRateSpam();
- });
+ this.detectRateSpam("/" + packet.command()); // Spigot
+ }, true); // CraftBukkit - sync commands
});
}
private void performUnsignedChatCommand(String command) {
@@ -1478,101 +1476,79 @@
+
+ PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(this.getCraftPlayer(), prefixedCommand, new org.bukkit.craftbukkit.util.LazyPlayerSet(this.server));
+ this.cserver.getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ return;
+ }
+
+ command = event.getMessage().substring(1);
+ // CraftBukkit end
ParseResults<CommandSourceStack> parseResults = this.parseCommand(command);
if (this.server.enforceSecureProfile() && SignableCommand.hasSignableArguments(parseResults)) {
LOGGER.error(
@@ -1416,28 +_,57 @@
@@ -1416,13 +_,21 @@
Optional<LastSeenMessages> optional = this.unpackAndApplyLastSeen(packet.lastSeenMessages());
if (!optional.isEmpty()) {
this.tryHandleChat(packet.command(), () -> {
+ // CraftBukkit start - SPIGOT-7346: Prevent disconnected players from executing commands
+ if (this.player.hasDisconnected()) {
+ return;
+ }
+ // CraftBukkit end
+ if (this.player.hasDisconnected()) return; // CraftBukkit - SPIGOT-7346: Prevent disconnected players from executing commands
this.performSignedChatCommand(packet, optional.get());
- this.detectRateSpam();
- });
+ this.detectRateSpam("/" + packet.command()); // Spigot
+ }, true); // CraftBukkit - sync commands
});
}
}
private void performSignedChatCommand(ServerboundChatCommandSignedPacket packet, LastSeenMessages lastSeenMessages) {
+ // CraftBukkit start
+ String command = "/" + packet.command();
+ if (org.spigotmc.SpigotConfig.logCommands) { // Paper - Add missing SpigotConfig logCommands check
+ LOGGER.info("{} issued server command: {}", this.player.getScoreboardName(), command);
+ } // Paper - Add missing SpigotConfig logCommands check
+
+ PlayerCommandPreprocessEvent event = new PlayerCommandPreprocessEvent(this.getCraftPlayer(), command, new org.bukkit.craftbukkit.util.LazyPlayerSet(this.server));
+ this.cserver.getPluginManager().callEvent(event);
+ command = event.getMessage().substring(1);
+ // Paper start
+ final String slashCommand = "/" + packet.command();
+ if (org.spigotmc.SpigotConfig.logCommands) {
+ LOGGER.info("{} issued server command: {}", this.player.getScoreboardName(), slashCommand);
+ }
+ // Paper end
+
ParseResults<CommandSourceStack> parseResults = this.parseCommand(packet.command());
Map<String, PlayerChatMessage> map;
try {
+ // Paper - Always parse the original command to add to the chat chain
map = this.collectSignedArguments(packet, SignableCommand.of(parseResults), lastSeenMessages);
} catch (SignedMessageChain.DecodeException var6) {
this.handleMessageDecodeFailure(var6);
@@ -1433,11 +_,30 @@
return;
}
+ // Paper start - Fix cancellation and message changing
+ if (event.isCancelled()) {
+ // Only now are we actually good to return
+ // Paper start
+ // Parsing commands to be on main :cryingandshaking: - if that weren't the case, both this and chat could be pushed off to the chat message chain immediately
+ // Always decode message arguments before cancelling, else the chat chain will be broken
+ if (this.player.isRemoved()) {
+ return;
+ }
+
+ // Remove signed parts if the command was changed
+ if (!command.equals(packet.command())) {
+ parseResults = this.parseCommand(command);
+ final org.bukkit.event.player.PlayerCommandPreprocessEvent event = new org.bukkit.event.player.PlayerCommandPreprocessEvent(this.getCraftPlayer(), slashCommand, new org.bukkit.craftbukkit.util.LazyPlayerSet(this.server));
+ if (!event.callEvent()) {
+ return;
+ }
+
+ final String updatedCommand = event.getMessage().substring(1);
+ if (!updatedCommand.equals(packet.command())) {
+ // Remove signed parts if the command was changed
+ parseResults = this.parseCommand(updatedCommand);
+ map = Collections.emptyMap();
+ }
+ // Paper end - Fix cancellation and message changing
+
+ // Paper end
CommandSigningContext commandSigningContext = new CommandSigningContext.SignedArguments(map);
parseResults = Commands.mapSource(
parseResults, commandSourceStack -> commandSourceStack.withSigningContext(commandSigningContext, this.chatMessageChain)
);
- this.server.getCommands().performCommand(parseResults, packet.command());
+ this.server.getCommands().performCommand(parseResults, command); // CraftBukkit
+ this.server.getCommands().performCommand(parseResults, updatedCommand); // Paper
}
private void handleMessageDecodeFailure(SignedMessageChain.DecodeException exception) {
@@ -1501,14 +_,20 @@
return dispatcher.parse(command, this.player.createCommandSourceStack());
}
@@ -1503,7 +_,7 @@
- private void tryHandleChat(String message, Runnable handler) {
+ private void tryHandleChat(String message, Runnable handler, boolean sync) { // CraftBukkit
private void tryHandleChat(String message, Runnable handler) {
if (isChatMessageIllegal(message)) {
- this.disconnect(Component.translatable("multiplayer.disconnect.illegal_characters"));
- } else if (this.player.getChatVisibility() == ChatVisiblity.HIDDEN) {
+ this.disconnectAsync(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper - add proper async disconnect
+ } else if (this.player.isRemoved() || this.player.getChatVisibility() == ChatVisiblity.HIDDEN) { // CraftBukkit - dead men tell no tales
} else if (this.player.getChatVisibility() == ChatVisiblity.HIDDEN) {
this.send(new ClientboundSystemChatPacket(Component.translatable("chat.disabled.options").withStyle(ChatFormatting.RED), false));
} else {
this.player.resetLastActionTime();
- this.server.execute(handler);
+ // CraftBukkit start
+ if (sync) {
+ this.server.execute(handler);
+ } else {
+ handler.run();
+ }
+ // CraftBukkit end
}
}
@@ -1520,7 +_,7 @@
var10000 = Optional.of(lastSeenMessages);
} catch (LastSeenMessagesValidator.ValidationException var5) {
@@ -2607,7 +2583,7 @@
this.chatMessageChain
.append(
() -> {
+ server.executeBlocking(() -> { // Paper - Broadcast chat session update sync
+ server.executeBlocking(() -> { // Paper - Broadcast chat session update sync, the used broadcast method isn't thread safe
this.player.setChatSession(chatSession);
this.server
.getPlayerList()
@@ -135,7 +135,7 @@
@Nullable
private BlockState inBlockState = null;
private final List<List<Entity.Movement>> movementThisTick = new ObjectArrayList<>();
@@ -259,6 +_,45 @@
@@ -259,6 +_,41 @@
private final LongSet visitedBlocks = new LongOpenHashSet();
private final InsideBlockEffectApplier.StepBasedCollector insideEffectCollector = new InsideBlockEffectApplier.StepBasedCollector();
private CustomData customData = CustomData.EMPTY;
@@ -173,10 +173,6 @@
+ public final AABB getBoundingBoxAt(double x, double y, double z) {
+ return this.dimensions.makeBoundingBox(x, y, z);
+ }
+ // MC-296337
+ protected void clearMovementsThisTick() {
+ this.movementThisTick.clear();
+ }
+ // Paper end
public Entity(EntityType<?> entityType, Level level) {
@@ -96,14 +96,6 @@
}
}
@@ -386,6 +_,7 @@
public void applyEffectsFromBlocks() {
if (!useExperimentalMovement(this.level())) {
this.applyEffectsFromBlocks(this.position(), this.position());
+ this.clearMovementsThisTick(); // Paper - MC-296337
} else {
super.applyEffectsFromBlocks();
}
@@ -457,6 +_,15 @@
this.setDisplayOffset(compound.getIntOr("DisplayOffset", this.getDefaultDisplayOffset()));
this.flipped = compound.getBooleanOr("FlippedRotation", false);
@@ -10,7 +10,7 @@
pos,
6,
65,
@@ -63,8 +_,10 @@
@@ -63,16 +_,18 @@
if (blockPos.equals(pos)) {
return BlockPos.TraversalNodeStatus.ACCEPT;
} else {
@@ -23,7 +23,8 @@
if (!fluidState.is(FluidTags.WATER)) {
return BlockPos.TraversalNodeStatus.SKIP;
} else if (blockState.getBlock() instanceof BucketPickup bucketPickup
@@ -72,7 +_,7 @@
- && !bucketPickup.pickupBlock(null, level, blockPos, blockState).isEmpty()) {
+ && !bucketPickup.pickupBlock(null, blockList, blockPos, blockState).isEmpty()) { // CraftBukkit
return BlockPos.TraversalNodeStatus.ACCEPT;
} else {
if (blockState.getBlock() instanceof LiquidBlock) {
@@ -1,13 +1,14 @@
package io.papermc.paper.datacomponent;
import java.util.function.Function;
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.util.NullOps;
import net.minecraft.util.Unit;
import org.bukkit.craftbukkit.CraftRegistry;
public record DataComponentAdapter<NMS, API>(
DataComponentType<NMS> type,
Function<API, NMS> apiToVanilla,
Function<NMS, API> vanillaToApi,
boolean codecValidation
@@ -26,11 +27,11 @@ public record DataComponentAdapter<NMS, API>(
return this.apiToVanilla == API_TO_UNIMPLEMENTED_CONVERTER;
}
public NMS toVanilla(final API value, final Holder<? extends DataComponentType<NMS>> type) {
public NMS toVanilla(final API value) {
final NMS nms = this.apiToVanilla.apply(value);
if (this.codecValidation && !type.value().isTransient()) {
type.value().codecOrThrow().encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(NullOps.INSTANCE), nms).ifError(error -> {
throw new IllegalArgumentException("Failed to encode data component %s (%s)".formatted(type.unwrapKey().orElseThrow(), error.message()));
if (this.codecValidation) {
this.type.codecOrThrow().encodeStart(CraftRegistry.getMinecraftRegistry().createSerializationContext(NullOps.INSTANCE), nms).ifError(error -> {
throw new IllegalArgumentException("Failed to encode data component %s (%s)".formatted(BuiltInRegistries.DATA_COMPONENT_TYPE.getKey(this.type), error.message()));
});
}
@@ -40,10 +40,10 @@ import io.papermc.paper.datacomponent.item.PaperUseRemainder;
import io.papermc.paper.datacomponent.item.PaperWeapon;
import io.papermc.paper.datacomponent.item.PaperWritableBookContent;
import io.papermc.paper.datacomponent.item.PaperWrittenBookContent;
import io.papermc.paper.registry.PaperRegistries;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import io.papermc.paper.registry.PaperRegistries;
import net.minecraft.core.component.DataComponentType;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.BuiltInRegistries;
@@ -147,8 +147,7 @@ public final class DataComponentAdapters {
register(DataComponents.OMINOUS_BOTTLE_AMPLIFIER, PaperOminousBottleAmplifier::new);
register(DataComponents.JUKEBOX_PLAYABLE, PaperJukeboxPlayable::new);
register(DataComponents.PROVIDES_BANNER_PATTERNS, PaperRegistries::fromNms, PaperRegistries::toNms);
register(
DataComponents.RECIPES,
register(DataComponents.RECIPES,
nms -> transformUnmodifiable(nms, PaperAdventure::asAdventureKey),
api -> transformUnmodifiable(api, key -> PaperAdventure.asVanilla(Registries.RECIPE, key))
);
@@ -165,7 +164,7 @@ public final class DataComponentAdapters {
// bees
// register(DataComponents.LOCK, PaperLockCode::new);
register(DataComponents.CONTAINER_LOOT, PaperSeededContainerLoot::new);
register(DataComponents.BREAK_SOUND, nms -> PaperAdventure.asAdventure(nms.value().location()), PaperAdventure::resolveSound);
register(DataComponents.BREAK_SOUND, nms -> PaperAdventure.asAdventure(nms.value().location()), PaperAdventure::resolveSound);
register(DataComponents.TOOLTIP_DISPLAY, PaperTooltipDisplay::new);
register(DataComponents.WEAPON, PaperWeapon::new);
register(DataComponents.BLOCKS_ATTACKS, PaperBlocksAttacks::new);
@@ -196,42 +195,38 @@ public final class DataComponentAdapters {
register(DataComponents.SHEEP_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData()));
register(DataComponents.SHULKER_COLOR, nms -> DyeColor.getByWoolData((byte) nms.getId()), api -> net.minecraft.world.item.DyeColor.byId(api.getWoolData()));
for (final ResourceKey<DataComponentType<?>> key : BuiltInRegistries.DATA_COMPONENT_TYPE.registryKeySet()) {
if (!ADAPTERS.containsKey(key)) {
registerUnimplemented(key);
for (final Map.Entry<ResourceKey<DataComponentType<?>>, DataComponentType<?>> componentType : BuiltInRegistries.DATA_COMPONENT_TYPE.entrySet()) {
if (!ADAPTERS.containsKey(componentType.getKey())) {
registerUnimplemented(componentType.getValue());
}
}
}
private static <NMS> ResourceKey<DataComponentType<?>> getKey(final DataComponentType<NMS> type) {
return BuiltInRegistries.DATA_COMPONENT_TYPE.getResourceKey(type).orElseThrow();
}
public static void registerUntyped(final DataComponentType<Unit> type) {
registerInternal(getKey(type), UNIT_TO_API_CONVERTER, DataComponentAdapter.API_TO_UNIT_CONVERTER, false);
registerInternal(type, UNIT_TO_API_CONVERTER, DataComponentAdapter.API_TO_UNIT_CONVERTER, false);
}
private static <COMMON> void registerIdentity(final DataComponentType<COMMON> type) {
registerInternal(getKey(type), Function.identity(), Function.identity(), true);
registerInternal(type, Function.identity(), Function.identity(), true);
}
@SuppressWarnings("unchecked")
public static void registerUnimplemented(final ResourceKey<DataComponentType<?>> key) {
registerInternal(key, UNIMPLEMENTED_TO_API_CONVERTER, DataComponentAdapter.API_TO_UNIMPLEMENTED_CONVERTER, false);
public static <NMS> void registerUnimplemented(final DataComponentType<NMS> type) {
registerInternal(type, UNIMPLEMENTED_TO_API_CONVERTER, DataComponentAdapter.API_TO_UNIMPLEMENTED_CONVERTER, false);
}
private static <NMS, API extends Handleable<NMS>> void register(final DataComponentType<NMS> type, final Function<NMS, API> vanillaToApi) {
registerInternal(getKey(type), vanillaToApi, Handleable::getHandle, false);
registerInternal(type, vanillaToApi, Handleable::getHandle, false);
}
private static <NMS, API> void register(final DataComponentType<NMS> type, final Function<NMS, API> vanillaToApi, final Function<API, NMS> apiToVanilla) {
registerInternal(getKey(type), vanillaToApi, apiToVanilla, false);
registerInternal(type, vanillaToApi, apiToVanilla, false);
}
private static <NMS, API> void registerInternal(final ResourceKey<DataComponentType<?>> key, final Function<NMS, API> vanillaToApi, final Function<API, NMS> apiToVanilla, final boolean codecValidation) {
private static <NMS, API> void registerInternal(final DataComponentType<NMS> type, final Function<NMS, API> vanillaToApi, final Function<API, NMS> apiToVanilla, final boolean codecValidation) {
final ResourceKey<DataComponentType<?>> key = BuiltInRegistries.DATA_COMPONENT_TYPE.getResourceKey(type).orElseThrow();
if (ADAPTERS.containsKey(key)) {
throw new IllegalStateException("Duplicate adapter registration for " + key);
}
ADAPTERS.put(key, new DataComponentAdapter<>(apiToVanilla, vanillaToApi, codecValidation));
ADAPTERS.put(key, new DataComponentAdapter<>(type, apiToVanilla, vanillaToApi, codecValidation && !type.isTransient()));
}
}
@@ -1,16 +1,17 @@
package io.papermc.paper.datacomponent;
import io.papermc.paper.registry.HolderableBase;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponentMap;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.util.Handleable;
import org.jspecify.annotations.Nullable;
public abstract class PaperDataComponentType<T, NMS> extends HolderableBase<net.minecraft.core.component.DataComponentType<NMS>> implements DataComponentType {
public abstract class PaperDataComponentType<T, NMS> implements DataComponentType, Handleable<net.minecraft.core.component.DataComponentType<NMS>> {
static {
DataComponentAdapters.bootstrap();
@@ -41,64 +42,80 @@ public abstract class PaperDataComponentType<T, NMS> extends HolderableBase<net.
return type.getAdapter().fromVanilla(nmsValue);
}
private final NamespacedKey key;
private final net.minecraft.core.component.DataComponentType<NMS> type;
private final DataComponentAdapter<NMS, T> adapter;
private PaperDataComponentType(final Holder<net.minecraft.core.component.DataComponentType<NMS>> holder, final DataComponentAdapter<NMS, T> adapter) {
super(holder);
public PaperDataComponentType(final NamespacedKey key, final net.minecraft.core.component.DataComponentType<NMS> type, final DataComponentAdapter<NMS, T> adapter) {
this.key = key;
this.type = type;
this.adapter = adapter;
}
@Override
public NamespacedKey getKey() {
return this.key;
}
@Override
public boolean isPersistent() {
return !this.getHandle().isTransient();
return !this.type.isTransient();
}
public DataComponentAdapter<NMS, T> getAdapter() {
return this.adapter;
}
@SuppressWarnings({"unchecked"})
public static <NMS> DataComponentType of(final Holder<?> holder) {
final DataComponentAdapter<NMS, ?> adapter = (DataComponentAdapter<NMS, ?>) DataComponentAdapters.ADAPTERS.get(holder.unwrapKey().orElseThrow());
@Override
public net.minecraft.core.component.DataComponentType<NMS> getHandle() {
return this.type;
}
@SuppressWarnings("unchecked")
public static <NMS> DataComponentType of(final NamespacedKey key, final net.minecraft.core.component.DataComponentType<NMS> type) {
final DataComponentAdapter<NMS, ?> adapter = (DataComponentAdapter<NMS, ?>) DataComponentAdapters.ADAPTERS.get(BuiltInRegistries.DATA_COMPONENT_TYPE.getResourceKey(type).orElseThrow());
if (adapter == null) {
throw new IllegalArgumentException("No adapter found for " + holder);
throw new IllegalArgumentException("No adapter found for " + key);
}
if (adapter.isUnimplemented()) {
return new Unimplemented<>((Holder<net.minecraft.core.component.DataComponentType<NMS>>) holder, adapter);
return new Unimplemented<>(key, type, adapter);
} else if (adapter.isValued()) {
return new ValuedImpl<>((Holder<net.minecraft.core.component.DataComponentType<NMS>>) holder, adapter);
return new ValuedImpl<>(key, type, adapter);
} else {
return new NonValuedImpl<>((Holder<net.minecraft.core.component.DataComponentType<NMS>>) holder, adapter);
return new NonValuedImpl<>(key, type, adapter);
}
}
public static final class NonValuedImpl<T, NMS> extends PaperDataComponentType<T, NMS> implements NonValued {
NonValuedImpl(
final Holder<net.minecraft.core.component.DataComponentType<NMS>> holder,
final NamespacedKey key,
final net.minecraft.core.component.DataComponentType<NMS> type,
final DataComponentAdapter<NMS, T> adapter
) {
super(holder, adapter);
super(key, type, adapter);
}
}
public static final class ValuedImpl<T, NMS> extends PaperDataComponentType<T, NMS> implements Valued<T> {
ValuedImpl(
final Holder<net.minecraft.core.component.DataComponentType<NMS>> holder,
final NamespacedKey key,
final net.minecraft.core.component.DataComponentType<NMS> type,
final DataComponentAdapter<NMS, T> adapter
) {
super(holder, adapter);
super(key, type, adapter);
}
}
public static final class Unimplemented<T, NMS> extends PaperDataComponentType<T, NMS> {
public Unimplemented(
final Holder<net.minecraft.core.component.DataComponentType<NMS>> holder,
final NamespacedKey key,
final net.minecraft.core.component.DataComponentType<NMS> type,
final DataComponentAdapter<NMS, T> adapter
) {
super(holder, adapter);
super(key, type, adapter);
}
}
}
@@ -75,11 +75,7 @@ public final class PluginRemapper {
return null;
}
try {
return new PluginRemapper(pluginsDir);
} catch (final Exception e) {
throw new RuntimeException("Failed to create PluginRemapper, try deleting the '" + pluginsDir.resolve(PAPER_REMAPPED) + "' directory", e);
}
return new PluginRemapper(pluginsDir);
}
public void shutdown() {
@@ -8,7 +8,6 @@ import io.papermc.paper.util.MappingEnvironment;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -53,35 +52,32 @@ class RemappedPluginIndex {
try {
Files.createDirectories(this.dir);
} catch (final IOException ex) {
throw new UncheckedIOException(ex);
throw new RuntimeException(ex);
}
}
this.indexFile = dir.resolve(INDEX_FILE_NAME);
if (Files.isRegularFile(this.indexFile)) {
this.state = this.readIndex();
try {
this.state = this.readIndex();
} catch (final IOException e) {
throw new RuntimeException(e);
}
} else {
this.state = new State();
}
}
private State readIndex() {
private State readIndex() throws IOException {
final State state;
try (final BufferedReader reader = Files.newBufferedReader(this.indexFile)) {
state = GSON.fromJson(reader, State.class);
} catch (final Exception ex) {
throw new RuntimeException("Failed to read index file '" + this.indexFile + "'", ex);
}
// If mappings have changed, delete all cached files and create a new index
if (!state.mappingsHash.equals(MappingEnvironment.mappingsHash())) {
for (final String fileName : state.hashes.values()) {
final Path path = this.dir.resolve(fileName);
try {
Files.deleteIfExists(path);
} catch (final IOException ex) {
throw new UncheckedIOException("Failed to delete no longer needed file '" + path + "'", ex);
}
Files.deleteIfExists(this.dir.resolve(fileName));
}
return new State();
}
@@ -115,11 +111,10 @@ class RemappedPluginIndex {
}
iterator.remove();
final Path filePath = this.dir.resolve(fileName);
try {
Files.deleteIfExists(filePath);
Files.deleteIfExists(this.dir.resolve(fileName));
} catch (final IOException ex) {
throw new UncheckedIOException("Failed to delete no longer needed file '" + filePath + "'", ex);
throw new RuntimeException(ex);
}
}
@@ -12,17 +12,11 @@ public abstract class HolderableBase<M> implements Holderable<M> {
this.holder = holder;
}
// methods below are overridden to make final
@Override
public final Holder<M> getHolder() {
return this.holder;
}
@Override
public final M getHandle() {
return Holderable.super.getHandle();
}
@Override
public final int hashCode() {
return Holderable.super.implHashCode();
@@ -34,7 +28,7 @@ public abstract class HolderableBase<M> implements Holderable<M> {
}
@Override
public String toString() {
public final String toString() {
return Holderable.super.implToString();
}
@@ -106,7 +106,7 @@ public final class PaperRegistries {
start(Registries.VILLAGER_TYPE, RegistryKey.VILLAGER_TYPE).craft(Villager.Type.class, CraftVillager.CraftType::new).build(),
start(Registries.MAP_DECORATION_TYPE, RegistryKey.MAP_DECORATION_TYPE).craft(MapCursor.Type.class, CraftMapCursor.CraftType::new).build(),
start(Registries.MENU, RegistryKey.MENU).craft(MenuType.class, CraftMenuType::new).build(),
start(Registries.ATTRIBUTE, RegistryKey.ATTRIBUTE).craft(Attribute.class, CraftAttribute::new).serializationUpdater(FieldRename.ATTRIBUTE_RENAME).build(),
start(Registries.ATTRIBUTE, RegistryKey.ATTRIBUTE).craft(Attribute.class, CraftAttribute::new).build(),
start(Registries.FLUID, RegistryKey.FLUID).craft(Fluid.class, CraftFluid::new).build(),
start(Registries.SOUND_EVENT, RegistryKey.SOUND_EVENT).craft(Sound.class, CraftSound::new, true).build(),
start(Registries.DATA_COMPONENT_TYPE, RegistryKey.DATA_COMPONENT_TYPE).craft(DataComponentTypes.class, PaperDataComponentType::of).build(),
@@ -22,9 +22,7 @@ import net.minecraft.core.Vec3i;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.craftbukkit.util.Waitable;
@@ -152,20 +150,6 @@ public final class MCUtil {
return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2);
}
/**
* Converts a NMS World/Vector to Bukkit Location
*/
public static Location toLocation(Level world, Vec3 pos) {
return new Location(world.getWorld(), pos.x(), pos.y(), pos.z());
}
/**
* Converts a NMS World/Vector to Bukkit Location
*/
public static Location toLocation(Level world, Vec3 pos, float yaw, float pitch) {
return new Location(world.getWorld(), pos.x(), pos.y(), pos.z(), yaw, pitch);
}
public static BlockPos toBlockPos(Position pos) {
return new BlockPos(pos.blockX(), pos.blockY(), pos.blockZ());
}
@@ -1,7 +1,6 @@
package io.papermc.paper.util;
import com.google.common.base.Preconditions;
import io.papermc.paper.registry.HolderableBase;
import java.util.Locale;
import net.minecraft.core.Holder;
import org.bukkit.Keyed;
@@ -13,13 +12,14 @@ import org.jspecify.annotations.Nullable;
@SuppressWarnings({"removal", "DeprecatedIsStillUsed"})
@Deprecated
@NullMarked
public abstract class OldEnumHolderable<A extends OldEnum<A>, M> extends HolderableBase<M> implements Holderable<M>, OldEnum<A>, Keyed {
public abstract class OldEnumHolderable<A extends OldEnum<A>, M> implements Holderable<M>, OldEnum<A>, Keyed {
private final Holder<M> holder;
private final int ordinal;
private final @Nullable String name;
protected OldEnumHolderable(final Holder<M> holder, final int ordinal) {
super(holder);
this.holder = holder;
this.ordinal = ordinal;
if (holder instanceof final Holder.Reference<M> reference) {
// For backwards compatibility, minecraft values will stile return the uppercase name without the namespace,
@@ -36,6 +36,11 @@ public abstract class OldEnumHolderable<A extends OldEnum<A>, M> extends Holdera
}
}
@Override
public Holder<M> getHolder() {
return this.holder;
}
@Override
@Deprecated
public int compareTo(final A other) {
@@ -61,6 +66,21 @@ public abstract class OldEnumHolderable<A extends OldEnum<A>, M> extends Holdera
Preconditions.checkState(this.holder.kind() == Holder.Kind.REFERENCE, "Cannot call method for this registry item, because it is not registered.");
}
@Override
public NamespacedKey getKey() {
return MCUtil.fromResourceKey(this.holder.unwrapKey().orElseThrow(() -> new IllegalStateException("Cannot get key for this registry item, because it is not registered.")));
}
@Override
public boolean equals(final Object obj) {
return this.implEquals(obj);
}
@Override
public int hashCode() {
return this.implHashCode();
}
@Override
public String toString() {
if (this.name != null) {
@@ -1,12 +1,12 @@
package org.bukkit.craftbukkit;
import io.papermc.paper.util.Holderable;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import org.bukkit.GameEvent;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.util.Handleable;
import org.jetbrains.annotations.NotNull;
public class CraftGameEvent extends GameEvent implements Holderable<net.minecraft.world.level.gameevent.GameEvent> {
public class CraftGameEvent extends GameEvent implements Handleable<net.minecraft.world.level.gameevent.GameEvent> {
public static GameEvent minecraftToBukkit(net.minecraft.world.level.gameevent.GameEvent minecraft) {
return CraftRegistry.minecraftToBukkit(minecraft, Registries.GAME_EVENT);
@@ -16,44 +16,57 @@ public class CraftGameEvent extends GameEvent implements Holderable<net.minecraf
return CraftRegistry.bukkitToMinecraft(bukkit);
}
private final Holder<net.minecraft.world.level.gameevent.GameEvent> holder;
private final NamespacedKey key;
private final net.minecraft.resources.ResourceKey<net.minecraft.world.level.gameevent.GameEvent> handleKey; // Paper
private final net.minecraft.world.level.gameevent.GameEvent handle;
public CraftGameEvent(final Holder<net.minecraft.world.level.gameevent.GameEvent> holder) {
this.holder = holder;
public CraftGameEvent(NamespacedKey key, net.minecraft.world.level.gameevent.GameEvent handle) {
this.key = key;
this.handleKey = net.minecraft.resources.ResourceKey.create(net.minecraft.core.registries.Registries.GAME_EVENT, org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(key)); // Paper
this.handle = handle;
}
@Override
public Holder<net.minecraft.world.level.gameevent.GameEvent> getHolder() {
return this.holder;
public net.minecraft.world.level.gameevent.GameEvent getHandle() {
return this.handle;
}
@Override
public int getRange() {
return this.getHandle().notificationRadius();
return this.handle.notificationRadius();
}
@Override
public int getVibrationLevel() {
return net.minecraft.world.level.gameevent.vibrations.VibrationSystem.getGameEventFrequency(this.getHolder().unwrapKey().orElseThrow());
return net.minecraft.world.level.gameevent.vibrations.VibrationSystem.getGameEventFrequency(this.handleKey);
}
@NotNull
@Override
public NamespacedKey getKey() {
return Holderable.super.getKey();
return this.key;
}
@Override
public boolean equals(Object other) {
return Holderable.super.implEquals(other);
if (this == other) {
return true;
}
if (!(other instanceof CraftGameEvent)) {
return false;
}
return this.getKey().equals(((GameEvent) other).getKey());
}
@Override
public int hashCode() {
return Holderable.super.implHashCode();
return this.getKey().hashCode();
}
@Override
public String toString() {
return Holderable.super.implToString();
return "CraftGameEvent{key=" + this.key + "}";
}
}
@@ -1,19 +1,22 @@
package org.bukkit.craftbukkit;
import io.papermc.paper.registry.HolderableBase;
import com.google.common.base.Preconditions;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.contents.TranslatableContents;
import org.bukkit.JukeboxSong;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.util.Handleable;
import org.jetbrains.annotations.NotNull;
public class CraftJukeboxSong extends HolderableBase<net.minecraft.world.item.JukeboxSong> implements JukeboxSong {
public class CraftJukeboxSong implements JukeboxSong, Handleable<net.minecraft.world.item.JukeboxSong> {
public static JukeboxSong minecraftToBukkit(net.minecraft.world.item.JukeboxSong minecraft) {
return CraftRegistry.minecraftToBukkit(minecraft, Registries.JUKEBOX_SONG);
}
public static JukeboxSong minecraftHolderToBukkit(Holder<net.minecraft.world.item.JukeboxSong> minecraft) {
return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.JUKEBOX_SONG);
return CraftJukeboxSong.minecraftToBukkit(minecraft.value());
}
public static net.minecraft.world.item.JukeboxSong bukkitToMinecraft(JukeboxSong bukkit) {
@@ -21,16 +24,41 @@ public class CraftJukeboxSong extends HolderableBase<net.minecraft.world.item.Ju
}
public static Holder<net.minecraft.world.item.JukeboxSong> bukkitToMinecraftHolder(JukeboxSong bukkit) {
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.JUKEBOX_SONG);
Preconditions.checkArgument(bukkit != null);
net.minecraft.core.Registry<net.minecraft.world.item.JukeboxSong> registry = CraftRegistry.getMinecraftRegistry(Registries.JUKEBOX_SONG);
if (registry.wrapAsHolder(CraftJukeboxSong.bukkitToMinecraft(bukkit)) instanceof Holder.Reference<net.minecraft.world.item.JukeboxSong> holder) {
return holder;
}
throw new IllegalArgumentException("No Reference holder found for " + bukkit
+ ", this can happen if a plugin creates its own trim pattern without properly registering it.");
}
public CraftJukeboxSong(final Holder<net.minecraft.world.item.JukeboxSong> holder) {
super(holder);
private final NamespacedKey key;
private final net.minecraft.world.item.JukeboxSong handle;
public CraftJukeboxSong(NamespacedKey key, net.minecraft.world.item.JukeboxSong handle) {
this.key = key;
this.handle = handle;
}
@Override
public net.minecraft.world.item.JukeboxSong getHandle() {
return this.handle;
}
@Override
@NotNull
public NamespacedKey getKey() {
return this.key;
}
@NotNull
@Override
public String getTranslationKey() {
if (!(this.getHandle().description().getContents() instanceof TranslatableContents)) throw new UnsupportedOperationException("Description isn't translatable!"); // Paper
return ((TranslatableContents) this.getHandle().description().getContents()).getKey();
if (!(this.handle.description().getContents() instanceof TranslatableContents)) throw new UnsupportedOperationException("Description isn't translatable!"); // Paper
return ((TranslatableContents) this.handle.description().getContents()).getKey();
}
}
@@ -2,7 +2,6 @@ package org.bukkit.craftbukkit.attribute;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull;
@@ -55,7 +54,11 @@ final class AttributeMappings {
public static @NotNull NamespacedKey uuidToKey(final UUID uuid) {
final NamespacedKey key = ATTRIBUTE_MODIFIER_IDS.get(uuid);
return Objects.requireNonNullElseGet(key, () -> NamespacedKey.minecraft(uuid.toString()));
if (key != null) {
return key;
} else {
return NamespacedKey.minecraft(uuid.toString());
}
}
private static void add(final long msb, final long lsb, final String id) {
@@ -2,7 +2,6 @@ package org.bukkit.craftbukkit.attribute;
import com.google.common.base.Preconditions;
import io.papermc.paper.registry.RegistryKey;
import io.papermc.paper.util.OldEnumHolderable;
import java.util.Locale;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
@@ -11,8 +10,10 @@ import org.bukkit.attribute.Attribute;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.legacy.FieldRename;
import org.bukkit.craftbukkit.util.ApiVersion;
import org.bukkit.craftbukkit.util.Handleable;
import org.jetbrains.annotations.NotNull;
public class CraftAttribute extends OldEnumHolderable<Attribute, net.minecraft.world.entity.ai.attributes.Attribute> implements Attribute {
public class CraftAttribute implements Attribute, Handleable<net.minecraft.world.entity.ai.attributes.Attribute> {
private static int count = 0;
@@ -21,7 +22,7 @@ public class CraftAttribute extends OldEnumHolderable<Attribute, net.minecraft.w
}
public static Attribute minecraftHolderToBukkit(Holder<net.minecraft.world.entity.ai.attributes.Attribute> minecraft) {
return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.ATTRIBUTE);
return CraftAttribute.minecraftToBukkit(minecraft.value());
}
public static Attribute stringToBukkit(String string) {
@@ -43,7 +44,16 @@ public class CraftAttribute extends OldEnumHolderable<Attribute, net.minecraft.w
}
public static Holder<net.minecraft.world.entity.ai.attributes.Attribute> bukkitToMinecraftHolder(Attribute bukkit) {
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.ATTRIBUTE);
Preconditions.checkArgument(bukkit != null);
net.minecraft.core.Registry<net.minecraft.world.entity.ai.attributes.Attribute> registry = CraftRegistry.getMinecraftRegistry(Registries.ATTRIBUTE);
if (registry.wrapAsHolder(CraftAttribute.bukkitToMinecraft(bukkit)) instanceof Holder.Reference<net.minecraft.world.entity.ai.attributes.Attribute> holder) {
return holder;
}
throw new IllegalArgumentException("No Reference holder found for " + bukkit
+ ", this can happen if a plugin creates its own sound effect with out properly registering it.");
}
public static String bukkitToString(Attribute bukkit) {
@@ -52,17 +62,85 @@ public class CraftAttribute extends OldEnumHolderable<Attribute, net.minecraft.w
return bukkit.getKey().toString();
}
public CraftAttribute(final Holder<net.minecraft.world.entity.ai.attributes.Attribute> holder) {
super(holder, count++);
private final NamespacedKey key;
private final net.minecraft.world.entity.ai.attributes.Attribute attributeBase;
private final String name;
private final int ordinal;
public CraftAttribute(NamespacedKey key, net.minecraft.world.entity.ai.attributes.Attribute attributeBase) {
this.key = key;
this.attributeBase = attributeBase;
// For backwards compatibility, minecraft values will stile return the uppercase name without the namespace,
// in case plugins use for example the name as key in a config file to receive attribute specific values.
// Custom attributes will return the key with namespace. For a plugin this should look than like a new attribute
// (which can always be added in new minecraft versions and the plugin should therefore handle it accordingly).
if (NamespacedKey.MINECRAFT.equals(key.getNamespace())) {
this.name = key.getKey().toUpperCase(Locale.ROOT);
} else {
this.name = key.toString();
}
this.ordinal = CraftAttribute.count++;
}
@Override
public net.minecraft.world.entity.ai.attributes.Attribute getHandle() {
return this.attributeBase;
}
@NotNull
@Override
public NamespacedKey getKey() {
return this.key;
}
@NotNull
@Override
public String getTranslationKey() {
return this.getHandle().getDescriptionId();
return this.attributeBase.getDescriptionId();
}
@Override
public String translationKey() {
return this.getHandle().getDescriptionId();
public @NotNull String translationKey() {
return this.attributeBase.getDescriptionId();
}
@Override
public int compareTo(@NotNull Attribute attribute) {
return this.ordinal - attribute.ordinal();
}
@NotNull
@Override
public String name() {
return this.name;
}
@Override
public int ordinal() {
return this.ordinal;
}
@Override
public String toString() {
// For backwards compatibility
return this.name();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof CraftAttribute otherAttribute)) {
return false;
}
return this.getKey().equals(otherAttribute.getKey());
}
@Override
public int hashCode() {
return this.getKey().hashCode();
}
}
@@ -1,13 +1,15 @@
package org.bukkit.craftbukkit.entity;
import com.google.common.base.Preconditions;
import io.papermc.paper.util.OldEnumHolderable;
import java.util.Locale;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.entity.animal.CatVariant;
import org.bukkit.DyeColor;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.entity.Cat;
public class CraftCat extends CraftTameableAnimal implements Cat {
@@ -43,7 +45,7 @@ public class CraftCat extends CraftTameableAnimal implements Cat {
this.getHandle().setCollarColor(net.minecraft.world.item.DyeColor.byId(color.getWoolData()));
}
public static class CraftType extends OldEnumHolderable<Type, CatVariant> implements Type {
public static class CraftType implements Type, Handleable<CatVariant> {
private static int count = 0;
public static Type minecraftToBukkit(CatVariant minecraft) {
@@ -51,7 +53,7 @@ public class CraftCat extends CraftTameableAnimal implements Cat {
}
public static Type minecraftHolderToBukkit(Holder<CatVariant> minecraft) {
return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.CAT_VARIANT);
return CraftType.minecraftToBukkit(minecraft.value());
}
public static CatVariant bukkitToMinecraft(Type bukkit) {
@@ -62,8 +64,73 @@ public class CraftCat extends CraftTameableAnimal implements Cat {
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.CAT_VARIANT);
}
public CraftType(final Holder<CatVariant> holder) {
super(holder, count++);
private final NamespacedKey key;
private final CatVariant catVariant;
private final String name;
private final int ordinal;
public CraftType(NamespacedKey key, CatVariant catVariant) {
this.key = key;
this.catVariant = catVariant;
// For backwards compatibility, minecraft values will still return the uppercase name without the namespace,
// in case plugins use for example the name as key in a config file to receive type specific values.
// Custom types will return the key with namespace. For a plugin this should look than like a new type
// (which can always be added in new minecraft versions and the plugin should therefore handle it accordingly).
if (NamespacedKey.MINECRAFT.equals(key.getNamespace())) {
this.name = key.getKey().toUpperCase(Locale.ROOT);
} else {
this.name = key.toString();
}
this.ordinal = CraftType.count++;
}
@Override
public CatVariant getHandle() {
return this.catVariant;
}
@Override
public NamespacedKey getKey() {
return this.key;
}
@Override
public int compareTo(Type variant) {
return this.ordinal - variant.ordinal();
}
@Override
public String name() {
return this.name;
}
@Override
public int ordinal() {
return this.ordinal;
}
@Override
public String toString() {
// For backwards compatibility
return this.name();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof CraftType)) {
return false;
}
return this.getKey().equals(((CraftType) other).getKey());
}
@Override
public int hashCode() {
return this.getKey().hashCode();
}
}
@@ -1,13 +1,15 @@
package org.bukkit.craftbukkit.entity;
import com.google.common.base.Preconditions;
import io.papermc.paper.util.OldEnumHolderable;
import java.util.Locale;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.entity.animal.frog.Frog;
import net.minecraft.world.entity.animal.frog.FrogVariant;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.entity.Entity;
public class CraftFrog extends CraftAnimals implements org.bukkit.entity.Frog {
@@ -47,7 +49,7 @@ public class CraftFrog extends CraftAnimals implements org.bukkit.entity.Frog {
this.getHandle().setVariant(CraftVariant.bukkitToMinecraftHolder(variant));
}
public static class CraftVariant extends OldEnumHolderable<Variant, FrogVariant> implements Variant {
public static class CraftVariant implements Variant, Handleable<FrogVariant> {
private static int count = 0;
public static Variant minecraftToBukkit(FrogVariant minecraft) {
@@ -55,7 +57,7 @@ public class CraftFrog extends CraftAnimals implements org.bukkit.entity.Frog {
}
public static Variant minecraftHolderToBukkit(Holder<FrogVariant> minecraft) {
return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.FROG_VARIANT);
return CraftVariant.minecraftToBukkit(minecraft.value());
}
public static FrogVariant bukkitToMinecraft(Variant bukkit) {
@@ -65,8 +67,74 @@ public class CraftFrog extends CraftAnimals implements org.bukkit.entity.Frog {
public static Holder<FrogVariant> bukkitToMinecraftHolder(Variant bukkit) {
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.FROG_VARIANT);
}
public CraftVariant(final Holder<FrogVariant> holder) {
super(holder, count++);
private final NamespacedKey key;
private final FrogVariant frogVariant;
private final String name;
private final int ordinal;
public CraftVariant(NamespacedKey key, FrogVariant frogVariant) {
this.key = key;
this.frogVariant = frogVariant;
// For backwards compatibility, minecraft values will still return the uppercase name without the namespace,
// in case plugins use for example the name as key in a config file to receive variant specific values.
// Custom variants will return the key with namespace. For a plugin this should look than like a new variant
// (which can always be added in new minecraft versions and the plugin should therefore handle it accordingly).
if (NamespacedKey.MINECRAFT.equals(key.getNamespace())) {
this.name = key.getKey().toUpperCase(Locale.ROOT);
} else {
this.name = key.toString();
}
this.ordinal = CraftVariant.count++;
}
@Override
public FrogVariant getHandle() {
return this.frogVariant;
}
@Override
public NamespacedKey getKey() {
return this.key;
}
@Override
public int compareTo(Variant variant) {
return this.ordinal - variant.ordinal();
}
@Override
public String name() {
return this.name;
}
@Override
public int ordinal() {
return this.ordinal;
}
@Override
public String toString() {
// For backwards compatibility
return this.name();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof CraftVariant)) {
return false;
}
return this.getKey().equals(((Variant) other).getKey());
}
@Override
public int hashCode() {
return this.getKey().hashCode();
}
}
}
@@ -6,7 +6,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import net.minecraft.Optionull;
@@ -906,8 +905,7 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
@Override
public <T> T getMemory(MemoryKey<T> memoryKey) {
final Optional<?> memory = this.getHandle().getBrain().getMemoryInternal(CraftMemoryKey.bukkitToMinecraft(memoryKey));
return memory != null ? (T) memory.map(CraftMemoryMapper::fromNms).orElse(null) : null;
return (T) this.getHandle().getBrain().getMemory(CraftMemoryKey.bukkitToMinecraft(memoryKey)).map(CraftMemoryMapper::fromNms).orElse(null);
}
@Override
@@ -2,7 +2,7 @@ package org.bukkit.craftbukkit.entity;
import com.destroystokyo.paper.entity.villager.Reputation;
import com.google.common.base.Preconditions;
import io.papermc.paper.util.OldEnumHolderable;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import net.minecraft.core.BlockPos;
@@ -14,9 +14,11 @@ import net.minecraft.world.entity.npc.VillagerType;
import net.minecraft.world.level.block.BedBlock;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.util.CraftLocation;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.entity.Villager;
import org.bukkit.entity.ZombieVillager;
import org.bukkit.event.entity.CreatureSpawnEvent;
@@ -162,7 +164,7 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
return (entityzombievillager != null) ? (ZombieVillager) entityzombievillager.getBukkitEntity() : null;
}
public static class CraftType extends OldEnumHolderable<Type, VillagerType> implements Type {
public static class CraftType implements Type, Handleable<VillagerType> {
private static int count = 0;
public static Type minecraftToBukkit(VillagerType minecraft) {
@@ -170,7 +172,7 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
}
public static Type minecraftHolderToBukkit(Holder<VillagerType> minecraft) {
return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.VILLAGER_TYPE);
return CraftType.minecraftToBukkit(minecraft.value());
}
public static VillagerType bukkitToMinecraft(Type bukkit) {
@@ -181,12 +183,77 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.VILLAGER_TYPE);
}
public CraftType(final Holder<VillagerType> holder){
super(holder, count++);
private final NamespacedKey key;
private final VillagerType villagerType;
private final String name;
private final int ordinal;
public CraftType(NamespacedKey key, VillagerType villagerType) {
this.key = key;
this.villagerType = villagerType;
// For backwards compatibility, minecraft values will still return the uppercase name without the namespace,
// in case plugins use for example the name as key in a config file to receive type specific values.
// Custom types will return the key with namespace. For a plugin this should look than like a new type
// (which can always be added in new minecraft versions and the plugin should therefore handle it accordingly).
if (NamespacedKey.MINECRAFT.equals(key.getNamespace())) {
this.name = key.getKey().toUpperCase(Locale.ROOT);
} else {
this.name = key.toString();
}
this.ordinal = CraftType.count++;
}
@Override
public VillagerType getHandle() {
return this.villagerType;
}
@Override
public NamespacedKey getKey() {
return this.key;
}
@Override
public int compareTo(Type type) {
return this.ordinal - type.ordinal();
}
@Override
public String name() {
return this.name;
}
@Override
public int ordinal() {
return this.ordinal;
}
@Override
public String toString() {
// For backwards compatibility
return this.name();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof CraftType)) {
return false;
}
return this.getKey().equals(((Type) other).getKey());
}
@Override
public int hashCode() {
return this.getKey().hashCode();
}
}
public static class CraftProfession extends OldEnumHolderable<Profession, VillagerProfession> implements Profession {
public static class CraftProfession implements Profession, Handleable<VillagerProfession> {
private static int count = 0;
public static Profession minecraftHolderToBukkit(Holder<VillagerProfession> minecraft) {
@@ -205,8 +272,73 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
return CraftRegistry.bukkitToMinecraft(bukkit);
}
public CraftProfession(final Holder<VillagerProfession> holder) {
super(holder, count++);
private final NamespacedKey key;
private final VillagerProfession villagerProfession;
private final String name;
private final int ordinal;
public CraftProfession(NamespacedKey key, VillagerProfession villagerProfession) {
this.key = key;
this.villagerProfession = villagerProfession;
// For backwards compatibility, minecraft values will still return the uppercase name without the namespace,
// in case plugins use for example the name as key in a config file to receive profession specific values.
// Custom professions will return the key with namespace. For a plugin this should look than like a new profession
// (which can always be added in new minecraft versions and the plugin should therefore handle it accordingly).
if (NamespacedKey.MINECRAFT.equals(key.getNamespace())) {
this.name = key.getKey().toUpperCase(Locale.ROOT);
} else {
this.name = key.toString();
}
this.ordinal = CraftProfession.count++;
}
@Override
public VillagerProfession getHandle() {
return this.villagerProfession;
}
@Override
public NamespacedKey getKey() {
return this.key;
}
@Override
public int compareTo(Profession profession) {
return this.ordinal - profession.ordinal();
}
@Override
public String name() {
return this.name;
}
@Override
public int ordinal() {
return this.ordinal;
}
@Override
public String toString() {
// For backwards compatibility
return this.name();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof CraftProfession)) {
return false;
}
return this.getKey().equals(((Profession) other).getKey());
}
@Override
public int hashCode() {
return this.getKey().hashCode();
}
}
@@ -248,14 +380,4 @@ public class CraftVillager extends CraftAbstractVillager implements Villager {
public void clearReputations() {
getHandle().getGossips().gossips.clear();
}
@Override
public void updateDemand() {
getHandle().updateDemand();
}
@Override
public void restock() {
getHandle().restock();
}
}
@@ -1,14 +1,15 @@
package org.bukkit.craftbukkit.entity;
import com.google.common.base.Preconditions;
import io.papermc.paper.registry.HolderableBase;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.entity.animal.wolf.WolfSoundVariant;
import net.minecraft.world.entity.animal.wolf.WolfVariant;
import org.bukkit.DyeColor;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.entity.Wolf;
public class CraftWolf extends CraftTameableAnimal implements Wolf {
@@ -90,14 +91,14 @@ public class CraftWolf extends CraftTameableAnimal implements Wolf {
this.getHandle().setSoundVariant(CraftSoundVariant.bukkitToMinecraftHolder(soundVariant));
}
public static class CraftVariant extends HolderableBase<WolfVariant> implements Variant {
public static class CraftVariant implements Variant, Handleable<WolfVariant> {
public static Variant minecraftToBukkit(WolfVariant minecraft) {
return CraftRegistry.minecraftToBukkit(minecraft, Registries.WOLF_VARIANT);
}
public static Variant minecraftHolderToBukkit(Holder<WolfVariant> minecraft) {
return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.WOLF_VARIANT);
return CraftVariant.minecraftToBukkit(minecraft.value());
}
public static WolfVariant bukkitToMinecraft(Variant bukkit) {
@@ -105,22 +106,68 @@ public class CraftWolf extends CraftTameableAnimal implements Wolf {
}
public static Holder<WolfVariant> bukkitToMinecraftHolder(Variant bukkit) {
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.WOLF_VARIANT);
Preconditions.checkArgument(bukkit != null);
net.minecraft.core.Registry<WolfVariant> registry = CraftRegistry.getMinecraftRegistry(Registries.WOLF_VARIANT);
if (registry.wrapAsHolder(CraftVariant.bukkitToMinecraft(bukkit)) instanceof Holder.Reference<WolfVariant> holder) {
return holder;
}
throw new IllegalArgumentException("No Reference holder found for " + bukkit
+ ", this can happen if a plugin creates its own wolf variant with out properly registering it.");
}
public CraftVariant(final Holder<WolfVariant> holder) {
super(holder);
private final NamespacedKey key;
private final WolfVariant variant;
public CraftVariant(NamespacedKey key, WolfVariant variant) {
this.key = key;
this.variant = variant;
}
@Override
public WolfVariant getHandle() {
return this.variant;
}
@Override
public NamespacedKey getKey() {
return this.key;
}
@Override
public String toString() {
return this.key.toString();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof CraftVariant otherVariant)) {
return false;
}
return this.getKey().equals(otherVariant.getKey());
}
@Override
public int hashCode() {
return this.getKey().hashCode();
}
}
public static class CraftSoundVariant extends HolderableBase<WolfSoundVariant> implements SoundVariant {
public static class CraftSoundVariant implements SoundVariant, Handleable<WolfSoundVariant> {
public static SoundVariant minecraftToBukkit(WolfSoundVariant minecraft) {
return CraftRegistry.minecraftToBukkit(minecraft, Registries.WOLF_SOUND_VARIANT);
}
public static SoundVariant minecraftHolderToBukkit(Holder<WolfSoundVariant> minecraft) {
return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.WOLF_SOUND_VARIANT);
return CraftSoundVariant.minecraftToBukkit(minecraft.value());
}
public static WolfSoundVariant bukkitToMinecraft(SoundVariant bukkit) {
@@ -128,11 +175,57 @@ public class CraftWolf extends CraftTameableAnimal implements Wolf {
}
public static Holder<WolfSoundVariant> bukkitToMinecraftHolder(SoundVariant bukkit) {
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.WOLF_SOUND_VARIANT);
Preconditions.checkArgument(bukkit != null);
net.minecraft.core.Registry<WolfSoundVariant> registry = CraftRegistry.getMinecraftRegistry(Registries.WOLF_SOUND_VARIANT);
if (registry.wrapAsHolder(CraftSoundVariant.bukkitToMinecraft(bukkit)) instanceof Holder.Reference<WolfSoundVariant> holder) {
return holder;
}
throw new IllegalArgumentException("No Reference holder found for " + bukkit
+ ", this can happen if a plugin creates its own wolf sound variant with out properly registering it.");
}
public CraftSoundVariant(final Holder<WolfSoundVariant> holder) {
super(holder);
private final NamespacedKey key;
private final WolfSoundVariant soundVariant;
public CraftSoundVariant(NamespacedKey key, WolfSoundVariant soundVariant) {
this.key = key;
this.soundVariant = soundVariant;
}
@Override
public WolfSoundVariant getHandle() {
return this.soundVariant;
}
@Override
public NamespacedKey getKey() {
return this.key;
}
@Override
public String toString() {
return this.key.toString();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof CraftSoundVariant otherVariant)) {
return false;
}
return this.getKey().equals(otherVariant.getKey());
}
@Override
public int hashCode() {
return this.getKey().hashCode();
}
}
}
@@ -1,14 +1,15 @@
package org.bukkit.craftbukkit.generator.structure;
import io.papermc.paper.util.Holderable;
import net.minecraft.core.Holder;
import com.google.common.base.Suppliers;
import java.util.function.Supplier;
import net.minecraft.core.registries.Registries;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.generator.structure.Structure;
import org.bukkit.generator.structure.StructureType;
public class CraftStructure extends Structure implements Holderable<net.minecraft.world.level.levelgen.structure.Structure> {
public class CraftStructure extends Structure implements Handleable<net.minecraft.world.level.levelgen.structure.Structure> {
public static Structure minecraftToBukkit(net.minecraft.world.level.levelgen.structure.Structure minecraft) {
return CraftRegistry.minecraftToBukkit(minecraft, Registries.STRUCTURE);
@@ -18,39 +19,28 @@ public class CraftStructure extends Structure implements Holderable<net.minecraf
return CraftRegistry.bukkitToMinecraft(bukkit);
}
private final Holder<net.minecraft.world.level.levelgen.structure.Structure> holder;
private final NamespacedKey key;
private final net.minecraft.world.level.levelgen.structure.Structure structure;
private final Supplier<StructureType> structureType;
public CraftStructure(Holder<net.minecraft.world.level.levelgen.structure.Structure> holder) {
this.holder = holder;
public CraftStructure(NamespacedKey key, net.minecraft.world.level.levelgen.structure.Structure structure) {
this.key = key;
this.structure = structure;
this.structureType = Suppliers.memoize(() -> CraftStructureType.minecraftToBukkit(structure.type()));
}
@Override
public Holder<net.minecraft.world.level.levelgen.structure.Structure> getHolder() {
return this.holder;
public net.minecraft.world.level.levelgen.structure.Structure getHandle() {
return this.structure;
}
@Override
public StructureType getStructureType() {
return CraftStructureType.minecraftToBukkit(this.getHandle().type());
return this.structureType.get();
}
@Override
public NamespacedKey getKey() {
return Holderable.super.getKey();
}
@Override
public int hashCode() {
return Holderable.super.implHashCode();
}
@Override
public boolean equals(final Object obj) {
return Holderable.super.implEquals(obj);
}
@Override
public String toString() {
return Holderable.super.implToString();
return this.key;
}
}
@@ -1,13 +1,12 @@
package org.bukkit.craftbukkit.generator.structure;
import io.papermc.paper.util.Holderable;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.generator.structure.StructureType;
public class CraftStructureType extends StructureType implements Holderable<net.minecraft.world.level.levelgen.structure.StructureType<?>> {
public class CraftStructureType extends StructureType implements Handleable<net.minecraft.world.level.levelgen.structure.StructureType<?>> {
public static StructureType minecraftToBukkit(net.minecraft.world.level.levelgen.structure.StructureType<?> minecraft) {
return CraftRegistry.minecraftToBukkit(minecraft, Registries.STRUCTURE_TYPE);
@@ -17,34 +16,21 @@ public class CraftStructureType extends StructureType implements Holderable<net.
return CraftRegistry.bukkitToMinecraft(bukkit);
}
private final Holder<net.minecraft.world.level.levelgen.structure.StructureType<?>> holder;
private final NamespacedKey key;
private final net.minecraft.world.level.levelgen.structure.StructureType<?> structureType;
public CraftStructureType(final Holder<net.minecraft.world.level.levelgen.structure.StructureType<?>> holder) {
this.holder = holder;
public CraftStructureType(NamespacedKey key, net.minecraft.world.level.levelgen.structure.StructureType<?> structureType) {
this.key = key;
this.structureType = structureType;
}
@Override
public Holder<net.minecraft.world.level.levelgen.structure.StructureType<?>> getHolder() {
return this.holder;
public net.minecraft.world.level.levelgen.structure.StructureType<?> getHandle() {
return this.structureType;
}
@Override
public NamespacedKey getKey() {
return Holderable.super.getKey();
}
@Override
public int hashCode() {
return Holderable.super.implHashCode();
}
@Override
public boolean equals(final Object obj) {
return Holderable.super.implEquals(obj);
}
@Override
public String toString() {
return Holderable.super.implToString();
return this.key;
}
}
@@ -577,7 +577,7 @@ public final class CraftItemStack extends ItemStack {
}
private <A, V> void setDataInternal(final io.papermc.paper.datacomponent.PaperDataComponentType<A, V> type, final A value) {
this.handle.set(type.getHandle(), type.getAdapter().toVanilla(value, type.getHolder()));
this.handle.set(type.getHandle(), type.getAdapter().toVanilla(value));
}
@Override
@@ -1,15 +1,17 @@
package org.bukkit.craftbukkit.map;
import io.papermc.paper.util.OldEnumHolderable;
import java.util.Locale;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.world.level.saveddata.maps.MapDecorationType;
import org.bukkit.NamespacedKey;
import org.bukkit.craftbukkit.CraftRegistry;
import org.bukkit.craftbukkit.util.Handleable;
import org.bukkit.map.MapCursor;
public final class CraftMapCursor {
public static final class CraftType extends OldEnumHolderable<MapCursor.Type, MapDecorationType> implements MapCursor.Type {
public static final class CraftType implements MapCursor.Type, Handleable<MapDecorationType> {
private static int count = 0;
@@ -18,7 +20,7 @@ public final class CraftMapCursor {
}
public static MapCursor.Type minecraftHolderToBukkit(Holder<MapDecorationType> minecraft) {
return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.MAP_DECORATION_TYPE);
return CraftType.minecraftToBukkit(minecraft.value());
}
public static MapDecorationType bukkitToMinecraft(MapCursor.Type bukkit) {
@@ -29,8 +31,73 @@ public final class CraftMapCursor {
return CraftRegistry.bukkitToMinecraftHolder(bukkit, Registries.MAP_DECORATION_TYPE);
}
public CraftType(final Holder<MapDecorationType> holder) {
super(holder, count++);
private final NamespacedKey key;
private final MapDecorationType mapDecorationType;
private final String name;
private final int ordinal;
public CraftType(NamespacedKey key, MapDecorationType mapDecorationType) {
this.key = key;
this.mapDecorationType = mapDecorationType;
// For backwards compatibility, minecraft values will still return the uppercase name without the namespace,
// in case plugins use for example the name as key in a config file to receive type specific values.
// Custom types will return the key with namespace. For a plugin this should look than like a new type
// (which can always be added in new minecraft versions and the plugin should therefore handle it accordingly).
if (NamespacedKey.MINECRAFT.equals(key.getNamespace())) {
this.name = key.getKey().toUpperCase(Locale.ROOT);
} else {
this.name = key.toString();
}
this.ordinal = CraftType.count++;
}
@Override
public MapDecorationType getHandle() {
return this.mapDecorationType;
}
@Override
public NamespacedKey getKey() {
return this.key;
}
@Override
public int compareTo(MapCursor.Type type) {
return this.ordinal - type.ordinal();
}
@Override
public String name() {
return this.name;
}
@Override
public int ordinal() {
return this.ordinal;
}
@Override
public String toString() {
// For backwards compatibility
return this.name();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (!(other instanceof CraftType)) {
return false;
}
return this.getKey().equals(((MapCursor.Type) other).getKey());
}
@Override
public int hashCode() {
return this.getKey().hashCode();
}
@Override
@@ -86,11 +86,6 @@ public class BlockStateListPopulator extends DummyGeneratorAccess {
return this.world.getMinecraftWorld();
}
@Override
public ServerLevel getLevel() {
return this.getMinecraftWorld();
}
public void refreshTiles() {
for (CraftBlockState snapshot : this.blocks.values()) {
if (snapshot instanceof CraftBlockEntityState) {
@@ -109,7 +109,7 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
logger.log(Level.SEVERE, "------------------------------");
logger.log(Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):"); // Paper
FeatureHooks.dumpAllChunkLoadInfo(MinecraftServer.getServer(), isLongTimeout); // Paper - log detailed tick information
WatchdogThread.dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(MinecraftServer.getServer().serverThread.threadId(), Integer.MAX_VALUE), logger);
WatchdogThread.dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE), logger);
logger.log(Level.SEVERE, "------------------------------");
// Paper start - Only print full dump on long timeouts