More work?
This commit is contained in:
parent
152e82ceec
commit
9e92fed7a2
18 changed files with 158 additions and 172 deletions
24
patches/server/0122-PlayerTeleportEndGatewayEvent.patch
Normal file
24
patches/server/0122-PlayerTeleportEndGatewayEvent.patch
Normal file
|
@ -0,0 +1,24 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 31 Dec 2016 21:44:50 -0500
|
||||
Subject: [PATCH] PlayerTeleportEndGatewayEvent
|
||||
|
||||
Allows you to access the Gateway being used in a teleport event
|
||||
Fix the offset used for player teleportation
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
index 5890aa22912eed9d645393f5a7189d6884fb2c66..b99bd43bf5185bed21fad7dac31baf1a30bdd1fe 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -1455,6 +1455,11 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player {
|
||||
PositionMoveRotation absolutePosition = PositionMoveRotation.calculateAbsolute(PositionMoveRotation.of(this), PositionMoveRotation.of(teleportTarget), teleportTarget.relatives());
|
||||
Location exit = (worldserver == null) ? null : CraftLocation.toBukkit(absolutePosition.position(), worldserver.getWorld(), absolutePosition.yRot(), absolutePosition.xRot());
|
||||
PlayerTeleportEvent tpEvent = new PlayerTeleportEvent(this.getBukkitEntity(), enter, exit, teleportTarget.cause());
|
||||
+ // Paper start - gateway-specific teleport event
|
||||
+ if (this.portalProcess != null && this.portalProcess.isSamePortal(((net.minecraft.world.level.block.EndGatewayBlock) net.minecraft.world.level.block.Blocks.END_GATEWAY)) && this.serverLevel().getBlockEntity(this.portalProcess.getEntryPosition()) instanceof net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity theEndGatewayBlockEntity) {
|
||||
+ tpEvent = new com.destroystokyo.paper.event.player.PlayerTeleportEndGatewayEvent(this.getBukkitEntity(), enter, exit, new org.bukkit.craftbukkit.block.CraftEndGateway(this.serverLevel().getWorld(), theEndGatewayBlockEntity));
|
||||
+ }
|
||||
+ // Paper end - gateway-specific teleport event
|
||||
Bukkit.getServer().getPluginManager().callEvent(tpEvent);
|
||||
Location newExit = tpEvent.getTo();
|
||||
if (tpEvent.isCancelled() || newExit == null) {
|
|
@ -0,0 +1,82 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 7 Jan 2017 15:24:46 -0500
|
||||
Subject: [PATCH] Provide E/TE/Chunk count stat methods
|
||||
|
||||
Provides counts without the ineffeciency of using .getEntities().size()
|
||||
which creates copy of the collections.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index 658ceb9c43bb48f88596cd7270e276a369a3937e..b34663ba24a0925c7fe65b354f4029c51ecc3bd1 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -116,7 +116,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public static final int TICKS_PER_DAY = 24000;
|
||||
public static final int MAX_ENTITY_SPAWN_Y = 20000000;
|
||||
public static final int MIN_ENTITY_SPAWN_Y = -20000000;
|
||||
- protected final List<TickingBlockEntity> blockEntityTickers = Lists.newArrayList();
|
||||
+ public final List<TickingBlockEntity> blockEntityTickers = Lists.newArrayList(); // Paper - public
|
||||
protected final NeighborUpdater neighborUpdater;
|
||||
private final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList();
|
||||
private boolean tickingBlockEntities;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index 274c9cc32d7f65456d184db7f61bc4b159f890f8..8cf4ecc5065ade18f0d13eaf0a786912ecb4dd08 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -168,6 +168,56 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftWorld.DATA_TYPE_REGISTRY);
|
||||
private net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
|
||||
|
||||
+ // Paper start - Provide fast information methods
|
||||
+ @Override
|
||||
+ public int getEntityCount() {
|
||||
+ int ret = 0;
|
||||
+ for (net.minecraft.world.entity.Entity entity : world.getEntities().getAll()) {
|
||||
+ if (entity.isChunkLoaded()) {
|
||||
+ ++ret;
|
||||
+ }
|
||||
+ }
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getTileEntityCount() {
|
||||
+ // We don't use the full world tile entity list, so we must iterate chunks
|
||||
+ int size = 0;
|
||||
+ for (ChunkHolder playerchunk : ca.spottedleaf.moonrise.common.util.ChunkSystem.getVisibleChunkHolders(this.world)) {
|
||||
+ net.minecraft.world.level.chunk.LevelChunk chunk = playerchunk.getTickingChunk();
|
||||
+ if (chunk == null) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ size += chunk.blockEntities.size();
|
||||
+ }
|
||||
+ return size;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getTickableTileEntityCount() {
|
||||
+ return world.blockEntityTickers.size();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getChunkCount() {
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ for (ChunkHolder chunkHolder : ca.spottedleaf.moonrise.common.util.ChunkSystem.getVisibleChunkHolders(this.world)) {
|
||||
+ if (chunkHolder.getTickingChunk() != null) {
|
||||
+ ++ret;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int getPlayerCount() {
|
||||
+ return world.players().size();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
private static final Random rand = new Random();
|
||||
|
||||
public CraftWorld(ServerLevel world, ChunkGenerator gen, BiomeProvider biomeProvider, Environment env) {
|
27
patches/server/0124-Enforce-Sync-Player-Saves.patch
Normal file
27
patches/server/0124-Enforce-Sync-Player-Saves.patch
Normal file
|
@ -0,0 +1,27 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 7 Jan 2017 15:41:58 -0500
|
||||
Subject: [PATCH] Enforce Sync Player Saves
|
||||
|
||||
Saving players async is extremely dangerous. This will force it to main
|
||||
the same way we handle async chunk loads.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 04e25dba87cc1531898bdf9640d6da44ee3bf410..18d4ee1e1fb37848ac6587a0a68785be1851b1e8 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -998,11 +998,13 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public void saveAll() {
|
||||
+ io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main
|
||||
MinecraftTimings.savePlayers.startTiming(); // Paper
|
||||
for (int i = 0; i < this.players.size(); ++i) {
|
||||
- this.save((ServerPlayer) this.players.get(i));
|
||||
+ this.save(this.players.get(i));
|
||||
}
|
||||
MinecraftTimings.savePlayers.stopTiming(); // Paper
|
||||
+ return null; }); // Paper - ensure main
|
||||
}
|
||||
|
||||
public UserWhiteList getWhiteList() {
|
|
@ -0,0 +1,354 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Tue, 19 Dec 2017 16:31:46 -0500
|
||||
Subject: [PATCH] ExperienceOrbs API for Reason/Source/Triggering player
|
||||
|
||||
Adds lots of information about why this orb exists.
|
||||
|
||||
Replaces isFromBottle() with logic that persists entity reloads too.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
index 0de7b8b8d2670c6ec50eb56348ca28a315b961e5..73b6aa34ad2579d79f388c5660cdfbef41a769f2 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -433,7 +433,7 @@ public class ServerPlayerGameMode {
|
||||
|
||||
// Drop event experience
|
||||
if (flag && event != null) {
|
||||
- iblockdata.getBlock().popExperience(this.level, pos, event.getExpToDrop());
|
||||
+ iblockdata.getBlock().popExperience(this.level, pos, event.getExpToDrop(), this.player); // Paper
|
||||
}
|
||||
|
||||
return true;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
|
||||
index 7f3ac3e8631e30c968ef664f994ad208d05eb4a3..b9160ebca0d11dbbf96da5f0f5810d302cfcea9a 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
|
||||
@@ -44,9 +44,63 @@ public class ExperienceOrb extends Entity {
|
||||
public int value;
|
||||
public int count;
|
||||
private Player followingPlayer;
|
||||
+ // Paper start
|
||||
+ @javax.annotation.Nullable
|
||||
+ public java.util.UUID sourceEntityId;
|
||||
+ @javax.annotation.Nullable
|
||||
+ public java.util.UUID triggerEntityId;
|
||||
+ public org.bukkit.entity.ExperienceOrb.SpawnReason spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN;
|
||||
+
|
||||
+ private void loadPaperNBT(CompoundTag tag) {
|
||||
+ if (!tag.contains("Paper.ExpData", net.minecraft.nbt.Tag.TAG_COMPOUND)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ CompoundTag comp = tag.getCompound("Paper.ExpData");
|
||||
+ if (comp.hasUUID("source")) {
|
||||
+ this.sourceEntityId = comp.getUUID("source");
|
||||
+ }
|
||||
+ if (comp.hasUUID("trigger")) {
|
||||
+ this.triggerEntityId = comp.getUUID("trigger");
|
||||
+ }
|
||||
+ if (comp.contains("reason")) {
|
||||
+ String reason = comp.getString("reason");
|
||||
+ try {
|
||||
+ this.spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.valueOf(reason);
|
||||
+ } catch (Exception e) {
|
||||
+ this.level().getCraftServer().getLogger().warning("Invalid spawnReason set for experience orb: " + e.getMessage() + " - " + reason);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ private void savePaperNBT(CompoundTag tag) {
|
||||
+ CompoundTag comp = new CompoundTag();
|
||||
+ if (this.sourceEntityId != null) {
|
||||
+ comp.putUUID("source", this.sourceEntityId);
|
||||
+ }
|
||||
+ if (this.triggerEntityId != null) {
|
||||
+ comp.putUUID("trigger", triggerEntityId);
|
||||
+ }
|
||||
+ if (this.spawnReason != null && this.spawnReason != org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN) {
|
||||
+ comp.putString("reason", this.spawnReason.name());
|
||||
+ }
|
||||
+ tag.put("Paper.ExpData", comp);
|
||||
+ }
|
||||
|
||||
+ @io.papermc.paper.annotation.DoNotUse
|
||||
+ @Deprecated
|
||||
public ExperienceOrb(Level world, double x, double y, double z, int amount) {
|
||||
+ this(world, x, y, z, amount, null, null);
|
||||
+ }
|
||||
+
|
||||
+ public ExperienceOrb(Level world, double x, double y, double z, int amount, @javax.annotation.Nullable org.bukkit.entity.ExperienceOrb.SpawnReason reason, @javax.annotation.Nullable Entity triggerId) {
|
||||
+ this(world, x, y, z, amount, reason, triggerId, null);
|
||||
+ }
|
||||
+
|
||||
+ public ExperienceOrb(Level world, double x, double y, double z, int amount, @javax.annotation.Nullable org.bukkit.entity.ExperienceOrb.SpawnReason reason, @javax.annotation.Nullable Entity triggerId, @javax.annotation.Nullable Entity sourceId) {
|
||||
this(EntityType.EXPERIENCE_ORB, world);
|
||||
+ this.sourceEntityId = sourceId != null ? sourceId.getUUID() : null;
|
||||
+ this.triggerEntityId = triggerId != null ? triggerId.getUUID() : null;
|
||||
+ this.spawnReason = reason != null ? reason : org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN;
|
||||
+ // Paper end
|
||||
this.setPos(x, y, z);
|
||||
this.setYRot((float) (this.random.nextDouble() * 360.0D));
|
||||
this.setDeltaMovement((this.random.nextDouble() * 0.20000000298023224D - 0.10000000149011612D) * 2.0D, this.random.nextDouble() * 0.2D * 2.0D, (this.random.nextDouble() * 0.20000000298023224D - 0.10000000149011612D) * 2.0D);
|
||||
@@ -171,12 +225,20 @@ public class ExperienceOrb extends Entity {
|
||||
}
|
||||
|
||||
public static void award(ServerLevel world, Vec3 pos, int amount) {
|
||||
+ // Paper start - add reasons for orbs
|
||||
+ award(world, pos, amount, null, null, null);
|
||||
+ }
|
||||
+ public static void award(ServerLevel world, Vec3 pos, int amount, org.bukkit.entity.ExperienceOrb.SpawnReason reason, Entity triggerId) {
|
||||
+ award(world, pos, amount, reason, triggerId, null);
|
||||
+ }
|
||||
+ public static void award(ServerLevel world, Vec3 pos, int amount, org.bukkit.entity.ExperienceOrb.SpawnReason reason, Entity triggerId, Entity sourceId) {
|
||||
+ // Paper end - add reasons for orbs
|
||||
while (amount > 0) {
|
||||
int j = ExperienceOrb.getExperienceValue(amount);
|
||||
|
||||
amount -= j;
|
||||
if (!ExperienceOrb.tryMergeToExisting(world, pos, j)) {
|
||||
- world.addFreshEntity(new ExperienceOrb(world, pos.x(), pos.y(), pos.z(), j));
|
||||
+ world.addFreshEntity(new ExperienceOrb(world, pos.x(), pos.y(), pos.z(), j, reason, triggerId, sourceId)); // Paper - add reason
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,6 +311,7 @@ public class ExperienceOrb extends Entity {
|
||||
nbt.putShort("Age", (short) this.age);
|
||||
nbt.putShort("Value", (short) this.value);
|
||||
nbt.putInt("Count", this.count);
|
||||
+ this.savePaperNBT(nbt); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -257,6 +320,7 @@ public class ExperienceOrb extends Entity {
|
||||
this.age = nbt.getShort("Age");
|
||||
this.value = nbt.getShort("Value");
|
||||
this.count = Math.max(nbt.getInt("Count"), 1);
|
||||
+ this.loadPaperNBT(nbt); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 6ea3488a578a7464bd34df265742a777575c9029..237025be183b3cc93920430075edcc0bb2899b68 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -1837,7 +1837,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
protected void dropExperience(ServerLevel world, @Nullable Entity attacker) {
|
||||
// CraftBukkit start - Update getExpReward() above if the removed if() changes!
|
||||
if (!(this instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon)) { // CraftBukkit - SPIGOT-2420: Special case ender dragon will drop the xp over time
|
||||
- ExperienceOrb.award(world, this.position(), this.expToDrop);
|
||||
+ ExperienceOrb.award(world, this.position(), this.expToDrop, this instanceof ServerPlayer ? org.bukkit.entity.ExperienceOrb.SpawnReason.PLAYER_DEATH : org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, attacker, this); // Paper
|
||||
this.expToDrop = 0;
|
||||
}
|
||||
// CraftBukkit end
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Animal.java b/src/main/java/net/minecraft/world/entity/animal/Animal.java
|
||||
index e359bb8e6366b0c695fe3bb14967556a875524f4..775bfac26aaa6db998c2647ec81247b67d0bf784 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Animal.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Animal.java
|
||||
@@ -277,12 +277,14 @@ public abstract class Animal extends AgeableMob {
|
||||
|
||||
public void finalizeSpawnChildFromBreeding(ServerLevel worldserver, Animal entityanimal, @Nullable AgeableMob entityageable, int experience) {
|
||||
// CraftBukkit end
|
||||
- Optional.ofNullable(this.getLoveCause()).or(() -> {
|
||||
- return Optional.ofNullable(entityanimal.getLoveCause());
|
||||
- }).ifPresent((entityplayer) -> {
|
||||
+ // Paper start
|
||||
+ ServerPlayer entityplayer = this.getLoveCause();
|
||||
+ if (entityplayer == null) entityplayer = entityanimal.getLoveCause();
|
||||
+ if (entityplayer != null) {
|
||||
+ // Paper end
|
||||
entityplayer.awardStat(Stats.ANIMALS_BRED);
|
||||
CriteriaTriggers.BRED_ANIMALS.trigger(entityplayer, this, entityanimal, entityageable);
|
||||
- });
|
||||
+ } // Paper
|
||||
this.setAge(6000);
|
||||
entityanimal.setAge(6000);
|
||||
this.resetLove();
|
||||
@@ -291,7 +293,7 @@ public abstract class Animal extends AgeableMob {
|
||||
if (worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
|
||||
// CraftBukkit start - use event experience
|
||||
if (experience > 0) {
|
||||
- worldserver.addFreshEntity(new ExperienceOrb(worldserver, this.getX(), this.getY(), this.getZ(), experience));
|
||||
+ worldserver.addFreshEntity(new ExperienceOrb(worldserver, this.getX(), this.getY(), this.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer, entityageable)); // Paper
|
||||
}
|
||||
// CraftBukkit end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Fox.java b/src/main/java/net/minecraft/world/entity/animal/Fox.java
|
||||
index 258fad440d4d2402a273c761da57130a57202b3c..faffc3a9ed8bc306277cad37bc43af2ef7303493 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Fox.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Fox.java
|
||||
@@ -882,7 +882,7 @@ public class Fox extends Animal implements VariantHolder<Fox.Variant> {
|
||||
if (worldserver.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
|
||||
// CraftBukkit start - use event experience
|
||||
if (experience > 0) {
|
||||
- this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), experience));
|
||||
+ this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer, entityfox)); // Paper
|
||||
}
|
||||
// CraftBukkit end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/animal/Turtle.java b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
index 81982515b7757febb964627e9c5046d52bf5edf5..a2c5042e99a8f4cd45d502320cf1c06e8af0bd0e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/animal/Turtle.java
|
||||
@@ -462,7 +462,7 @@ public class Turtle extends Animal {
|
||||
RandomSource randomsource = this.animal.getRandom();
|
||||
|
||||
if (getServerLevel((Level) this.level).getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
|
||||
- this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), randomsource.nextInt(7) + 1));
|
||||
+ this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), randomsource.nextInt(7) + 1, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer)); // Paper;
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
|
||||
index 95d69e3ca1a9095dfb340e9be0ec322ab6c5eb5e..0012ab1f56180081d210c8836e2a59d543b950b8 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EnderDragon.java
|
||||
@@ -659,7 +659,7 @@ public class EnderDragon extends Mob implements Enemy {
|
||||
|
||||
if (world instanceof ServerLevel worldserver) {
|
||||
if (this.dragonDeathTime > 150 && this.dragonDeathTime % 5 == 0 && true) { // CraftBukkit - SPIGOT-2420: Already checked for the game rule when calculating the xp
|
||||
- ExperienceOrb.award(worldserver, this.position(), Mth.floor((float) short0 * 0.08F));
|
||||
+ ExperienceOrb.award(worldserver, this.position(), Mth.floor((float) short0 * 0.08F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, this.lastHurtByPlayer, this); // Paper
|
||||
}
|
||||
|
||||
if (this.dragonDeathTime == 1 && !this.isSilent()) {
|
||||
@@ -691,7 +691,7 @@ public class EnderDragon extends Mob implements Enemy {
|
||||
if (world instanceof ServerLevel) {
|
||||
ServerLevel worldserver = (ServerLevel) world; // CraftBukkit - decompile error
|
||||
if (true) { // CraftBukkit - SPIGOT-2420: Already checked for the game rule when calculating the xp
|
||||
- ExperienceOrb.award(worldserver, this.position(), Mth.floor((float) short0 * 0.2F));
|
||||
+ ExperienceOrb.award(worldserver, this.position(), Mth.floor((float) short0 * 0.2F), org.bukkit.entity.ExperienceOrb.SpawnReason.ENTITY_DEATH, this.lastHurtByPlayer, this); // Paper
|
||||
}
|
||||
|
||||
if (this.dragonFight != null) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
index 624f06d630b55cdcaa97cb66736b69c7ad45dd83..83bb48891d03534468d61cf7683438b3efb131cf 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
|
||||
@@ -630,7 +630,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
||||
}
|
||||
|
||||
if (offer.shouldRewardExp()) {
|
||||
- this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5D, this.getZ(), i));
|
||||
+ this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5D, this.getZ(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, this.getTradingPlayer(), this)); // Paper
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
|
||||
index 380a876b3cbd660b34dd504cd20f6031b35a613a..8034588a9a87b907c35e28e220280d463f34554e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java
|
||||
@@ -208,7 +208,7 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill
|
||||
if (offer.shouldRewardExp()) {
|
||||
int i = 3 + this.random.nextInt(4);
|
||||
|
||||
- this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5D, this.getZ(), i));
|
||||
+ this.level().addFreshEntity(new ExperienceOrb(this.level(), this.getX(), this.getY() + 0.5D, this.getZ(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.VILLAGER_TRADE, this.getTradingPlayer(), this)); // Paper
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
|
||||
index ed378bc8135c329cb7423da06eb26fff69ee4954..9d24d4c3802c525546dae92530c9c5b3cf77924e 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java
|
||||
@@ -530,7 +530,7 @@ public class FishingHook extends Projectile {
|
||||
this.level().addFreshEntity(entityitem);
|
||||
// CraftBukkit start - this.random.nextInt(6) + 1 -> playerFishEvent.getExpToDrop()
|
||||
if (playerFishEvent.getExpToDrop() > 0) {
|
||||
- entityhuman.level().addFreshEntity(new ExperienceOrb(entityhuman.level(), entityhuman.getX(), entityhuman.getY() + 0.5D, entityhuman.getZ() + 0.5D, playerFishEvent.getExpToDrop()));
|
||||
+ entityhuman.level().addFreshEntity(new ExperienceOrb(entityhuman.level(), entityhuman.getX(), entityhuman.getY() + 0.5D, entityhuman.getZ() + 0.5D, playerFishEvent.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.FISHING, this.getPlayerOwner(), this)); // Paper
|
||||
}
|
||||
// CraftBukkit end
|
||||
if (itemstack1.is(ItemTags.FISHES)) {
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java
|
||||
index 89292bd47e80f7c8bd6a382a44b912a43037b58e..268e46777bdea5b539b0c6833eee08ea8a6c61c2 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownExperienceBottle.java
|
||||
@@ -55,7 +55,7 @@ public class ThrownExperienceBottle extends ThrowableItemProjectile {
|
||||
}
|
||||
// CraftBukkit end
|
||||
|
||||
- ExperienceOrb.award((ServerLevel) this.level(), this.position(), i);
|
||||
+ ExperienceOrb.award((ServerLevel) this.level(), this.position(), i, org.bukkit.entity.ExperienceOrb.SpawnReason.EXP_BOTTLE, this.getOwner(), this); // Paper
|
||||
this.discard(EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
|
||||
index 56d8ed71861b0a47692fde4c5acc97aaba8166da..13bc52bc856031c930370828b0381e43920aabd2 100644
|
||||
--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
|
||||
+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
|
||||
@@ -98,7 +98,7 @@ public class GrindstoneMenu extends AbstractContainerMenu {
|
||||
public void onTake(net.minecraft.world.entity.player.Player player, ItemStack stack) {
|
||||
context.execute((world, blockposition) -> {
|
||||
if (world instanceof ServerLevel) {
|
||||
- ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), this.getExperienceAmount(world));
|
||||
+ ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), this.getExperienceAmount(world), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player); // Paper
|
||||
}
|
||||
|
||||
world.levelEvent(1042, blockposition, 0);
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java
|
||||
index 3cefda12d4c2ca2c4e9ef97eff961a55af164d6b..43c2b411115d3a8a0e47d3e2277789b2667897af 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/Block.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/Block.java
|
||||
@@ -363,8 +363,13 @@ public class Block extends BlockBehaviour implements ItemLike {
|
||||
}
|
||||
|
||||
public void popExperience(ServerLevel world, BlockPos pos, int size) {
|
||||
+ // Paper start - add entity parameter
|
||||
+ popExperience(world, pos, size, null);
|
||||
+ }
|
||||
+ public void popExperience(ServerLevel world, BlockPos pos, int size, net.minecraft.world.entity.Entity entity) {
|
||||
+ // Paper end - add entity parameter
|
||||
if (world.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) {
|
||||
- ExperienceOrb.award(world, Vec3.atCenterOf(pos), size);
|
||||
+ ExperienceOrb.award(world, Vec3.atCenterOf(pos), size, org.bukkit.entity.ExperienceOrb.SpawnReason.BLOCK_BREAK, entity); // Paper
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
|
||||
index bddbb351ef676a86edb5da74a2a656c7da2ecb5d..62c49afd4da165d0cb4156f106e6e5480d267d4e 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java
|
||||
@@ -517,7 +517,7 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit
|
||||
j = event.getExpToDrop();
|
||||
// CraftBukkit end
|
||||
|
||||
- ExperienceOrb.award(worldserver, vec3d, j);
|
||||
+ ExperienceOrb.award(worldserver, vec3d, j, org.bukkit.entity.ExperienceOrb.SpawnReason.FURNACE, entityhuman); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java
|
||||
index 3dc11c82e4ccdb57a5e7510bddc5247869075d3e..1c3aacda9242444c0c7bd92cb391e6fff963bb79 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java
|
||||
@@ -426,7 +426,7 @@ public final class CraftEntityTypes {
|
||||
return item;
|
||||
}));
|
||||
register(new EntityTypeData<>(EntityType.EXPERIENCE_ORB, ExperienceOrb.class, CraftExperienceOrb::new,
|
||||
- spawnData -> new net.minecraft.world.entity.ExperienceOrb(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), 0)
|
||||
+ spawnData -> new net.minecraft.world.entity.ExperienceOrb(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), 0, org.bukkit.entity.ExperienceOrb.SpawnReason.CUSTOM, null, null) // Paper
|
||||
));
|
||||
register(new EntityTypeData<>(EntityType.AREA_EFFECT_CLOUD, AreaEffectCloud.class, CraftAreaEffectCloud::new, spawnData -> new net.minecraft.world.entity.AreaEffectCloud(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z())));
|
||||
register(new EntityTypeData<>(EntityType.EGG, Egg.class, CraftEgg::new, spawnData -> new ThrownEgg(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), new net.minecraft.world.item.ItemStack(Items.EGG))));
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java
|
||||
index 9231511af4cba747594000364f0b8fceeeab4819..5a7d314ec0562e472f5dc45924a7b24841cff126 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftExperienceOrb.java
|
||||
@@ -18,6 +18,18 @@ public class CraftExperienceOrb extends CraftEntity implements ExperienceOrb {
|
||||
this.getHandle().value = value;
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public java.util.UUID getTriggerEntityId() {
|
||||
+ return getHandle().triggerEntityId;
|
||||
+ }
|
||||
+ public java.util.UUID getSourceEntityId() {
|
||||
+ return getHandle().sourceEntityId;
|
||||
+ }
|
||||
+ public SpawnReason getSpawnReason() {
|
||||
+ return getHandle().spawnReason;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public net.minecraft.world.entity.ExperienceOrb getHandle() {
|
||||
return (net.minecraft.world.entity.ExperienceOrb) this.entity;
|
44
patches/server/0126-Cap-Entity-Collisions.patch
Normal file
44
patches/server/0126-Cap-Entity-Collisions.patch
Normal file
|
@ -0,0 +1,44 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 22 Jan 2017 18:07:56 -0500
|
||||
Subject: [PATCH] Cap Entity Collisions
|
||||
|
||||
Limit a single entity to colliding a max of configurable times per tick.
|
||||
This will alleviate issues where living entities are hoarded in 1x1 pens
|
||||
|
||||
This is not tied to the maxEntityCramming rule. Cramming will still apply
|
||||
just as it does in Vanilla, but entity pushing logic will be capped.
|
||||
|
||||
You can set this to 0 to disable collisions.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
index 847fd720f11e89d906430c820bc92afe0454761d..b1b26e7c0f66f0697bcfe9eb045d45f31cd9ab06 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
||||
@@ -404,6 +404,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
public long activatedTick = Integer.MIN_VALUE;
|
||||
public void inactiveTick() { }
|
||||
// Spigot end
|
||||
+ protected int numCollisions = 0; // Paper - Cap entity collisions
|
||||
// Paper start - Entity origin API
|
||||
@javax.annotation.Nullable
|
||||
private org.bukkit.util.Vector origin;
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
index 237025be183b3cc93920430075edcc0bb2899b68..f2f8fbc8a8cf32bcba0ad7ac9b6cdd75468e062a 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -3642,10 +3642,12 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
}
|
||||
|
||||
Iterator iterator1 = list.iterator();
|
||||
+ this.numCollisions = Math.max(0, this.numCollisions - this.level().paperConfig().collisions.maxEntityCollisions); // Paper - Cap entity collisions
|
||||
|
||||
- while (iterator1.hasNext()) {
|
||||
+ while (iterator1.hasNext() && this.numCollisions < this.level().paperConfig().collisions.maxEntityCollisions) { // Paper - Cap entity collisions
|
||||
Entity entity1 = (Entity) iterator1.next();
|
||||
-
|
||||
+ entity1.numCollisions++; // Paper - Cap entity collisions
|
||||
+ this.numCollisions++; // Paper - Cap entity collisions
|
||||
this.doPush(entity1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sun, 5 Feb 2017 00:04:04 -0500
|
||||
Subject: [PATCH] Remove CraftScheduler Async Task Debugger
|
||||
|
||||
I have not once ever seen this system help debug a crash.
|
||||
One report of a suspected memory leak with the system.
|
||||
|
||||
This adds additional overhead to asynchronous task dispatching
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
index 22ddc74d85efb4e80e6f06acdf93341a122804fc..0e7f402a7b841c5f6f5a4b699b7bb3d9f46b1af6 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
@@ -433,7 +433,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
}
|
||||
this.parsePending();
|
||||
} else {
|
||||
- this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(this.currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass()));
|
||||
+ // this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(this.currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass())); // Paper
|
||||
this.executor.execute(new com.destroystokyo.paper.ServerSchedulerReportingWrapper(task)); // Paper
|
||||
// We don't need to parse pending
|
||||
// (async tasks must live with race-conditions if they attempt to cancel between these few lines of code)
|
||||
@@ -450,7 +450,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
this.pending.addAll(temp);
|
||||
temp.clear();
|
||||
MinecraftTimings.bukkitSchedulerFinishTimer.stopTiming(); // Paper
|
||||
- this.debugHead = this.debugHead.getNextHead(this.currentTick);
|
||||
+ //this.debugHead = this.debugHead.getNextHead(this.currentTick); // Paper
|
||||
}
|
||||
|
||||
private void addTask(final CraftTask task) {
|
||||
@@ -514,10 +514,15 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
+ // Paper start
|
||||
+ return "";
|
||||
+ /*
|
||||
int debugTick = this.currentTick;
|
||||
StringBuilder string = new StringBuilder("Recent tasks from ").append(debugTick - CraftScheduler.RECENT_TICKS).append('-').append(debugTick).append('{');
|
||||
this.debugHead.debugTo(string);
|
||||
return string.append('}').toString();
|
||||
+ */
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
@Deprecated
|
|
@ -0,0 +1,290 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||
Date: Fri, 12 May 2017 23:34:11 -0500
|
||||
Subject: [PATCH] Properly handle async calls to restart the server
|
||||
|
||||
The watchdog thread calls the server restart function asynchronously. Prior to
|
||||
this change, it attempted to do several non-safe operations from the watchdog
|
||||
thread, rather than the main. Specifically, because of a separate upstream change,
|
||||
it causes player entities to be ticked asynchronously, among other things.
|
||||
|
||||
This is dangerous.
|
||||
|
||||
This patch moves the old handling into a synchronous variant, for calls from the
|
||||
restart command, and adds separate handling for async calls, such as those from
|
||||
the watchdog thread.
|
||||
|
||||
When calling from the watchdog thread, we cannot assume the main thread is in a
|
||||
tickable state; it may be completely deadlocked. In order to handle this, we mark
|
||||
the server as stopping, in order to account for situations where the server should
|
||||
complete a tick reasonbly soon, i.e. 99% of cases.
|
||||
|
||||
Should the server not enter a state where it is stopping within 10 seconds, We
|
||||
will assume that the server has in fact deadlocked and will proceed to force
|
||||
kill the server.
|
||||
|
||||
This modification does not force restart the server should we actually enter a
|
||||
deadlocked state where the server is stopping, whereas this will in most cases
|
||||
exit within a reasonable amount of time, to put a fixed limit on a process that
|
||||
will have plugins and worlds saving to the disk has a high potential to result
|
||||
in corruption/dataloss.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
index 23bf747bf268bd1100d8eadb81751ce72ef927ed..835bbd873ec04954024ae8649e6bc9a4557b11c5 100644
|
||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
||||
@@ -248,6 +248,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
private Map<ResourceKey<Level>, ServerLevel> levels;
|
||||
private PlayerList playerList;
|
||||
private volatile boolean running;
|
||||
+ private volatile boolean isRestarting = false; // Paper - flag to signify we're attempting to restart
|
||||
private boolean stopped;
|
||||
private int tickCount;
|
||||
private int ticksUntilAutosave;
|
||||
@@ -953,7 +954,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
if (this.playerList != null) {
|
||||
MinecraftServer.LOGGER.info("Saving players");
|
||||
this.playerList.saveAll();
|
||||
- this.playerList.removeAll();
|
||||
+ this.playerList.removeAll(this.isRestarting); // Paper
|
||||
try { Thread.sleep(100); } catch (InterruptedException ex) {} // CraftBukkit - SPIGOT-625 - give server at least a chance to send packets
|
||||
}
|
||||
|
||||
@@ -1033,6 +1034,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
public void halt(boolean waitForShutdown) {
|
||||
+ // Paper start - allow passing of the intent to restart
|
||||
+ this.safeShutdown(waitForShutdown, false);
|
||||
+ }
|
||||
+ public void safeShutdown(boolean waitForShutdown, boolean isRestarting) {
|
||||
+ this.isRestarting = isRestarting;
|
||||
+ // Paper end
|
||||
this.running = false;
|
||||
if (waitForShutdown) {
|
||||
try {
|
||||
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
index 18d4ee1e1fb37848ac6587a0a68785be1851b1e8..0a63e32b4e51500dd808ad2360d0521bf9632180 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
|
||||
@@ -1112,8 +1112,15 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public void removeAll() {
|
||||
+ // Paper start - Extract method to allow for restarting flag
|
||||
+ this.removeAll(false);
|
||||
+ }
|
||||
+
|
||||
+ public void removeAll(boolean isRestarting) {
|
||||
+ // Paper end
|
||||
// CraftBukkit start - disconnect safely
|
||||
for (ServerPlayer player : this.players) {
|
||||
+ if (isRestarting) player.connection.disconnect(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.restartMessage)); else // Paper
|
||||
player.connection.disconnect(java.util.Objects.requireNonNullElseGet(this.server.server.shutdownMessage(), net.kyori.adventure.text.Component::empty)); // CraftBukkit - add custom shutdown message // Paper - Adventure
|
||||
}
|
||||
// CraftBukkit end
|
||||
diff --git a/src/main/java/org/spigotmc/RestartCommand.java b/src/main/java/org/spigotmc/RestartCommand.java
|
||||
index de8c703803bcd074f765a44cabc7c635176b716d..824c4ad135ea5177f416687c7042639ed126b70b 100644
|
||||
--- a/src/main/java/org/spigotmc/RestartCommand.java
|
||||
+++ b/src/main/java/org/spigotmc/RestartCommand.java
|
||||
@@ -46,86 +46,134 @@ public class RestartCommand extends Command
|
||||
AsyncCatcher.enabled = false; // Disable async catcher incase it interferes with us
|
||||
try
|
||||
{
|
||||
- String[] split = restartScript.split( " " );
|
||||
- if ( split.length > 0 && new File( split[0] ).isFile() )
|
||||
+ // Paper - extract method and cleanup
|
||||
+ boolean isRestarting = addShutdownHook( restartScript );
|
||||
+ if ( isRestarting )
|
||||
{
|
||||
- System.out.println( "Attempting to restart with " + restartScript );
|
||||
+ System.out.println( "Attempting to restart with " + SpigotConfig.restartScript );
|
||||
+ } else
|
||||
+ {
|
||||
+ System.out.println( "Startup script '" + SpigotConfig.restartScript + "' does not exist! Stopping server." );
|
||||
+ }
|
||||
+ // Stop the watchdog
|
||||
+ WatchdogThread.doStop();
|
||||
|
||||
- // Disable Watchdog
|
||||
- WatchdogThread.doStop();
|
||||
+ shutdownServer( isRestarting );
|
||||
+ // Paper end
|
||||
+ } catch ( Exception ex )
|
||||
+ {
|
||||
+ ex.printStackTrace();
|
||||
+ }
|
||||
+ }
|
||||
|
||||
- // Kick all players
|
||||
- for ( ServerPlayer p : (List<ServerPlayer>) MinecraftServer.getServer().getPlayerList().players )
|
||||
- {
|
||||
- p.connection.disconnect( CraftChatMessage.fromStringOrEmpty( SpigotConfig.restartMessage, true ) );
|
||||
- }
|
||||
- // Give the socket a chance to send the packets
|
||||
- try
|
||||
- {
|
||||
- Thread.sleep( 100 );
|
||||
- } catch ( InterruptedException ex )
|
||||
- {
|
||||
- }
|
||||
- // Close the socket so we can rebind with the new process
|
||||
- MinecraftServer.getServer().getConnection().stop();
|
||||
+ // Paper start - sync copied from above with minor changes, async added
|
||||
+ private static void shutdownServer(boolean isRestarting)
|
||||
+ {
|
||||
+ if ( MinecraftServer.getServer().isSameThread() )
|
||||
+ {
|
||||
+ // Kick all players
|
||||
+ for ( ServerPlayer p : com.google.common.collect.ImmutableList.copyOf( MinecraftServer.getServer().getPlayerList().players ) )
|
||||
+ {
|
||||
+ p.connection.disconnect( CraftChatMessage.fromStringOrEmpty( SpigotConfig.restartMessage, true ) );
|
||||
+ }
|
||||
+ // Give the socket a chance to send the packets
|
||||
+ try
|
||||
+ {
|
||||
+ Thread.sleep( 100 );
|
||||
+ } catch ( InterruptedException ex )
|
||||
+ {
|
||||
+ }
|
||||
|
||||
- // Give time for it to kick in
|
||||
- try
|
||||
- {
|
||||
- Thread.sleep( 100 );
|
||||
- } catch ( InterruptedException ex )
|
||||
- {
|
||||
- }
|
||||
+ closeSocket();
|
||||
|
||||
- // Actually shutdown
|
||||
- try
|
||||
- {
|
||||
- MinecraftServer.getServer().close();
|
||||
- } catch ( Throwable t )
|
||||
- {
|
||||
- }
|
||||
+ // Actually shutdown
|
||||
+ try
|
||||
+ {
|
||||
+ MinecraftServer.getServer().close(); // calls stop()
|
||||
+ } catch ( Throwable t )
|
||||
+ {
|
||||
+ }
|
||||
+
|
||||
+ // Actually stop the JVM
|
||||
+ System.exit( 0 );
|
||||
|
||||
- // This will be done AFTER the server has completely halted
|
||||
- Thread shutdownHook = new Thread()
|
||||
+ } else
|
||||
+ {
|
||||
+ // Mark the server to shutdown at the end of the tick
|
||||
+ MinecraftServer.getServer().safeShutdown( false, isRestarting );
|
||||
+
|
||||
+ // wait 10 seconds to see if we're actually going to try shutdown
|
||||
+ try
|
||||
+ {
|
||||
+ Thread.sleep( 10000 );
|
||||
+ }
|
||||
+ catch (InterruptedException ignored)
|
||||
+ {
|
||||
+ }
|
||||
+
|
||||
+ // Check if we've actually hit a state where the server is going to safely shutdown
|
||||
+ // if we have, let the server stop as usual
|
||||
+ if (MinecraftServer.getServer().isStopped()) return;
|
||||
+
|
||||
+ // If the server hasn't stopped by now, assume worse case and kill
|
||||
+ closeSocket();
|
||||
+ System.exit( 0 );
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
+ // Paper - Split from moved code
|
||||
+ private static void closeSocket()
|
||||
+ {
|
||||
+ // Close the socket so we can rebind with the new process
|
||||
+ MinecraftServer.getServer().getConnection().stop();
|
||||
+
|
||||
+ // Give time for it to kick in
|
||||
+ try
|
||||
+ {
|
||||
+ Thread.sleep( 100 );
|
||||
+ } catch ( InterruptedException ex )
|
||||
+ {
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
+ // Paper start - copied from above and modified to return if the hook registered
|
||||
+ private static boolean addShutdownHook(String restartScript)
|
||||
+ {
|
||||
+ String[] split = restartScript.split( " " );
|
||||
+ if ( split.length > 0 && new File( split[0] ).isFile() )
|
||||
+ {
|
||||
+ Thread shutdownHook = new Thread()
|
||||
+ {
|
||||
+ @Override
|
||||
+ public void run()
|
||||
{
|
||||
- @Override
|
||||
- public void run()
|
||||
+ try
|
||||
{
|
||||
- try
|
||||
+ String os = System.getProperty( "os.name" ).toLowerCase(java.util.Locale.ENGLISH);
|
||||
+ if ( os.contains( "win" ) )
|
||||
{
|
||||
- String os = System.getProperty( "os.name" ).toLowerCase(java.util.Locale.ENGLISH);
|
||||
- if ( os.contains( "win" ) )
|
||||
- {
|
||||
- Runtime.getRuntime().exec( "cmd /c start " + restartScript );
|
||||
- } else
|
||||
- {
|
||||
- Runtime.getRuntime().exec( "sh " + restartScript );
|
||||
- }
|
||||
- } catch ( Exception e )
|
||||
+ Runtime.getRuntime().exec( "cmd /c start " + restartScript );
|
||||
+ } else
|
||||
{
|
||||
- e.printStackTrace();
|
||||
+ Runtime.getRuntime().exec( "sh " + restartScript );
|
||||
}
|
||||
+ } catch ( Exception e )
|
||||
+ {
|
||||
+ e.printStackTrace();
|
||||
}
|
||||
- };
|
||||
-
|
||||
- shutdownHook.setDaemon( true );
|
||||
- Runtime.getRuntime().addShutdownHook( shutdownHook );
|
||||
- } else
|
||||
- {
|
||||
- System.out.println( "Startup script '" + SpigotConfig.restartScript + "' does not exist! Stopping server." );
|
||||
-
|
||||
- // Actually shutdown
|
||||
- try
|
||||
- {
|
||||
- MinecraftServer.getServer().close();
|
||||
- } catch ( Throwable t )
|
||||
- {
|
||||
}
|
||||
- }
|
||||
- System.exit( 0 );
|
||||
- } catch ( Exception ex )
|
||||
+ };
|
||||
+
|
||||
+ shutdownHook.setDaemon( true );
|
||||
+ Runtime.getRuntime().addShutdownHook( shutdownHook );
|
||||
+ return true;
|
||||
+ } else
|
||||
{
|
||||
- ex.printStackTrace();
|
||||
+ return false;
|
||||
}
|
||||
}
|
||||
+ // Paper end
|
||||
+
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Zach Brown <zach.brown@destroystokyo.com>
|
||||
Date: Tue, 16 May 2017 21:29:08 -0500
|
||||
Subject: [PATCH] Add option to make parrots stay on shoulders despite movement
|
||||
|
||||
Makes parrots not fall off whenever the player changes height, or touches water, or gets hit by a passing leaf.
|
||||
Instead, switches the behavior so that players have to sneak to make the birds leave.
|
||||
|
||||
I suspect Mojang may switch to this behavior before full release.
|
||||
|
||||
To be converted into a Paper-API event at some point in the future?
|
||||
|
||||
== AT ==
|
||||
public net.minecraft.world.entity.player.Player removeEntitiesOnShoulder()V
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 9289df9663a2dfbc28c2c6dd8c31bf516a6229ae..2cc5663878a7c0f4b4d5f4b9a0f69de2326bf415 100644
|
||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -2268,6 +2268,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
||||
switch (packet.getAction()) {
|
||||
case PRESS_SHIFT_KEY:
|
||||
this.player.setShiftKeyDown(true);
|
||||
+
|
||||
+ // Paper start - Add option to make parrots stay
|
||||
+ if (this.player.level().paperConfig().entities.behavior.parrotsAreUnaffectedByPlayerMovement) {
|
||||
+ this.player.removeEntitiesOnShoulder();
|
||||
+ }
|
||||
+ // Paper end - Add option to make parrots stay
|
||||
+
|
||||
break;
|
||||
case RELEASE_SHIFT_KEY:
|
||||
this.player.setShiftKeyDown(false);
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
index b953b8e7e184c0c0eb7231564ad120765d66823a..fb6b7be09fffbb9ffefba3f0c0c97b0f90ff6a94 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
@@ -617,6 +617,7 @@ public abstract class Player extends LivingEntity {
|
||||
this.playShoulderEntityAmbientSound(this.getShoulderEntityLeft());
|
||||
this.playShoulderEntityAmbientSound(this.getShoulderEntityRight());
|
||||
if (!this.level().isClientSide && (this.fallDistance > 0.5F || this.isInWater()) || this.abilities.flying || this.isSleeping() || this.isInPowderSnow) {
|
||||
+ if (!this.level().paperConfig().entities.behavior.parrotsAreUnaffectedByPlayerMovement) // Paper - Add option to make parrots stay
|
||||
this.removeEntitiesOnShoulder();
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: kashike <kashike@vq.lc>
|
||||
Date: Fri, 9 Jun 2017 07:24:34 -0700
|
||||
Subject: [PATCH] Add configuration option to prevent player names from being
|
||||
suggested
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 1f028c40dbe159f836e255ec52287903bca9fab8..271f299823495fd92c49a1fbb04e1daa501fafb0 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -2854,5 +2854,10 @@ public final class CraftServer implements Server {
|
||||
commandMap.registerServerAliases();
|
||||
return true;
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean suggestPlayerNamesWhenNullTabCompletions() {
|
||||
+ return io.papermc.paper.configuration.GlobalConfiguration.get().commands.suggestPlayerNamesWhenNullTabCompletions;
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shane Freeder <theboyetronic@gmail.com>
|
||||
Date: Sun, 11 Jun 2017 21:01:18 +0100
|
||||
Subject: [PATCH] provide a configurable option to disable creeper lingering
|
||||
effect spawns
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Creeper.java b/src/main/java/net/minecraft/world/entity/monster/Creeper.java
|
||||
index 71ea942d663a15a45c97b9b6d5c7519ec5a828d7..31405c3a95e8e8217a6efede1e4599c14583081f 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/monster/Creeper.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Creeper.java
|
||||
@@ -287,7 +287,7 @@ public class Creeper extends Monster {
|
||||
private void spawnLingeringCloud() {
|
||||
Collection<MobEffectInstance> collection = this.getActiveEffects();
|
||||
|
||||
- if (!collection.isEmpty()) {
|
||||
+ if (!collection.isEmpty() && !this.level().paperConfig().entities.behavior.disableCreeperLingeringEffect) { // Paper - Option to disable creeper lingering effect
|
||||
AreaEffectCloud entityareaeffectcloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ());
|
||||
|
||||
entityareaeffectcloud.setOwner(this); // CraftBukkit
|
57
patches/server/0132-Item-canEntityPickup.patch
Normal file
57
patches/server/0132-Item-canEntityPickup.patch
Normal file
|
@ -0,0 +1,57 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Fri, 5 May 2017 03:57:17 -0500
|
||||
Subject: [PATCH] Item#canEntityPickup
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
index 03d289abc30927793aa00f6758ed9db6fb765999..51381c32c8650400331a122a4b6c8d95c9d0632b 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/Mob.java
|
||||
@@ -672,6 +672,11 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
ItemEntity entityitem = (ItemEntity) iterator.next();
|
||||
|
||||
if (!entityitem.isRemoved() && !entityitem.getItem().isEmpty() && !entityitem.hasPickUpDelay() && this.wantsToPickUp(worldserver, entityitem.getItem())) {
|
||||
+ // Paper start - Item#canEntityPickup
|
||||
+ if (!entityitem.canMobPickup) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ // Paper end - Item#canEntityPickup
|
||||
this.pickUpItem(worldserver, entityitem);
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index c1859488af5a3a5c7a5a70e6789b40ee44e1d01e..95d43e451f3343a9a9488b23695908235b55d6c5 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -60,6 +60,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
public UUID target;
|
||||
public final float bobOffs;
|
||||
private int lastTick = MinecraftServer.currentTick - 1; // CraftBukkit
|
||||
+ public boolean canMobPickup = true; // Paper - Item#canEntityPickup
|
||||
|
||||
public ItemEntity(EntityType<? extends ItemEntity> type, Level world) {
|
||||
super(type, world);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
|
||||
index fb3738f4c558796f41e3327dd41b8aec68007a8a..5620a0849fda49313c68edfd747fedd09641a3d5 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java
|
||||
@@ -63,6 +63,18 @@ public class CraftItem extends CraftEntity implements Item {
|
||||
}
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public boolean canMobPickup() {
|
||||
+ return this.getHandle().canMobPickup;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setCanMobPickup(boolean canMobPickup) {
|
||||
+ this.getHandle().canMobPickup = canMobPickup;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public void setOwner(UUID uuid) {
|
||||
this.getHandle().setTarget(uuid);
|
|
@ -0,0 +1,41 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 7 May 2017 06:26:09 -0500
|
||||
Subject: [PATCH] PlayerPickupItemEvent#setFlyAtPlayer
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index 95d43e451f3343a9a9488b23695908235b55d6c5..92b52ccca3ec7aaab1ffcdc1b85bf6b3e507087f 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -452,6 +452,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
// CraftBukkit start - fire PlayerPickupItemEvent
|
||||
int canHold = player.getInventory().canHold(itemstack);
|
||||
int remaining = i - canHold;
|
||||
+ boolean flyAtPlayer = false; // Paper
|
||||
|
||||
if (this.pickupDelay <= 0 && canHold > 0) {
|
||||
itemstack.setCount(canHold);
|
||||
@@ -459,8 +460,14 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
PlayerPickupItemEvent playerEvent = new PlayerPickupItemEvent((Player) player.getBukkitEntity(), (org.bukkit.entity.Item) this.getBukkitEntity(), remaining);
|
||||
playerEvent.setCancelled(!playerEvent.getPlayer().getCanPickupItems());
|
||||
this.level().getCraftServer().getPluginManager().callEvent(playerEvent);
|
||||
+ flyAtPlayer = playerEvent.getFlyAtPlayer(); // Paper
|
||||
if (playerEvent.isCancelled()) {
|
||||
itemstack.setCount(i); // SPIGOT-5294 - restore count
|
||||
+ // Paper start
|
||||
+ if (flyAtPlayer) {
|
||||
+ player.take(this, i);
|
||||
+ }
|
||||
+ // Paper end
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -490,6 +497,7 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
// CraftBukkit end
|
||||
|
||||
if (this.pickupDelay == 0 && (this.target == null || this.target.equals(player.getUUID())) && player.getInventory().add(itemstack)) {
|
||||
+ if (flyAtPlayer) // Paper - PlayerPickupItemEvent
|
||||
player.take(this, i);
|
||||
if (itemstack.isEmpty()) {
|
||||
this.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause
|
41
patches/server/0134-PlayerAttemptPickupItemEvent.patch
Normal file
41
patches/server/0134-PlayerAttemptPickupItemEvent.patch
Normal file
|
@ -0,0 +1,41 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: BillyGalbreath <Blake.Galbreath@GMail.com>
|
||||
Date: Sun, 11 Jun 2017 16:30:30 -0500
|
||||
Subject: [PATCH] PlayerAttemptPickupItemEvent
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index 92b52ccca3ec7aaab1ffcdc1b85bf6b3e507087f..75ebf09777e19645eee296a9edabac39c858ffb9 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -40,6 +40,7 @@ import org.bukkit.event.entity.EntityPickupItemEvent;
|
||||
import org.bukkit.event.entity.EntityRemoveEvent;
|
||||
import org.bukkit.event.player.PlayerPickupItemEvent;
|
||||
// CraftBukkit end
|
||||
+import org.bukkit.event.player.PlayerAttemptPickupItemEvent; // Paper
|
||||
|
||||
public class ItemEntity extends Entity implements TraceableEntity {
|
||||
|
||||
@@ -454,6 +455,22 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
int remaining = i - canHold;
|
||||
boolean flyAtPlayer = false; // Paper
|
||||
|
||||
+ // Paper start - PlayerAttemptPickupItemEvent
|
||||
+ if (this.pickupDelay <= 0) {
|
||||
+ PlayerAttemptPickupItemEvent attemptEvent = new PlayerAttemptPickupItemEvent((org.bukkit.entity.Player) player.getBukkitEntity(), (org.bukkit.entity.Item) this.getBukkitEntity(), remaining);
|
||||
+ this.level().getCraftServer().getPluginManager().callEvent(attemptEvent);
|
||||
+
|
||||
+ flyAtPlayer = attemptEvent.getFlyAtPlayer();
|
||||
+ if (attemptEvent.isCancelled()) {
|
||||
+ if (flyAtPlayer) {
|
||||
+ player.take(this, i);
|
||||
+ }
|
||||
+
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - PlayerAttemptPickupItemEvent
|
||||
+
|
||||
if (this.pickupDelay <= 0 && canHold > 0) {
|
||||
itemstack.setCount(canHold);
|
||||
// Call legacy event
|
|
@ -0,0 +1,77 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Sun, 8 Aug 2021 16:26:46 -0700
|
||||
Subject: [PATCH] Do not submit profile lookups to worldgen threads
|
||||
|
||||
They block. On network I/O.
|
||||
|
||||
If enough tasks are submitted the server will eventually stall
|
||||
out due to a sync load, as the worldgen threads will be
|
||||
stalling on profile lookups.
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
|
||||
index 5d0ef11671beb2381e0e1959f5e5f845789a2982..b87d3ac2700eedb492bd55a631c60630c2f9c96c 100644
|
||||
--- a/src/main/java/net/minecraft/Util.java
|
||||
+++ b/src/main/java/net/minecraft/Util.java
|
||||
@@ -95,6 +95,22 @@ public class Util {
|
||||
private static final TracingExecutor BACKGROUND_EXECUTOR = makeExecutor("Main");
|
||||
private static final TracingExecutor IO_POOL = makeIoExecutor("IO-Worker-", false);
|
||||
private static final TracingExecutor DOWNLOAD_POOL = makeIoExecutor("Download-", true);
|
||||
+ // Paper start - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
|
||||
+ public static final ExecutorService PROFILE_EXECUTOR = Executors.newFixedThreadPool(2, new java.util.concurrent.ThreadFactory() {
|
||||
+
|
||||
+ private final AtomicInteger count = new AtomicInteger();
|
||||
+
|
||||
+ @Override
|
||||
+ public Thread newThread(Runnable run) {
|
||||
+ Thread ret = new Thread(run);
|
||||
+ ret.setName("Profile Lookup Executor #" + this.count.getAndIncrement());
|
||||
+ ret.setUncaughtExceptionHandler((Thread thread, Throwable throwable) -> {
|
||||
+ LOGGER.error("Uncaught exception in thread " + thread.getName(), throwable);
|
||||
+ });
|
||||
+ return ret;
|
||||
+ }
|
||||
+ });
|
||||
+ // Paper end - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
|
||||
private static final DateTimeFormatter FILENAME_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss", Locale.ROOT);
|
||||
public static final int LINEAR_LOOKUP_THRESHOLD = 8;
|
||||
private static final Set<String> ALLOWED_UNTRUSTED_LINK_PROTOCOLS = Set.of("http", "https");
|
||||
diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java
|
||||
index c89f4a885982f06823886c81fd386b8de029a3dd..416b26c2ab62b29d640169166980e398d5824b14 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/GameProfileCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java
|
||||
@@ -169,7 +169,7 @@ public class GameProfileCache {
|
||||
} else {
|
||||
CompletableFuture<Optional<GameProfile>> completablefuture1 = CompletableFuture.supplyAsync(() -> {
|
||||
return this.get(username);
|
||||
- }, Util.backgroundExecutor().forName("getProfile")).whenCompleteAsync((optional, throwable) -> {
|
||||
+ }, Util.PROFILE_EXECUTOR).whenCompleteAsync((optional, throwable) -> { // Paper - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
|
||||
this.requests.remove(username);
|
||||
}, this.executor);
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java
|
||||
index 59187889db52ccb132460b0e937d0bd5cbeb77f4..4b7176779c455a876419a497a8178163a68553fc 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/entity/SkullBlockEntity.java
|
||||
@@ -105,7 +105,7 @@ public class SkullBlockEntity extends BlockEntity {
|
||||
ProfileResult profileResult = apiServices.sessionService().fetchProfile(uuid, true);
|
||||
return Optional.ofNullable(profileResult).map(ProfileResult::profile);
|
||||
}
|
||||
- }, Util.backgroundExecutor().forName("fetchProfile"));
|
||||
+ }, Util.PROFILE_EXECUTOR); // Paper - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java
|
||||
index 26a7c2d37e6a8284ab444a9edad967bdcad1e5a3..210fdad5f2041368fc359b275f1cbf05b70b6989 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java
|
||||
@@ -161,7 +161,7 @@ public final class CraftPlayerProfile implements PlayerProfile {
|
||||
|
||||
@Override
|
||||
public CompletableFuture<PlayerProfile> update() {
|
||||
- return CompletableFuture.supplyAsync(this::getUpdatedProfile, Util.backgroundExecutor());
|
||||
+ return CompletableFuture.supplyAsync(this::getUpdatedProfile, Util.PROFILE_EXECUTOR); // Paper - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
|
||||
}
|
||||
|
||||
private CraftPlayerProfile getUpdatedProfile() {
|
767
patches/server/0136-Basic-PlayerProfile-API.patch
Normal file
767
patches/server/0136-Basic-PlayerProfile-API.patch
Normal file
|
@ -0,0 +1,767 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Mon, 15 Jan 2018 22:11:48 -0500
|
||||
Subject: [PATCH] Basic PlayerProfile API
|
||||
|
||||
Establishes base extension of profile systems for future edits too
|
||||
|
||||
== AT ==
|
||||
public org.bukkit.craftbukkit.profile.CraftProfileProperty
|
||||
public org.bukkit.craftbukkit.profile.CraftPlayerTextures
|
||||
public org.bukkit.craftbukkit.profile.CraftPlayerTextures copyFrom(Lorg/bukkit/profile/PlayerTextures;)V
|
||||
public org.bukkit.craftbukkit.profile.CraftPlayerTextures rebuildPropertyIfDirty()V
|
||||
public org.bukkit.craftbukkit.profile.CraftPlayerProfile toString(Lcom/mojang/authlib/properties/PropertyMap;)Ljava/lang/String;
|
||||
public org.bukkit.craftbukkit.profile.CraftPlayerProfile getProperty(Ljava/lang/String;)Lcom/mojang/authlib/properties/Property;
|
||||
public org.bukkit.craftbukkit.profile.CraftPlayerProfile setProperty(Ljava/lang/String;Lcom/mojang/authlib/properties/Property;)V
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java b/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..8849862b45ccbbc635a1c316e9870bca81e55c04
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java
|
||||
@@ -0,0 +1,451 @@
|
||||
+package com.destroystokyo.paper.profile;
|
||||
+
|
||||
+import com.google.common.base.Preconditions;
|
||||
+import com.mojang.authlib.yggdrasil.ProfileResult;
|
||||
+import io.papermc.paper.configuration.GlobalConfiguration;
|
||||
+import com.google.common.base.Charsets;
|
||||
+import com.google.common.collect.Iterables;
|
||||
+import com.mojang.authlib.GameProfile;
|
||||
+import com.mojang.authlib.properties.Property;
|
||||
+import com.mojang.authlib.properties.PropertyMap;
|
||||
+import net.minecraft.Util;
|
||||
+import net.minecraft.server.MinecraftServer;
|
||||
+import net.minecraft.server.players.GameProfileCache;
|
||||
+import net.minecraft.util.StringUtil;
|
||||
+import net.minecraft.world.item.component.ResolvableProfile;
|
||||
+import org.apache.commons.lang3.StringUtils;
|
||||
+import org.apache.commons.lang3.Validate;
|
||||
+import org.bukkit.configuration.serialization.SerializableAs;
|
||||
+import org.bukkit.craftbukkit.configuration.ConfigSerializationUtil;
|
||||
+import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
+import org.bukkit.craftbukkit.profile.CraftPlayerTextures;
|
||||
+import org.bukkit.craftbukkit.profile.CraftProfileProperty;
|
||||
+import org.bukkit.profile.PlayerTextures;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+
|
||||
+import javax.annotation.Nonnull;
|
||||
+import javax.annotation.Nullable;
|
||||
+import java.util.*;
|
||||
+import java.util.concurrent.CompletableFuture;
|
||||
+
|
||||
+@SerializableAs("PlayerProfile")
|
||||
+public class CraftPlayerProfile implements PlayerProfile, SharedPlayerProfile {
|
||||
+
|
||||
+ private boolean emptyName;
|
||||
+ private boolean emptyUUID;
|
||||
+ private GameProfile profile;
|
||||
+ private final PropertySet properties = new PropertySet();
|
||||
+
|
||||
+ public CraftPlayerProfile(CraftPlayer player) {
|
||||
+ this.profile = player.getHandle().getGameProfile();
|
||||
+ }
|
||||
+
|
||||
+ public CraftPlayerProfile(UUID id, String name) {
|
||||
+ this.profile = createAuthLibProfile(id, name);
|
||||
+ this.emptyName = name == null;
|
||||
+ this.emptyUUID = id == null;
|
||||
+ }
|
||||
+
|
||||
+ public CraftPlayerProfile(GameProfile profile) {
|
||||
+ Validate.notNull(profile, "GameProfile cannot be null!");
|
||||
+ this.profile = profile;
|
||||
+ }
|
||||
+
|
||||
+ public CraftPlayerProfile(ResolvableProfile resolvableProfile) {
|
||||
+ this(resolvableProfile.id().orElse(null), resolvableProfile.name().orElse(null));
|
||||
+ copyProfileProperties(resolvableProfile.gameProfile(), this.profile);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasProperty(String property) {
|
||||
+ return profile.getProperties().containsKey(property);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setProperty(ProfileProperty property) {
|
||||
+ String name = property.getName();
|
||||
+ PropertyMap properties = profile.getProperties();
|
||||
+ properties.removeAll(name);
|
||||
+
|
||||
+ Preconditions.checkArgument(properties.size() < 16, "Cannot add more than 16 properties to a profile");
|
||||
+ properties.put(name, new Property(name, property.getValue(), property.getSignature()));
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public CraftPlayerTextures getTextures() {
|
||||
+ return new CraftPlayerTextures(this);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setTextures(@Nullable PlayerTextures textures) {
|
||||
+ if (textures == null) {
|
||||
+ this.removeProperty("textures");
|
||||
+ } else {
|
||||
+ CraftPlayerTextures craftPlayerTextures = new CraftPlayerTextures(this);
|
||||
+ craftPlayerTextures.copyFrom(textures);
|
||||
+ craftPlayerTextures.rebuildPropertyIfDirty();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public GameProfile getGameProfile() {
|
||||
+ return profile;
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ @Override
|
||||
+ public UUID getId() {
|
||||
+ return this.emptyUUID ? null : this.profile.getId();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ @Deprecated(forRemoval = true)
|
||||
+ public UUID setId(@Nullable UUID uuid) {
|
||||
+ final GameProfile previousProfile = this.profile;
|
||||
+ final UUID previousId = this.getId();
|
||||
+ this.profile = createAuthLibProfile(uuid, previousProfile.getName());
|
||||
+ copyProfileProperties(previousProfile, this.profile);
|
||||
+ this.emptyUUID = uuid == null;
|
||||
+ return previousId;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public UUID getUniqueId() {
|
||||
+ return getId();
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ @Override
|
||||
+ public String getName() {
|
||||
+ return this.emptyName ? null : this.profile.getName();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ @Deprecated(forRemoval = true)
|
||||
+ public String setName(@Nullable String name) {
|
||||
+ GameProfile prev = this.profile;
|
||||
+ this.profile = createAuthLibProfile(prev.getId(), name);
|
||||
+ copyProfileProperties(prev, this.profile);
|
||||
+ this.emptyName = name == null;
|
||||
+ return prev.getName();
|
||||
+ }
|
||||
+
|
||||
+ @Nonnull
|
||||
+ @Override
|
||||
+ public Set<ProfileProperty> getProperties() {
|
||||
+ return properties;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setProperties(Collection<ProfileProperty> properties) {
|
||||
+ properties.forEach(this::setProperty);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void clearProperties() {
|
||||
+ profile.getProperties().clear();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean removeProperty(String property) {
|
||||
+ return !profile.getProperties().removeAll(property).isEmpty();
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ @Override
|
||||
+ public Property getProperty(String property) {
|
||||
+ return Iterables.getFirst(this.profile.getProperties().get(property), null);
|
||||
+ }
|
||||
+
|
||||
+ @Nullable
|
||||
+ @Override
|
||||
+ public void setProperty(@NotNull String propertyName, @Nullable Property property) {
|
||||
+ if (property != null) {
|
||||
+ this.setProperty(new ProfileProperty(propertyName, property.value(), property.signature()));
|
||||
+ } else {
|
||||
+ profile.getProperties().removeAll(propertyName);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NotNull GameProfile buildGameProfile() {
|
||||
+ GameProfile profile = new GameProfile(this.profile.getId(), this.profile.getName());
|
||||
+ profile.getProperties().putAll(this.profile.getProperties());
|
||||
+ return profile;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NotNull ResolvableProfile buildResolvableProfile() {
|
||||
+ if (this.emptyName || this.emptyUUID) {
|
||||
+ return new ResolvableProfile(this.emptyName ? Optional.empty() : Optional.of(this.profile.getName()), this.emptyUUID ? Optional.empty() : Optional.of(this.profile.getId()), this.profile.getProperties());
|
||||
+ } else {
|
||||
+ return new ResolvableProfile(this.buildGameProfile());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public CraftPlayerProfile clone() {
|
||||
+ CraftPlayerProfile clone = new CraftPlayerProfile(this.getId(), this.getName());
|
||||
+ clone.setProperties(getProperties());
|
||||
+ return clone;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isComplete() {
|
||||
+ return this.getId() != null && StringUtils.isNotBlank(this.getName());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NotNull CompletableFuture<PlayerProfile> update() {
|
||||
+ return CompletableFuture.supplyAsync(() -> {
|
||||
+ final CraftPlayerProfile clone = clone();
|
||||
+ clone.complete(true);
|
||||
+ return clone;
|
||||
+ }, Util.PROFILE_EXECUTOR);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean completeFromCache() {
|
||||
+ return completeFromCache(false, GlobalConfiguration.get().proxies.isProxyOnlineMode());
|
||||
+ }
|
||||
+
|
||||
+ public boolean completeFromCache(boolean onlineMode) {
|
||||
+ return completeFromCache(false, onlineMode);
|
||||
+ }
|
||||
+
|
||||
+ public boolean completeFromCache(boolean lookupUUID, boolean onlineMode) {
|
||||
+ MinecraftServer server = MinecraftServer.getServer();
|
||||
+ String name = profile.getName();
|
||||
+ GameProfileCache userCache = server.getProfileCache();
|
||||
+ if (this.getId() == null) {
|
||||
+ final GameProfile profile;
|
||||
+ if (onlineMode) {
|
||||
+ profile = lookupUUID ? userCache.get(name).orElse(null) : userCache.getProfileIfCached(name);
|
||||
+ } else {
|
||||
+ // Make an OfflinePlayer using an offline mode UUID since the name has no profile
|
||||
+ profile = new GameProfile(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8)), name);
|
||||
+ }
|
||||
+ if (profile != null) {
|
||||
+ // if old has it, assume its newer, so overwrite, else use cached if it was set and ours wasn't
|
||||
+ copyProfileProperties(this.profile, profile);
|
||||
+ this.profile = profile;
|
||||
+ this.emptyUUID = false; // UUID was just retrieved from user cache and profile isn't null (so a completed profile was found)
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if ((profile.getName().isEmpty() || !hasTextures()) && this.getId() != null) {
|
||||
+ Optional<GameProfile> optProfile = userCache.get(this.profile.getId());
|
||||
+ if (optProfile.isPresent()) {
|
||||
+ GameProfile profile = optProfile.get();
|
||||
+ if (this.profile.getName().isEmpty()) {
|
||||
+ // if old has it, assume its newer, so overwrite, else use cached if it was set and ours wasn't
|
||||
+ copyProfileProperties(this.profile, profile);
|
||||
+ this.profile = profile;
|
||||
+ this.emptyName = false; // Name was just retrieved via the userCache
|
||||
+ } else if (profile != this.profile) {
|
||||
+ copyProfileProperties(profile, this.profile);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return this.isComplete();
|
||||
+ }
|
||||
+
|
||||
+ public boolean complete(boolean textures) {
|
||||
+ return complete(textures, GlobalConfiguration.get().proxies.isProxyOnlineMode());
|
||||
+ }
|
||||
+
|
||||
+ public boolean complete(boolean textures, boolean onlineMode) {
|
||||
+ if (this.isComplete() && (!textures || hasTextures())) { // Don't do lookup if we already have everything
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ MinecraftServer server = MinecraftServer.getServer();
|
||||
+ boolean isCompleteFromCache = this.completeFromCache(true, onlineMode);
|
||||
+ if (onlineMode && (!isCompleteFromCache || (textures && !hasTextures()))) {
|
||||
+ ProfileResult result = server.getSessionService().fetchProfile(this.profile.getId(), true);
|
||||
+ if (result != null && result.profile() != null) {
|
||||
+ copyProfileProperties(result.profile(), this.profile, true);
|
||||
+ }
|
||||
+ if (this.isComplete()) {
|
||||
+ server.getProfileCache().add(this.profile);
|
||||
+ }
|
||||
+ }
|
||||
+ return this.isComplete() && (!onlineMode || !textures || hasTextures());
|
||||
+ }
|
||||
+
|
||||
+ private static void copyProfileProperties(GameProfile source, GameProfile target) {
|
||||
+ copyProfileProperties(source, target, false);
|
||||
+ }
|
||||
+
|
||||
+ private static void copyProfileProperties(GameProfile source, GameProfile target, boolean clearTarget) {
|
||||
+ if (source == target) {
|
||||
+ throw new IllegalArgumentException("Source and target profiles are the same (" + source + ")");
|
||||
+ }
|
||||
+ PropertyMap sourceProperties = source.getProperties();
|
||||
+ PropertyMap targetProperties = target.getProperties();
|
||||
+ if (clearTarget) targetProperties.clear();
|
||||
+ if (sourceProperties.isEmpty()) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ for (Property property : sourceProperties.values()) {
|
||||
+ targetProperties.removeAll(property.name());
|
||||
+ targetProperties.put(property.name(), property);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static GameProfile createAuthLibProfile(UUID uniqueId, String name) {
|
||||
+ Preconditions.checkArgument(name == null || name.length() <= 16, "Name cannot be longer than 16 characters");
|
||||
+ Preconditions.checkArgument(name == null || StringUtil.isValidPlayerName(name), "The name of the profile contains invalid characters: %s", name);
|
||||
+ return new GameProfile(
|
||||
+ uniqueId != null ? uniqueId : Util.NIL_UUID,
|
||||
+ name != null ? name : ""
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ private static ProfileProperty toBukkit(Property property) {
|
||||
+ return new ProfileProperty(property.name(), property.value(), property.signature());
|
||||
+ }
|
||||
+
|
||||
+ public static PlayerProfile asBukkitCopy(GameProfile gameProfile) {
|
||||
+ CraftPlayerProfile profile = new CraftPlayerProfile(gameProfile.getId(), gameProfile.getName());
|
||||
+ copyProfileProperties(gameProfile, profile.profile);
|
||||
+ return profile;
|
||||
+ }
|
||||
+
|
||||
+ public static PlayerProfile asBukkitMirror(GameProfile profile) {
|
||||
+ return new CraftPlayerProfile(profile);
|
||||
+ }
|
||||
+
|
||||
+ public static Property asAuthlib(ProfileProperty property) {
|
||||
+ return new Property(property.getName(), property.getValue(), property.getSignature());
|
||||
+ }
|
||||
+
|
||||
+ public static GameProfile asAuthlibCopy(PlayerProfile profile) {
|
||||
+ CraftPlayerProfile craft = ((CraftPlayerProfile) profile);
|
||||
+ return asAuthlib(craft.clone());
|
||||
+ }
|
||||
+
|
||||
+ public static GameProfile asAuthlib(PlayerProfile profile) {
|
||||
+ CraftPlayerProfile craft = ((CraftPlayerProfile) profile);
|
||||
+ return craft.getGameProfile();
|
||||
+ }
|
||||
+
|
||||
+ public static ResolvableProfile asResolvableProfileCopy(PlayerProfile profile) {
|
||||
+ return ((SharedPlayerProfile) profile).buildResolvableProfile();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @NotNull Map<String, Object> serialize() {
|
||||
+ Map<String, Object> map = new LinkedHashMap<>();
|
||||
+ if (!this.emptyUUID) {
|
||||
+ map.put("uniqueId", this.getId().toString());
|
||||
+ }
|
||||
+ if (!this.emptyName) {
|
||||
+ map.put("name", getName());
|
||||
+ }
|
||||
+ if (!this.properties.isEmpty()) {
|
||||
+ List<Object> propertiesData = new ArrayList<>();
|
||||
+ for (ProfileProperty property : properties) {
|
||||
+ propertiesData.add(CraftProfileProperty.serialize(new Property(property.getName(), property.getValue(), property.getSignature())));
|
||||
+ }
|
||||
+ map.put("properties", propertiesData);
|
||||
+ }
|
||||
+ return map;
|
||||
+ }
|
||||
+
|
||||
+ public static CraftPlayerProfile deserialize(Map<String, Object> map) {
|
||||
+ UUID uniqueId = ConfigSerializationUtil.getUuid(map, "uniqueId", true);
|
||||
+ String name = ConfigSerializationUtil.getString(map, "name", true);
|
||||
+
|
||||
+ // This also validates the deserialized unique id and name (ensures that not both are null):
|
||||
+ CraftPlayerProfile profile = new CraftPlayerProfile(uniqueId, name);
|
||||
+
|
||||
+ if (map.containsKey("properties")) {
|
||||
+ for (Object propertyData : (List<?>) map.get("properties")) {
|
||||
+ if (!(propertyData instanceof Map)) {
|
||||
+ throw new IllegalArgumentException("Property data (" + propertyData + ") is not a valid Map");
|
||||
+ }
|
||||
+ Property property = CraftProfileProperty.deserialize((Map<?, ?>) propertyData);
|
||||
+ profile.profile.getProperties().put(property.name(), property);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return profile;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean equals(final Object o) {
|
||||
+ if (this == o) return true;
|
||||
+ if (o == null || this.getClass() != o.getClass()) return false;
|
||||
+ final CraftPlayerProfile that = (CraftPlayerProfile) o;
|
||||
+ return this.emptyName == that.emptyName && this.emptyUUID == that.emptyUUID && Objects.equals(this.profile, that.profile);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int hashCode() {
|
||||
+ return Objects.hash(this.emptyName, this.emptyUUID, this.profile);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public String toString() {
|
||||
+ return "CraftPlayerProfile [uniqueId=" + getId() +
|
||||
+ ", name=" + getName() +
|
||||
+ ", properties=" + org.bukkit.craftbukkit.profile.CraftPlayerProfile.toString(this.profile.getProperties()) +
|
||||
+ "]";
|
||||
+ }
|
||||
+
|
||||
+ private class PropertySet extends AbstractSet<ProfileProperty> {
|
||||
+
|
||||
+ @Override
|
||||
+ @Nonnull
|
||||
+ public Iterator<ProfileProperty> iterator() {
|
||||
+ return new ProfilePropertyIterator(profile.getProperties().values().iterator());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public int size() {
|
||||
+ return profile.getProperties().size();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean add(ProfileProperty property) {
|
||||
+ setProperty(property);
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean addAll(Collection<? extends ProfileProperty> c) {
|
||||
+ //noinspection unchecked
|
||||
+ setProperties((Collection<ProfileProperty>) c);
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean contains(Object o) {
|
||||
+ return o instanceof ProfileProperty && profile.getProperties().containsKey(((ProfileProperty) o).getName());
|
||||
+ }
|
||||
+
|
||||
+ private class ProfilePropertyIterator implements Iterator<ProfileProperty> {
|
||||
+ private final Iterator<Property> iterator;
|
||||
+
|
||||
+ ProfilePropertyIterator(Iterator<Property> iterator) {
|
||||
+ this.iterator = iterator;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean hasNext() {
|
||||
+ return iterator.hasNext();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public ProfileProperty next() {
|
||||
+ return toBukkit(iterator.next());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void remove() {
|
||||
+ iterator.remove();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/profile/PaperAuthenticationService.java b/src/main/java/com/destroystokyo/paper/profile/PaperAuthenticationService.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..48e774677edf17d4a99ae9ed23d1b371dab41abb
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/profile/PaperAuthenticationService.java
|
||||
@@ -0,0 +1,30 @@
|
||||
+package com.destroystokyo.paper.profile;
|
||||
+
|
||||
+import com.mojang.authlib.Environment;
|
||||
+import com.mojang.authlib.EnvironmentParser;
|
||||
+import com.mojang.authlib.GameProfileRepository;
|
||||
+import com.mojang.authlib.minecraft.MinecraftSessionService;
|
||||
+import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
|
||||
+import com.mojang.authlib.yggdrasil.YggdrasilEnvironment;
|
||||
+
|
||||
+import java.net.Proxy;
|
||||
+
|
||||
+public class PaperAuthenticationService extends YggdrasilAuthenticationService {
|
||||
+
|
||||
+ private final Environment environment;
|
||||
+
|
||||
+ public PaperAuthenticationService(Proxy proxy) {
|
||||
+ super(proxy);
|
||||
+ this.environment = EnvironmentParser.getEnvironmentFromProperties().orElse(YggdrasilEnvironment.PROD.getEnvironment());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public MinecraftSessionService createMinecraftSessionService() {
|
||||
+ return new PaperMinecraftSessionService(this.getServicesKeySet(), this.getProxy(), this.environment);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public GameProfileRepository createProfileRepository() {
|
||||
+ return new PaperGameProfileRepository(this.getProxy(), this.environment);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java b/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..7b9e797b42c88b17d6a7c590a423f4e85d99a59d
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java
|
||||
@@ -0,0 +1,17 @@
|
||||
+package com.destroystokyo.paper.profile;
|
||||
+
|
||||
+import com.mojang.authlib.Environment;
|
||||
+import com.mojang.authlib.ProfileLookupCallback;
|
||||
+import com.mojang.authlib.yggdrasil.YggdrasilGameProfileRepository;
|
||||
+import java.net.Proxy;
|
||||
+
|
||||
+public class PaperGameProfileRepository extends YggdrasilGameProfileRepository {
|
||||
+ public PaperGameProfileRepository(Proxy proxy, Environment environment) {
|
||||
+ super(proxy, environment);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void findProfilesByNames(String[] names, ProfileLookupCallback callback) {
|
||||
+ super.findProfilesByNames(names, callback);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java b/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..985e6fc43a0946943847e0c283426242ef594a26
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java
|
||||
@@ -0,0 +1,22 @@
|
||||
+package com.destroystokyo.paper.profile;
|
||||
+
|
||||
+import com.mojang.authlib.Environment;
|
||||
+import com.mojang.authlib.yggdrasil.ProfileResult;
|
||||
+import com.mojang.authlib.yggdrasil.ServicesKeySet;
|
||||
+import com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService;
|
||||
+
|
||||
+import java.net.Proxy;
|
||||
+import java.util.UUID;
|
||||
+import org.jetbrains.annotations.Nullable;
|
||||
+
|
||||
+public class PaperMinecraftSessionService extends YggdrasilMinecraftSessionService {
|
||||
+
|
||||
+ protected PaperMinecraftSessionService(ServicesKeySet servicesKeySet, Proxy proxy, Environment environment) {
|
||||
+ super(servicesKeySet, proxy, environment);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public @Nullable ProfileResult fetchProfile(final UUID profileId, final boolean requireSecure) {
|
||||
+ return super.fetchProfile(profileId, requireSecure);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/profile/SharedPlayerProfile.java b/src/main/java/com/destroystokyo/paper/profile/SharedPlayerProfile.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..332700f84c5587e47a4d2056bfbb5413de97e9f2
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/profile/SharedPlayerProfile.java
|
||||
@@ -0,0 +1,26 @@
|
||||
+package com.destroystokyo.paper.profile;
|
||||
+
|
||||
+import com.mojang.authlib.GameProfile;
|
||||
+import com.mojang.authlib.properties.Property;
|
||||
+import net.minecraft.world.item.component.ResolvableProfile;
|
||||
+import org.jetbrains.annotations.NotNull;
|
||||
+import org.jetbrains.annotations.Nullable;
|
||||
+
|
||||
+import java.util.UUID;
|
||||
+
|
||||
+public interface SharedPlayerProfile {
|
||||
+
|
||||
+ @Nullable UUID getUniqueId();
|
||||
+
|
||||
+ @Nullable String getName();
|
||||
+
|
||||
+ boolean removeProperty(@NotNull String property);
|
||||
+
|
||||
+ @Nullable Property getProperty(@NotNull String propertyName);
|
||||
+
|
||||
+ @Nullable void setProperty(@NotNull String propertyName, @Nullable Property property);
|
||||
+
|
||||
+ @NotNull GameProfile buildGameProfile();
|
||||
+
|
||||
+ @NotNull ResolvableProfile buildResolvableProfile();
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
|
||||
index 7399358f18dc7869fbfe414186cf18414c1eaafc..a9dadd106ff0ac0f788c16048a73dfc3320b4944 100644
|
||||
--- a/src/main/java/net/minecraft/server/Main.java
|
||||
+++ b/src/main/java/net/minecraft/server/Main.java
|
||||
@@ -168,7 +168,7 @@ public class Main {
|
||||
}
|
||||
|
||||
File file = (File) optionset.valueOf("universe"); // CraftBukkit
|
||||
- Services services = Services.create(new YggdrasilAuthenticationService(Proxy.NO_PROXY), file, optionset); // Paper - pass OptionSet to load paper config files
|
||||
+ Services services = Services.create(new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY), file, optionset); // Paper - pass OptionSet to load paper config files; override authentication service
|
||||
// CraftBukkit start
|
||||
String s = (String) Optional.ofNullable((String) optionset.valueOf("world")).orElse(dedicatedserversettings.getProperties().levelName);
|
||||
LevelStorageSource convertable = LevelStorageSource.createDefault(file.toPath());
|
||||
diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java
|
||||
index 416b26c2ab62b29d640169166980e398d5824b14..774d81c702edb76a2f6184d4dc53687de6734a79 100644
|
||||
--- a/src/main/java/net/minecraft/server/players/GameProfileCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java
|
||||
@@ -126,6 +126,17 @@ public class GameProfileCache {
|
||||
return this.operationCount.incrementAndGet();
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ public @Nullable GameProfile getProfileIfCached(String name) {
|
||||
+ GameProfileCache.GameProfileInfo entry = this.profilesByName.get(name.toLowerCase(Locale.ROOT));
|
||||
+ if (entry == null) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ entry.setLastAccess(this.getNextOperation());
|
||||
+ return entry.getProfile();
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public Optional<GameProfile> get(String name) {
|
||||
String s1 = name.toLowerCase(Locale.ROOT);
|
||||
GameProfileCache.GameProfileInfo usercache_usercacheentry = (GameProfileCache.GameProfileInfo) this.profilesByName.get(s1);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 271f299823495fd92c49a1fbb04e1daa501fafb0..d18228961bfd201e922e1bd1ab41bb6b53124c5c 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -265,6 +265,9 @@ import org.yaml.snakeyaml.error.MarkedYAMLException;
|
||||
|
||||
import net.md_5.bungee.api.chat.BaseComponent; // Spigot
|
||||
|
||||
+import javax.annotation.Nullable; // Paper
|
||||
+import javax.annotation.Nonnull; // Paper
|
||||
+
|
||||
public final class CraftServer implements Server {
|
||||
private final String serverName = io.papermc.paper.ServerBuildInfo.buildInfo().brandName(); // Paper
|
||||
private final String serverVersion;
|
||||
@@ -310,6 +313,7 @@ public final class CraftServer implements Server {
|
||||
static {
|
||||
ConfigurationSerialization.registerClass(CraftOfflinePlayer.class);
|
||||
ConfigurationSerialization.registerClass(CraftPlayerProfile.class);
|
||||
+ ConfigurationSerialization.registerClass(com.destroystokyo.paper.profile.CraftPlayerProfile.class); // Paper
|
||||
CraftItemFactory.instance();
|
||||
CraftEntityFactory.instance();
|
||||
}
|
||||
@@ -2859,5 +2863,39 @@ public final class CraftServer implements Server {
|
||||
public boolean suggestPlayerNamesWhenNullTabCompletions() {
|
||||
return io.papermc.paper.configuration.GlobalConfiguration.get().commands.suggestPlayerNamesWhenNullTabCompletions;
|
||||
}
|
||||
+
|
||||
+ @Override
|
||||
+ public com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nonnull UUID uuid) {
|
||||
+ return createProfile(uuid, null);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nonnull String name) {
|
||||
+ return createProfile(null, name);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public com.destroystokyo.paper.profile.PlayerProfile createProfile(@Nullable UUID uuid, @Nullable String name) {
|
||||
+ Player player = uuid != null ? Bukkit.getPlayer(uuid) : (name != null ? Bukkit.getPlayerExact(name) : null);
|
||||
+ if (player != null) return new com.destroystokyo.paper.profile.CraftPlayerProfile((CraftPlayer) player);
|
||||
+
|
||||
+ return new com.destroystokyo.paper.profile.CraftPlayerProfile(uuid, name);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public com.destroystokyo.paper.profile.PlayerProfile createProfileExact(@Nullable UUID uuid, @Nullable String name) {
|
||||
+ Player player = uuid != null ? Bukkit.getPlayer(uuid) : (name != null ? Bukkit.getPlayerExact(name) : null);
|
||||
+ if (player == null) {
|
||||
+ return new com.destroystokyo.paper.profile.CraftPlayerProfile(uuid, name);
|
||||
+ }
|
||||
+
|
||||
+ if (java.util.Objects.equals(uuid, player.getUniqueId()) && java.util.Objects.equals(name, player.getName())) {
|
||||
+ return new com.destroystokyo.paper.profile.CraftPlayerProfile((CraftPlayer) player);
|
||||
+ }
|
||||
+
|
||||
+ final com.destroystokyo.paper.profile.CraftPlayerProfile profile = new com.destroystokyo.paper.profile.CraftPlayerProfile(uuid, name);
|
||||
+ profile.getGameProfile().getProperties().putAll(((CraftPlayer) player).getHandle().getGameProfile().getProperties());
|
||||
+ return profile;
|
||||
+ }
|
||||
// Paper end
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java
|
||||
index 210fdad5f2041368fc359b275f1cbf05b70b6989..d9cc76d7e60001957c0f59fdc32d016f3589aa08 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerProfile.java
|
||||
@@ -31,7 +31,7 @@ import org.bukkit.profile.PlayerTextures;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
@SerializableAs("PlayerProfile")
|
||||
-public final class CraftPlayerProfile implements PlayerProfile {
|
||||
+public final class CraftPlayerProfile implements PlayerProfile, com.destroystokyo.paper.profile.SharedPlayerProfile { // Paper
|
||||
|
||||
@Nonnull
|
||||
public static GameProfile validateSkullProfile(@Nonnull GameProfile gameProfile) {
|
||||
@@ -132,8 +132,10 @@ public final class CraftPlayerProfile implements PlayerProfile {
|
||||
}
|
||||
}
|
||||
|
||||
- void removeProperty(String propertyName) {
|
||||
- this.properties.removeAll(propertyName);
|
||||
+ // Paper start - change return value for shared interface
|
||||
+ public boolean removeProperty(String propertyName) {
|
||||
+ return !this.properties.removeAll(propertyName).isEmpty();
|
||||
+ // Paper end
|
||||
}
|
||||
|
||||
void rebuildDirtyProperties() {
|
||||
@@ -283,6 +285,7 @@ public final class CraftPlayerProfile implements PlayerProfile {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> serialize() {
|
||||
+ // Paper - diff on change
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
if (this.uniqueId != null) {
|
||||
map.put("uniqueId", this.uniqueId.toString());
|
||||
@@ -296,10 +299,12 @@ public final class CraftPlayerProfile implements PlayerProfile {
|
||||
this.properties.forEach((propertyName, property) -> propertiesData.add(CraftProfileProperty.serialize(property)));
|
||||
map.put("properties", propertiesData);
|
||||
}
|
||||
+ // Paper - diff on change
|
||||
return map;
|
||||
}
|
||||
|
||||
public static CraftPlayerProfile deserialize(Map<String, Object> map) {
|
||||
+ // Paper - diff on change
|
||||
UUID uniqueId = ConfigSerializationUtil.getUuid(map, "uniqueId", true);
|
||||
String name = ConfigSerializationUtil.getString(map, "name", true);
|
||||
|
||||
@@ -313,7 +318,7 @@ public final class CraftPlayerProfile implements PlayerProfile {
|
||||
profile.properties.put(property.name(), property);
|
||||
}
|
||||
}
|
||||
-
|
||||
+ // Paper - diff on change
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerTextures.java b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerTextures.java
|
||||
index 78e47fec27f4dd955632d03f7181682af0429961..0dce455fb47b3f5a2eb2b15a1cdbc4c6a54b7b69 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerTextures.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/profile/CraftPlayerTextures.java
|
||||
@@ -48,7 +48,7 @@ public final class CraftPlayerTextures implements PlayerTextures {
|
||||
}
|
||||
}
|
||||
|
||||
- private final CraftPlayerProfile profile;
|
||||
+ private final com.destroystokyo.paper.profile.SharedPlayerProfile profile; // Paper
|
||||
|
||||
// The textures data is loaded lazily:
|
||||
private boolean loaded = false;
|
||||
@@ -67,7 +67,7 @@ public final class CraftPlayerTextures implements PlayerTextures {
|
||||
// GameProfiles (even if these modifications are later reverted).
|
||||
private boolean dirty = false;
|
||||
|
||||
- CraftPlayerTextures(@Nonnull CraftPlayerProfile profile) {
|
||||
+ public CraftPlayerTextures(@Nonnull com.destroystokyo.paper.profile.SharedPlayerProfile profile) { // Paper
|
||||
this.profile = profile;
|
||||
}
|
||||
|
98
patches/server/0137-Add-UnknownCommandEvent.patch
Normal file
98
patches/server/0137-Add-UnknownCommandEvent.patch
Normal file
|
@ -0,0 +1,98 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Sweepyoface <github@sweepy.pw>
|
||||
Date: Sat, 17 Jun 2017 18:48:21 -0400
|
||||
Subject: [PATCH] Add UnknownCommandEvent
|
||||
|
||||
Co-authored-by: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
index 2fbd7f7c976fb55b7238f1e512afad79e52a5b2c..4d5f1dd1c3bd742b1bc5e3914101a699041caa7e 100644
|
||||
--- a/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java
|
||||
@@ -332,8 +332,13 @@ public class CommandSourceStack implements ExecutionCommandSource<CommandSourceS
|
||||
}
|
||||
|
||||
public void sendFailure(Component message) {
|
||||
+ // Paper start - Add UnknownCommandEvent
|
||||
+ this.sendFailure(message, true);
|
||||
+ }
|
||||
+ public void sendFailure(Component message, boolean withStyle) {
|
||||
+ // Paper end - Add UnknownCommandEvent
|
||||
if (this.source.acceptsFailure() && !this.silent) {
|
||||
- this.source.sendSystemMessage(Component.empty().append(message).withStyle(ChatFormatting.RED));
|
||||
+ this.source.sendSystemMessage(withStyle ? Component.empty().append(message).withStyle(ChatFormatting.RED) : message); // Paper - Add UnknownCommandEvent
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java
|
||||
index 603d0fa7f9690a09dca3c744bc4f90ac31132b90..2008fd542eaf1c2fac776ae1751c227a3b6dde4b 100644
|
||||
--- a/src/main/java/net/minecraft/commands/Commands.java
|
||||
+++ b/src/main/java/net/minecraft/commands/Commands.java
|
||||
@@ -334,7 +334,7 @@ public class Commands {
|
||||
Profiler.get().push(() -> {
|
||||
return "/" + s;
|
||||
});
|
||||
- ContextChain<CommandSourceStack> contextchain = Commands.finishParsing(parseresults, s, commandlistenerwrapper, label); // CraftBukkit
|
||||
+ ContextChain contextchain = this.finishParsing(parseresults, s, commandlistenerwrapper, label); // CraftBukkit // Paper - Add UnknownCommandEvent
|
||||
|
||||
try {
|
||||
if (contextchain != null) {
|
||||
@@ -368,14 +368,18 @@ public class Commands {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
- private static ContextChain<CommandSourceStack> finishParsing(ParseResults<CommandSourceStack> parseresults, String s, CommandSourceStack commandlistenerwrapper, String label) { // CraftBukkit
|
||||
+ private ContextChain<CommandSourceStack> finishParsing(ParseResults<CommandSourceStack> parseresults, String s, CommandSourceStack commandlistenerwrapper, String label) { // CraftBukkit // Paper - Add UnknownCommandEvent
|
||||
try {
|
||||
Commands.validateParseResults(parseresults);
|
||||
return (ContextChain) ContextChain.tryFlatten(parseresults.getContext().build(s)).orElseThrow(() -> {
|
||||
return CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand().createWithContext(parseresults.getReader());
|
||||
});
|
||||
} catch (CommandSyntaxException commandsyntaxexception) {
|
||||
- commandlistenerwrapper.sendFailure(ComponentUtils.fromMessage(commandsyntaxexception.getRawMessage()));
|
||||
+ // Paper start - Add UnknownCommandEvent
|
||||
+ final net.kyori.adventure.text.TextComponent.Builder builder = net.kyori.adventure.text.Component.text();
|
||||
+ // commandlistenerwrapper.sendFailure(ComponentUtils.fromMessage(commandsyntaxexception.getRawMessage()));
|
||||
+ builder.color(net.kyori.adventure.text.format.NamedTextColor.RED).append(io.papermc.paper.brigadier.PaperBrigadier.componentFromMessage(commandsyntaxexception.getRawMessage()));
|
||||
+ // Paper end - Add UnknownCommandEvent
|
||||
if (commandsyntaxexception.getInput() != null && commandsyntaxexception.getCursor() >= 0) {
|
||||
int i = Math.min(commandsyntaxexception.getInput().length(), commandsyntaxexception.getCursor());
|
||||
MutableComponent ichatmutablecomponent = Component.empty().withStyle(ChatFormatting.GRAY).withStyle((chatmodifier) -> {
|
||||
@@ -394,7 +398,17 @@ public class Commands {
|
||||
}
|
||||
|
||||
ichatmutablecomponent.append((Component) Component.translatable("command.context.here").withStyle(ChatFormatting.RED, ChatFormatting.ITALIC));
|
||||
- commandlistenerwrapper.sendFailure(ichatmutablecomponent);
|
||||
+ // Paper start - Add UnknownCommandEvent
|
||||
+ // commandlistenerwrapper.sendFailure(ichatmutablecomponent);
|
||||
+ builder
|
||||
+ .append(net.kyori.adventure.text.Component.newline())
|
||||
+ .append(io.papermc.paper.adventure.PaperAdventure.asAdventure(ichatmutablecomponent));
|
||||
+ }
|
||||
+ org.bukkit.event.command.UnknownCommandEvent event = new org.bukkit.event.command.UnknownCommandEvent(commandlistenerwrapper.getBukkitSender(), s, org.spigotmc.SpigotConfig.unknownCommandMessage.isEmpty() ? null : builder.build());
|
||||
+ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
+ if (event.message() != null) {
|
||||
+ commandlistenerwrapper.sendFailure(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.message()), false);
|
||||
+ // Paper end - Add UnknownCommandEvent
|
||||
}
|
||||
|
||||
return null;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index d18228961bfd201e922e1bd1ab41bb6b53124c5c..fa6284ebe3bdbf97b40a2ab61ba94062cdcf045e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -951,7 +951,13 @@ public final class CraftServer implements Server {
|
||||
|
||||
// Spigot start
|
||||
if (!org.spigotmc.SpigotConfig.unknownCommandMessage.isEmpty()) {
|
||||
- sender.sendMessage(org.spigotmc.SpigotConfig.unknownCommandMessage);
|
||||
+ // Paper start
|
||||
+ org.bukkit.event.command.UnknownCommandEvent event = new org.bukkit.event.command.UnknownCommandEvent(sender, commandLine, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.unknownCommandMessage));
|
||||
+ this.getPluginManager().callEvent(event);
|
||||
+ if (event.message() != null) {
|
||||
+ sender.sendMessage(event.message());
|
||||
+ }
|
||||
+ // Paper end
|
||||
}
|
||||
// Spigot end
|
||||
|
94
patches/server/0138-Shoulder-Entities-Release-API.patch
Normal file
94
patches/server/0138-Shoulder-Entities-Release-API.patch
Normal file
|
@ -0,0 +1,94 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
Date: Sat, 17 Jun 2017 15:18:30 -0400
|
||||
Subject: [PATCH] Shoulder Entities Release API
|
||||
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
index fb6b7be09fffbb9ffefba3f0c0c97b0f90ff6a94..357c71409af5f67a0a6aaa0cb08fd93a4a4f99de 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
|
||||
@@ -1948,7 +1948,31 @@ public abstract class Player extends LivingEntity {
|
||||
|
||||
}
|
||||
|
||||
+ // Paper start - release entity api
|
||||
+ public Entity releaseLeftShoulderEntity() {
|
||||
+ Entity entity = this.respawnEntityOnShoulder0(this.getShoulderEntityLeft());
|
||||
+ if (entity != null) {
|
||||
+ this.setShoulderEntityLeft(new CompoundTag());
|
||||
+ }
|
||||
+ return entity;
|
||||
+ }
|
||||
+
|
||||
+ public Entity releaseRightShoulderEntity() {
|
||||
+ Entity entity = this.respawnEntityOnShoulder0(this.getShoulderEntityRight());
|
||||
+ if (entity != null) {
|
||||
+ this.setShoulderEntityRight(new CompoundTag());
|
||||
+ }
|
||||
+ return entity;
|
||||
+ }
|
||||
+ // Paper end - release entity api
|
||||
+
|
||||
private boolean respawnEntityOnShoulder(CompoundTag nbttagcompound) { // CraftBukkit void->boolean
|
||||
+ // Paper start - release entity api - return entity - overload
|
||||
+ return this.respawnEntityOnShoulder0(nbttagcompound) != null;
|
||||
+ }
|
||||
+
|
||||
+ private Entity respawnEntityOnShoulder0(CompoundTag nbttagcompound) { // CraftBukkit void->boolean
|
||||
+ // Paper end - release entity api - return entity - overload
|
||||
if (!this.level().isClientSide && !nbttagcompound.isEmpty()) {
|
||||
return EntityType.create(nbttagcompound, this.level(), EntitySpawnReason.LOAD).map((entity) -> { // CraftBukkit
|
||||
if (entity instanceof TamableAnimal) {
|
||||
@@ -1956,11 +1980,11 @@ public abstract class Player extends LivingEntity {
|
||||
}
|
||||
|
||||
entity.setPos(this.getX(), this.getY() + 0.699999988079071D, this.getZ());
|
||||
- return ((ServerLevel) this.level()).addWithUUID(entity, CreatureSpawnEvent.SpawnReason.SHOULDER_ENTITY); // CraftBukkit
|
||||
- }).orElse(true); // CraftBukkit
|
||||
+ return ((ServerLevel) this.level()).addWithUUID(entity, CreatureSpawnEvent.SpawnReason.SHOULDER_ENTITY) ? entity : null; // CraftBukkit // Paper start - release entity api - return entity
|
||||
+ }).orElse(null); // CraftBukkit // Paper end - release entity api - return entity
|
||||
}
|
||||
|
||||
- return true; // CraftBukkit
|
||||
+ return null; // Paper - return null
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
index bfa44c4e37618df3f745bccc6e775ce16c19490d..768a6e3f5d75d37ae114ffcf2b090fe9de769381 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
|
||||
@@ -544,6 +544,32 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
||||
this.getHandle().getCooldowns().addCooldown(CraftItemStack.asNMSCopy(item), ticks);
|
||||
}
|
||||
|
||||
+ // Paper start
|
||||
+ @Override
|
||||
+ public org.bukkit.entity.Entity releaseLeftShoulderEntity() {
|
||||
+ if (!getHandle().getShoulderEntityLeft().isEmpty()) {
|
||||
+ Entity entity = getHandle().releaseLeftShoulderEntity();
|
||||
+ if (entity != null) {
|
||||
+ return entity.getBukkitEntity();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public org.bukkit.entity.Entity releaseRightShoulderEntity() {
|
||||
+ if (!getHandle().getShoulderEntityRight().isEmpty()) {
|
||||
+ Entity entity = getHandle().releaseRightShoulderEntity();
|
||||
+ if (entity != null) {
|
||||
+ return entity.getBukkitEntity();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return null;
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
@Override
|
||||
public boolean discoverRecipe(NamespacedKey recipe) {
|
||||
return this.discoverRecipes(Arrays.asList(recipe)) != 0;
|
Loading…
Add table
Add a link
Reference in a new issue