More more more more more work

This commit is contained in:
Nassim Jahnke 2021-11-23 15:03:50 +01:00 committed by MiniDigger | Martin
parent d7cdc72bdf
commit 6f3591fd6d
90 changed files with 203 additions and 211 deletions

View file

@ -1,46 +0,0 @@
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 9611388a6aeebb86b19d89c526f53dfed4d3ed27..d17af2ec8f72bf0cbe5928e7a83c06ba5ad4503d 100644
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
@@ -379,6 +379,7 @@ public class ItemEntity extends Entity {
// 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);
@@ -386,8 +387,14 @@ public class ItemEntity extends Entity {
PlayerPickupItemEvent playerEvent = new PlayerPickupItemEvent((org.bukkit.entity.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;
}
@@ -417,7 +424,11 @@ public class ItemEntity extends Entity {
// CraftBukkit end
if (this.pickupDelay == 0 && (this.owner == null || this.owner.equals(player.getUUID())) && player.getInventory().add(itemstack)) {
- player.take(this, i);
+ // Paper Start
+ if (flyAtPlayer) {
+ player.take(this, i);
+ }
+ // Paper End
if (itemstack.isEmpty()) {
this.discard();
itemstack.setCount(i);

View file

@ -1,41 +0,0 @@
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 d17af2ec8f72bf0cbe5928e7a83c06ba5ad4503d..54025e401eb02fceb47afb182f0ede620ca23a8d 100644
--- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java
@@ -37,6 +37,7 @@ import net.minecraft.stats.Stats;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
// CraftBukkit end
+import org.bukkit.event.player.PlayerAttemptPickupItemEvent; // Paper
public class ItemEntity extends Entity {
@@ -381,6 +382,22 @@ public class ItemEntity extends Entity {
int remaining = i - canHold;
boolean flyAtPlayer = false; // Paper
+ // Paper start
+ 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
+
if (this.pickupDelay <= 0 && canHold > 0) {
itemstack.setCount(canHold);
// Call legacy event

View file

@ -1,25 +0,0 @@
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
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 696e2495ee8046c78ed53126db0e6c696c77c00d..e01f800130f183bf10a383e298b7da3d5f11e3a2 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -817,7 +817,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, org.spigotmc.SpigotConfig.unknownCommandMessage);
+ Bukkit.getServer().getPluginManager().callEvent(event);
+ if (event.message() != null) {
+ sender.sendMessage(event.message());
+ }
+ // Paper end
}
// Spigot end

View file

@ -1,549 +0,0 @@
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
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..84551164b76bc8f064a3a0c030c3a1b47f567b6f
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java
@@ -0,0 +1,302 @@
+package com.destroystokyo.paper.profile;
+
+import com.destroystokyo.paper.PaperConfig;
+import com.google.common.base.Charsets;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import com.mojang.authlib.properties.PropertyMap;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.players.GameProfileCache;
+import org.apache.commons.lang3.Validate;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.UUID;
+
+public class CraftPlayerProfile implements PlayerProfile {
+
+ 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 = new GameProfile(id, name);
+ }
+
+ public CraftPlayerProfile(GameProfile profile) {
+ Validate.notNull(profile, "GameProfile cannot be null!");
+ this.profile = 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);
+ properties.put(name, new Property(name, property.getValue(), property.getSignature()));
+ }
+
+ public GameProfile getGameProfile() {
+ return profile;
+ }
+
+ @Nullable
+ @Override
+ public UUID getId() {
+ return profile.getId();
+ }
+
+ @Override
+ public UUID setId(@Nullable UUID uuid) {
+ GameProfile prev = this.profile;
+ this.profile = new GameProfile(uuid, prev.getName());
+ copyProfileProperties(prev, this.profile);
+ return prev.getId();
+ }
+
+ @Nullable
+ @Override
+ public String getName() {
+ return profile.getName();
+ }
+
+ @Override
+ public String setName(@Nullable String name) {
+ GameProfile prev = this.profile;
+ this.profile = new GameProfile(prev.getId(), name);
+ copyProfileProperties(prev, this.profile);
+ 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();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ CraftPlayerProfile that = (CraftPlayerProfile) o;
+ return Objects.equals(profile, that.profile);
+ }
+
+ @Override
+ public int hashCode() {
+ return profile.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return profile.toString();
+ }
+
+ @Override
+ public CraftPlayerProfile clone() {
+ CraftPlayerProfile clone = new CraftPlayerProfile(this.getId(), this.getName());
+ clone.setProperties(getProperties());
+ return clone;
+ }
+
+ @Override
+ public boolean isComplete() {
+ return profile.isComplete();
+ }
+
+ @Override
+ public boolean completeFromCache() {
+ MinecraftServer server = MinecraftServer.getServer();
+ return completeFromCache(false, PaperConfig.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 (profile.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;
+ }
+ }
+
+ if ((profile.getName() == null || !hasTextures()) && profile.getId() != null) {
+ Optional<GameProfile> optProfile = userCache.get(this.profile.getId());
+ if (optProfile.isPresent()) {
+ GameProfile profile = optProfile.get();
+ if (this.profile.getName() == 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;
+ } else {
+ copyProfileProperties(profile, this.profile);
+ }
+ }
+ }
+ return this.profile.isComplete();
+ }
+
+ public boolean complete(boolean textures) {
+ MinecraftServer server = MinecraftServer.getServer();
+ return complete(textures, PaperConfig.isProxyOnlineMode());
+ }
+ public boolean complete(boolean textures, boolean onlineMode) {
+ MinecraftServer server = MinecraftServer.getServer();
+
+ boolean isCompleteFromCache = this.completeFromCache(true, onlineMode);
+ if (onlineMode && (!isCompleteFromCache || textures && !hasTextures())) {
+ GameProfile result = server.getSessionService().fillProfileProperties(profile, true);
+ if (result != null) {
+ copyProfileProperties(result, this.profile, true);
+ }
+ if (this.profile.isComplete()) {
+ server.getProfileCache().add(this.profile);
+ }
+ }
+ return profile.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) {
+ PropertyMap sourceProperties = source.getProperties();
+ PropertyMap targetProperties = target.getProperties();
+ if (clearTarget) targetProperties.clear();
+ if (sourceProperties.isEmpty()) {
+ return;
+ }
+
+ for (Property property : sourceProperties.values()) {
+ targetProperties.removeAll(property.getName());
+ targetProperties.put(property.getName(), property);
+ }
+ }
+
+ private static ProfileProperty toBukkit(Property property) {
+ return new ProfileProperty(property.getName(), property.getValue(), property.getSignature());
+ }
+
+ 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();
+ }
+
+ 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..d64d45eb01c65864fca1077982d89bc05e0f811b
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/profile/PaperAuthenticationService.java
@@ -0,0 +1,31 @@
+package com.destroystokyo.paper.profile;
+
+import com.mojang.authlib.*;
+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 = (Environment)EnvironmentParser.getEnvironmentFromProperties().orElse(YggdrasilEnvironment.PROD);;
+ }
+
+ @Override
+ public UserAuthentication createUserAuthentication(Agent agent) {
+ return new PaperUserAuthentication(this, agent);
+ }
+
+ @Override
+ public MinecraftSessionService createMinecraftSessionService() {
+ return new PaperMinecraftSessionService(this, this.environment);
+ }
+
+ @Override
+ public GameProfileRepository createProfileRepository() {
+ return new PaperGameProfileRepository(this, 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..582c169c85ac66f1f9430f79042e4655f776c157
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java
@@ -0,0 +1,18 @@
+package com.destroystokyo.paper.profile;
+
+import com.mojang.authlib.Agent;
+import com.mojang.authlib.Environment;
+import com.mojang.authlib.ProfileLookupCallback;
+import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
+import com.mojang.authlib.yggdrasil.YggdrasilGameProfileRepository;
+
+public class PaperGameProfileRepository extends YggdrasilGameProfileRepository {
+ public PaperGameProfileRepository(YggdrasilAuthenticationService authenticationService, Environment environment) {
+ super(authenticationService, environment);
+ }
+
+ @Override
+ public void findProfilesByNames(String[] names, Agent agent, ProfileLookupCallback callback) {
+ super.findProfilesByNames(names, agent, 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..93d73c27340645c7502acafdc0b2cfbc1a759dd8
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java
@@ -0,0 +1,30 @@
+package com.destroystokyo.paper.profile;
+
+import com.mojang.authlib.Environment;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.minecraft.MinecraftProfileTexture;
+import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
+import com.mojang.authlib.yggdrasil.YggdrasilMinecraftSessionService;
+
+import java.util.Map;
+
+public class PaperMinecraftSessionService extends YggdrasilMinecraftSessionService {
+ protected PaperMinecraftSessionService(YggdrasilAuthenticationService authenticationService, Environment environment) {
+ super(authenticationService, environment);
+ }
+
+ @Override
+ public Map<MinecraftProfileTexture.Type, MinecraftProfileTexture> getTextures(GameProfile profile, boolean requireSecure) {
+ return super.getTextures(profile, requireSecure);
+ }
+
+ @Override
+ public GameProfile fillProfileProperties(GameProfile profile, boolean requireSecure) {
+ return super.fillProfileProperties(profile, requireSecure);
+ }
+
+ @Override
+ protected GameProfile fillGameProfile(GameProfile profile, boolean requireSecure) {
+ return super.fillGameProfile(profile, requireSecure);
+ }
+}
diff --git a/src/main/java/com/destroystokyo/paper/profile/PaperUserAuthentication.java b/src/main/java/com/destroystokyo/paper/profile/PaperUserAuthentication.java
new file mode 100644
index 0000000000000000000000000000000000000000..3cdd06d3af7ff94f1fe1a11b9a9275e17c695a38
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/profile/PaperUserAuthentication.java
@@ -0,0 +1,12 @@
+package com.destroystokyo.paper.profile;
+
+import com.mojang.authlib.Agent;
+import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
+import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication;
+import java.util.UUID;
+
+public class PaperUserAuthentication extends YggdrasilUserAuthentication {
+ public PaperUserAuthentication(YggdrasilAuthenticationService authenticationService, Agent agent) {
+ super(authenticationService, UUID.randomUUID().toString(), agent);
+ }
+}
diff --git a/src/main/java/net/minecraft/server/MCUtil.java b/src/main/java/net/minecraft/server/MCUtil.java
index f0fed1d2c297d8d2a6903d2caa219b458c5e43c2..aa96017819712f42e16c7eac57222301600b66a5 100644
--- a/src/main/java/net/minecraft/server/MCUtil.java
+++ b/src/main/java/net/minecraft/server/MCUtil.java
@@ -1,5 +1,7 @@
package net.minecraft.server;
+import com.destroystokyo.paper.profile.CraftPlayerProfile;
+import com.destroystokyo.paper.profile.PlayerProfile;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import it.unimi.dsi.fastutil.objects.ObjectRBTreeSet;
import java.lang.ref.Cleaner;
@@ -11,6 +13,7 @@ import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import org.apache.commons.lang.exception.ExceptionUtils;
+import com.mojang.authlib.GameProfile;
import org.bukkit.Location;
import org.bukkit.block.BlockFace;
import org.bukkit.craftbukkit.CraftWorld;
@@ -349,6 +352,10 @@ public final class MCUtil {
return run.get();
}
+ public static PlayerProfile toBukkit(GameProfile profile) {
+ return CraftPlayerProfile.asBukkitMirror(profile);
+ }
+
/**
* Calculates distance between 2 entities
* @param e1
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index c8385460701395cb5c65fba41335469ffb2d9b9a..fb0b3c5770f66cc3590f5ac4e690a33cb6179be3 100644
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -130,7 +130,7 @@ public class Main {
}
File file = (File) optionset.valueOf("universe"); // CraftBukkit
- YggdrasilAuthenticationService yggdrasilauthenticationservice = new YggdrasilAuthenticationService(Proxy.NO_PROXY);
+ YggdrasilAuthenticationService yggdrasilauthenticationservice = new com.destroystokyo.paper.profile.PaperAuthenticationService(Proxy.NO_PROXY); // Paper
MinecraftSessionService minecraftsessionservice = yggdrasilauthenticationservice.createMinecraftSessionService();
GameProfileRepository gameprofilerepository = yggdrasilauthenticationservice.createProfileRepository();
GameProfileCache usercache = new GameProfileCache(gameprofilerepository, new File(file, MinecraftServer.USERID_CACHE_FILE.getName()));
diff --git a/src/main/java/net/minecraft/server/players/GameProfileCache.java b/src/main/java/net/minecraft/server/players/GameProfileCache.java
index 6e1b7d5b20e9f6ed1b650eb9d6ac9f8c4867b4b7..61405c2b53e03a4b83e2c70c6e4d3739ca9676cb 100644
--- a/src/main/java/net/minecraft/server/players/GameProfileCache.java
+++ b/src/main/java/net/minecraft/server/players/GameProfileCache.java
@@ -135,6 +135,13 @@ public class GameProfileCache {
return this.operationCount.incrementAndGet();
}
+ // Paper start
+ @Nullable public GameProfile getProfileIfCached(String name) {
+ GameProfileCache.GameProfileInfo entry = this.profilesByName.get(name.toLowerCase(Locale.ROOT));
+ return entry == null ? null : entry.getProfile();
+ }
+ // Paper end
+
public synchronized Optional<GameProfile> get(String name) { // Paper - synchronize
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 e01f800130f183bf10a383e298b7da3d5f11e3a2..a337967295f61f4892a2ae7dd65aeaba75a06172 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -246,6 +246,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 = "Paper"; // Paper
private final String serverVersion;
@@ -2494,5 +2497,24 @@ public final class CraftServer implements Server {
public boolean suggestPlayerNamesWhenNullTabCompletions() {
return com.destroystokyo.paper.PaperConfig.suggestPlayersWhenNullTabCompletions;
}
+
+ @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);
+ }
// Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
index 9405812b8c308d70de1e26ba55500301b24ecc3c..490df0dcfd0e1e0ab05943410493522f86444ef8 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
@@ -80,6 +80,13 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
}
private void setProfile(GameProfile profile) {
+ // Paper start
+ if (profile != null) {
+ com.destroystokyo.paper.profile.CraftPlayerProfile paperProfile = new com.destroystokyo.paper.profile.CraftPlayerProfile(profile);
+ paperProfile.completeFromCache(false, true);
+ profile = paperProfile.getGameProfile();
+ }
+ // Paper end
this.profile = profile;
this.serializedProfile = (profile == null) ? null : NbtUtils.writeGameProfile(new CompoundTag(), profile);
}

View file

@ -1,96 +0,0 @@
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 a4eb5de429f6934cf6f2b771d62db51e328f8987..193d73c53c7c3cc31246dd19c6d7ff4cb39cac1b 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -1951,20 +1951,44 @@ public abstract class Player extends LivingEntity {
}
+ // Paper start
+ public Entity releaseLeftShoulderEntity() {
+ Entity entity = this.spawnEntityFromShoulder0(this.getShoulderEntityLeft());
+ if (entity != null) {
+ this.setShoulderEntityLeft(new CompoundTag());
+ }
+ return entity;
+ }
+
+ public Entity releaseRightShoulderEntity() {
+ Entity entity = this.spawnEntityFromShoulder0(this.getShoulderEntityRight());
+ if (entity != null) {
+ this.setShoulderEntityRight(new CompoundTag());
+ }
+ return entity;
+ }
+ // Paper - maintain old signature
private boolean spawnEntityFromShoulder(CompoundTag nbttagcompound) { // CraftBukkit void->boolean
- if (!this.level.isClientSide && !nbttagcompound.isEmpty()) {
+ return spawnEntityFromShoulder0(nbttagcompound) != null;
+ }
+
+ // Paper - return entity
+ private Entity spawnEntityFromShoulder0(@Nullable CompoundTag nbttagcompound) {
+ if (!this.level.isClientSide && nbttagcompound != null && !nbttagcompound.isEmpty()) {
return EntityType.create(nbttagcompound, this.level).map((entity) -> { // CraftBukkit
if (entity instanceof TamableAnimal) {
((TamableAnimal) entity).setOwnerUUID(this.uuid);
}
entity.setPos(this.getX(), this.getY() + 0.699999988079071D, this.getZ());
- return ((ServerLevel) this.level).addEntitySerialized(entity, CreatureSpawnEvent.SpawnReason.SHOULDER_ENTITY); // CraftBukkit
- }).orElse(true); // CraftBukkit
+ boolean addedToWorld = ((ServerLevel) this.level).addEntitySerialized(entity, CreatureSpawnEvent.SpawnReason.SHOULDER_ENTITY); // CraftBukkit
+ return addedToWorld ? entity : null;
+ }).orElse(null); // CraftBukkit // Paper - false -> null
}
- return true; // CraftBukkit
+ return null; // Paper - return null
}
+ // Paper end
@Override
public abstract boolean isSpectator();
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
index 841dbf4a86b19d7c8ea41930ecb1f88c660fa117..54947f02f29dd3dc546ee0d0f4600630242f003d 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java
@@ -500,6 +500,32 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
this.getHandle().getCooldowns().addCooldown(CraftMagicNumbers.getItem(material), 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;

View file

@ -1,81 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 17 Jun 2017 17:00:32 -0400
Subject: [PATCH] Profile Lookup Events
Adds a Pre Lookup Event and a Post Lookup Event so that plugins may prefill in profile data, and cache the responses from
profiles that had to be looked up.
diff --git a/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java b/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java
index 582c169c85ac66f1f9430f79042e4655f776c157..08fdb681a68e8be6e4062af0630957ce3e524806 100644
--- a/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java
+++ b/src/main/java/com/destroystokyo/paper/profile/PaperGameProfileRepository.java
@@ -1,11 +1,16 @@
package com.destroystokyo.paper.profile;
+import com.destroystokyo.paper.event.profile.LookupProfileEvent;
+import com.destroystokyo.paper.event.profile.PreLookupProfileEvent;
+import com.google.common.collect.Sets;
import com.mojang.authlib.Agent;
import com.mojang.authlib.Environment;
+import com.mojang.authlib.GameProfile;
import com.mojang.authlib.ProfileLookupCallback;
import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
import com.mojang.authlib.yggdrasil.YggdrasilGameProfileRepository;
+import java.util.Set;
public class PaperGameProfileRepository extends YggdrasilGameProfileRepository {
public PaperGameProfileRepository(YggdrasilAuthenticationService authenticationService, Environment environment) {
super(authenticationService, environment);
@@ -13,6 +18,50 @@ public class PaperGameProfileRepository extends YggdrasilGameProfileRepository {
@Override
public void findProfilesByNames(String[] names, Agent agent, ProfileLookupCallback callback) {
- super.findProfilesByNames(names, agent, callback);
+ Set<String> unfoundNames = Sets.newHashSet();
+ for (String name : names) {
+ PreLookupProfileEvent event = new PreLookupProfileEvent(name);
+ event.callEvent();
+ if (event.getUUID() != null) {
+ // Plugin provided UUI, we can skip network call.
+ GameProfile gameprofile = new GameProfile(event.getUUID(), name);
+ // We might even have properties!
+ Set<ProfileProperty> profileProperties = event.getProfileProperties();
+ if (!profileProperties.isEmpty()) {
+ for (ProfileProperty property : profileProperties) {
+ gameprofile.getProperties().put(property.getName(), CraftPlayerProfile.asAuthlib(property));
+ }
+ }
+ callback.onProfileLookupSucceeded(gameprofile);
+ } else {
+ unfoundNames.add(name);
+ }
+ }
+
+ // Some things were not found.... Proceed to look up.
+ if (!unfoundNames.isEmpty()) {
+ String[] namesArr = unfoundNames.toArray(new String[unfoundNames.size()]);
+ super.findProfilesByNames(namesArr, agent, new PreProfileLookupCallback(callback));
+ }
+ }
+
+ private static class PreProfileLookupCallback implements ProfileLookupCallback {
+ private final ProfileLookupCallback callback;
+
+ PreProfileLookupCallback(ProfileLookupCallback callback) {
+ this.callback = callback;
+ }
+
+ @Override
+ public void onProfileLookupSucceeded(GameProfile gameProfile) {
+ PlayerProfile from = CraftPlayerProfile.asBukkitMirror(gameProfile);
+ new LookupProfileEvent(from).callEvent();
+ callback.onProfileLookupSucceeded(gameProfile);
+ }
+
+ @Override
+ public void onProfileLookupFailed(GameProfile gameProfile, Exception e) {
+ callback.onProfileLookupFailed(gameProfile, e);
+ }
}
}

View file

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Sun, 2 Jul 2017 21:35:56 -0500
Subject: [PATCH] Block player logins during server shutdown
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index a60b40d8cc802456374625af216c27998f8348b3..ab3409dd3a7671b46cba210cfa326311d10a7ef4 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -69,6 +69,12 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
}
public void tick() {
+ // Paper start - Do not allow logins while the server is shutting down
+ if (!MinecraftServer.getServer().isRunning()) {
+ this.disconnect(org.bukkit.craftbukkit.util.CraftChatMessage.fromString(org.spigotmc.SpigotConfig.restartMessage)[0]);
+ return;
+ }
+ // Paper end
if (this.state == ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT) {
this.handleAcceptedLogin();
} else if (this.state == ServerLoginPacketListenerImpl.State.DELAY_ACCEPT) {

View file

@ -1,65 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Sun, 18 Jun 2017 18:17:05 -0500
Subject: [PATCH] Entity#fromMobSpawner()
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index bf52f5f9b13e8b4eb3c7ee19b0e57bb872d2af1d..3b2334e9ba44205a4e0ec12045eab4fad91bb15a 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -322,6 +322,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
public final org.spigotmc.ActivationRange.ActivationType activationType = org.spigotmc.ActivationRange.initializeEntityActivationType(this);
public final boolean defaultActivationState;
public long activatedTick = Integer.MIN_VALUE;
+ public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one
protected int numCollisions = 0; // Paper
public void inactiveTick() { }
// Spigot end
@@ -1868,6 +1869,10 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
}
nbt.put("Paper.Origin", this.newDoubleList(origin.getX(), origin.getY(), origin.getZ()));
}
+ // Save entity's from mob spawner status
+ if (spawnedViaMobSpawner) {
+ nbt.putBoolean("Paper.FromMobSpawner", true);
+ }
// Paper end
return nbt;
} catch (Throwable throwable) {
@@ -2007,6 +2012,8 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
this.originWorld = originWorld;
origin = new org.bukkit.util.Vector(originTag.getDouble(0), originTag.getDouble(1), originTag.getDouble(2));
}
+
+ spawnedViaMobSpawner = nbt.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status
// Paper end
} catch (Throwable throwable) {
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
index 65744b55f06c225745e3e145e5f5e60ebefd304c..e720c751518af3f38fba0c1b22e4c01a46561b00 100644
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
@@ -167,6 +167,7 @@ public abstract class BaseSpawner {
}
// Spigot End
}
+ entity.spawnedViaMobSpawner = true; // Paper
// Spigot Start
if (org.bukkit.craftbukkit.event.CraftEventFactory.callSpawnerSpawnEvent(entity, pos).isCancelled()) {
Entity vehicle = entity.getVehicle();
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 78b3be2ea6351cb6375b77340218615aa75b87f5..a83d15178f71b1c4c6d8d49f7621eddd66577251 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -1192,5 +1192,10 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
//noinspection ConstantConditions
return originVector.toLocation(world);
}
+
+ @Override
+ public boolean fromMobSpawner() {
+ return getHandle().spawnedViaMobSpawner;
+ }
// Paper end
}

View file

@ -1,59 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 10 Dec 2016 16:24:06 -0500
Subject: [PATCH] Improve the Saddle API for Horses
Not all horses with Saddles have armor. This lets us break up the horses with saddles
and access their saddle state separately from an interface shared with Armor.
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java
index 6f473dbf949552afd288382b36223ea036eaa857..27a1ca43792644fc239af81dea5510f25d3328e9 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java
@@ -5,6 +5,7 @@ import net.minecraft.world.entity.ai.attributes.Attributes;
import org.apache.commons.lang.Validate;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.inventory.CraftInventoryAbstractHorse;
+import org.bukkit.craftbukkit.inventory.CraftSaddledInventory;
import org.bukkit.entity.AbstractHorse;
import org.bukkit.entity.AnimalTamer;
import org.bukkit.entity.Horse;
@@ -98,6 +99,6 @@ public abstract class CraftAbstractHorse extends CraftAnimals implements Abstrac
@Override
public AbstractHorseInventory getInventory() {
- return new CraftInventoryAbstractHorse(this.getHandle().inventory);
+ return new CraftSaddledInventory(getHandle().inventory);
}
}
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryHorse.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryHorse.java
index 7013059856c2471dc34112a1a2068b96b809dd96..b72b4260fc1c0e9928d70f97589d8db00849b9e8 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryHorse.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryHorse.java
@@ -4,7 +4,7 @@ import net.minecraft.world.Container;
import org.bukkit.inventory.HorseInventory;
import org.bukkit.inventory.ItemStack;
-public class CraftInventoryHorse extends CraftInventoryAbstractHorse implements HorseInventory {
+public class CraftInventoryHorse extends CraftSaddledInventory implements HorseInventory {
public CraftInventoryHorse(Container inventory) {
super(inventory);
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftSaddledInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftSaddledInventory.java
new file mode 100644
index 0000000000000000000000000000000000000000..3a617c07d445bacf5a13e0e3ff6481823cfc8477
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftSaddledInventory.java
@@ -0,0 +1,12 @@
+package org.bukkit.craftbukkit.inventory;
+
+import net.minecraft.world.Container;
+import org.bukkit.inventory.SaddledHorseInventory;
+
+public class CraftSaddledInventory extends CraftInventoryAbstractHorse implements SaddledHorseInventory {
+
+ public CraftSaddledInventory(Container inventory) {
+ super(inventory);
+ }
+
+}

View file

@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 4 May 2016 22:43:12 -0400
Subject: [PATCH] Implement ensureServerConversions API
This will take a Bukkit ItemStack and run it through any conversions a server process would perform on it,
to ensure it meets latest minecraft expectations.
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
index 69af359e0160480b77886ca35d8f8f3135f06455..73da393b26a7afd766b23716da454b0b68c26d5b 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
@@ -356,5 +356,11 @@ public final class CraftItemFactory implements ItemFactory {
public net.kyori.adventure.text.@org.jetbrains.annotations.NotNull Component displayName(@org.jetbrains.annotations.NotNull ItemStack itemStack) {
return io.papermc.paper.adventure.PaperAdventure.asAdventure(CraftItemStack.asNMSCopy(itemStack).getDisplayName());
}
+
+ // Paper start
+ @Override
+ public ItemStack ensureServerConversions(ItemStack item) {
+ return CraftItemStack.asCraftMirror(CraftItemStack.asNMSCopy(item));
+ }
// Paper end
}

View file

@ -1,32 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 4 May 2016 23:59:38 -0400
Subject: [PATCH] Implement getI18NDisplayName
Gets the Display name as seen in the Client.
Currently the server only supports the English language. To override this,
You must replace the language file embedded in the server jar.
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
index 73da393b26a7afd766b23716da454b0b68c26d5b..c50d3cee3dfebb62ad30f8d4efe23b5c7c9f2b57 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java
@@ -362,5 +362,18 @@ public final class CraftItemFactory implements ItemFactory {
public ItemStack ensureServerConversions(ItemStack item) {
return CraftItemStack.asCraftMirror(CraftItemStack.asNMSCopy(item));
}
+
+ @Override
+ public String getI18NDisplayName(ItemStack item) {
+ net.minecraft.world.item.ItemStack nms = null;
+ if (item instanceof CraftItemStack) {
+ nms = ((CraftItemStack) item).handle;
+ }
+ if (nms == null) {
+ nms = CraftItemStack.asNMSCopy(item);
+ }
+
+ return nms != null ? net.minecraft.locale.Language.getInstance().getOrDefault(nms.getItem().getDescriptionId()) : null;
+ }
// Paper end
}

View file

@ -1,50 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 3 Jul 2017 18:11:10 -0500
Subject: [PATCH] ProfileWhitelistVerifyEvent
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 0eea43c994e76b466fdda8ecd145d0b1c9273cea..17f56157d60d33695c4eac0e4fc94120a2101214 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -615,9 +615,9 @@ public abstract class PlayerList {
// return chatmessage;
event.disallow(PlayerLoginEvent.Result.KICK_BANNED, PaperAdventure.asAdventure(chatmessage)); // Paper - Adventure
- } else if (!this.isWhiteListed(gameprofile)) {
- chatmessage = new TranslatableComponent("multiplayer.disconnect.not_whitelisted");
- event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, PaperAdventure.LEGACY_SECTION_UXRC.deserialize(org.spigotmc.SpigotConfig.whitelistMessage)); // Spigot // Paper - Adventure
+ } else if (!this.isWhitelisted(gameprofile, event)) { // Paper
+ //chatmessage = new ChatMessage("multiplayer.disconnect.not_whitelisted"); // Paper
+ //event.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, org.spigotmc.SpigotConfig.whitelistMessage); // Spigot // Paper - moved to isWhitelisted
} else if (this.getIpBans().isBanned(socketaddress) && !this.getIpBans().get(socketaddress).hasExpired()) {
IpBanListEntry ipbanentry = this.ipBans.get(socketaddress);
@@ -998,9 +998,25 @@ public abstract class PlayerList {
this.server.getCommands().sendCommands(player);
}
+ // Paper start
public boolean isWhiteListed(GameProfile profile) {
- return !this.doWhiteList || this.ops.contains(profile) || this.whitelist.contains(profile);
+ return isWhitelisted(profile, null);
}
+ public boolean isWhitelisted(GameProfile gameprofile, org.bukkit.event.player.PlayerLoginEvent loginEvent) {
+ boolean isOp = this.ops.contains(gameprofile);
+ boolean isWhitelisted = !this.doWhiteList || isOp || this.whitelist.contains(gameprofile);
+ final com.destroystokyo.paper.event.profile.ProfileWhitelistVerifyEvent event;
+ event = new com.destroystokyo.paper.event.profile.ProfileWhitelistVerifyEvent(net.minecraft.server.MCUtil.toBukkit(gameprofile), this.doWhiteList, isWhitelisted, isOp, org.spigotmc.SpigotConfig.whitelistMessage);
+ event.callEvent();
+ if (!event.isWhitelisted()) {
+ if (loginEvent != null) {
+ loginEvent.disallow(PlayerLoginEvent.Result.KICK_WHITELIST, PaperAdventure.LEGACY_SECTION_UXRC.deserialize(event.getKickMessage() == null ? org.spigotmc.SpigotConfig.whitelistMessage : event.getKickMessage()));
+ }
+ return false;
+ }
+ return true;
+ }
+ // Paper end
public boolean isOp(GameProfile profile) {
return this.ops.contains(profile) || this.server.isSingleplayerOwner(profile) && this.server.getWorldData().getAllowCommands() || this.allowCheatsForAllPlayers;

View file

@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Kyle Wood <kyle@denwav.dev>
Date: Sun, 6 Aug 2017 17:17:53 -0500
Subject: [PATCH] Fix this stupid bullshit
Disable the 15 second sleep when the server jar hasn't been rebuilt within a period of time.
modified in order to prevent merge conflicts when Spigot changes/disables the warning,
and to provide some level of hint without being disruptive.
diff --git a/src/main/java/net/minecraft/server/Bootstrap.java b/src/main/java/net/minecraft/server/Bootstrap.java
index c7d5018cb6acef12e6da90626c75543ac279a101..64576ddd8363be55755fa50d1c16d95e4e02402d 100644
--- a/src/main/java/net/minecraft/server/Bootstrap.java
+++ b/src/main/java/net/minecraft/server/Bootstrap.java
@@ -42,7 +42,7 @@ public class Bootstrap {
public static void bootStrap() {
if (!Bootstrap.isBootstrapped) {
// CraftBukkit start
- String name = Bootstrap.class.getSimpleName();
+ /*String name = Bootstrap.class.getSimpleName(); // Paper - actually, I don't think this class should ever have been called DispenserRegistry, that's a stupid name, bootstrap is waaay better
switch (name) {
case "DispenserRegistry":
break;
@@ -56,7 +56,7 @@ public class Bootstrap {
System.err.println("*** WARNING: This server jar is unsupported, use at your own risk. ***");
System.err.println("**********************************************************************");
break;
- }
+ }*/ // Paper
// CraftBukkit end
Bootstrap.isBootstrapped = true;
if (Registry.REGISTRY.keySet().isEmpty()) {
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index bbf552bf586de94d8dfc5fb1c18e0af6f75aebe1..1da136f365664d4f8ace3d2d135b19eb97e55304 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -228,10 +228,12 @@ public class Main {
Calendar deadline = Calendar.getInstance();
deadline.add(Calendar.DAY_OF_YEAR, -28);
if (buildDate.before(deadline.getTime())) {
- System.err.println("*** Error, this build is outdated ***");
+ // Paper start - This is some stupid bullshit
+ System.err.println("*** Warning, you've not updated in a while! ***");
System.err.println("*** Please download a new build as per instructions from https://papermc.io/downloads ***"); // Paper
- System.err.println("*** Server will start in 20 seconds ***");
- Thread.sleep(TimeUnit.SECONDS.toMillis(20));
+ //System.err.println("*** Server will start in 20 seconds ***");
+ //Thread.sleep(TimeUnit.SECONDS.toMillis(20));
+ // Paper End
}
}

View file

@ -1,35 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Mon, 31 Jul 2017 01:49:48 -0500
Subject: [PATCH] LivingEntity#setKiller
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
index e955126fc82dfcdadb824c8d2d15e8b1f33bc67f..90b70935242757b5c302bac7777eb1428d69619e 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java
@@ -8,6 +8,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;
+import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffect;
@@ -344,6 +345,16 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity {
return this.getHandle().lastHurtByPlayer == null ? null : (Player) this.getHandle().lastHurtByPlayer.getBukkitEntity();
}
+ // Paper start
+ @Override
+ public void setKiller(Player killer) {
+ ServerPlayer entityPlayer = killer == null ? null : ((CraftPlayer) killer).getHandle();
+ getHandle().lastHurtByPlayer = entityPlayer;
+ getHandle().lastHurtByMob = entityPlayer;
+ getHandle().lastHurtByPlayerTime = entityPlayer == null ? 0 : 100; // 100 value taken from EntityLiving#damageEntity
+ }
+ // Paper end
+
@Override
public boolean addPotionEffect(PotionEffect effect) {
return this.addPotionEffect(effect, false);

View file

@ -1,19 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Mon, 31 Jul 2017 01:54:40 -0500
Subject: [PATCH] Ocelot despawns should honor nametags and leash
diff --git a/src/main/java/net/minecraft/world/entity/animal/Ocelot.java b/src/main/java/net/minecraft/world/entity/animal/Ocelot.java
index b223b54c80bdc2c9b620e5c9e44cab0c9abdd44c..49122e7baa5c0cd3691bcb48176fdefbdb79026b 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Ocelot.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Ocelot.java
@@ -133,7 +133,7 @@ public class Ocelot extends Animal {
@Override
public boolean removeWhenFarAway(double distanceSquared) {
- return !this.isTrusting() /*&& this.ticksLived > 2400*/; // CraftBukkit
+ return !this.isTrusting() && !this.hasCustomName() && !this.isLeashed() /*&& this.ticksLived > 2400*/; // CraftBukkit // Paper - honor name and leash
}
public static AttributeSupplier.Builder createAttributes() {

View file

@ -1,27 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Mon, 31 Jul 2017 01:45:19 -0500
Subject: [PATCH] Reset spawner timer when spawner event is cancelled
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
index e720c751518af3f38fba0c1b22e4c01a46561b00..14188ac6f158b36755abe23c0a967763cf7367d8 100644
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
@@ -168,6 +168,7 @@ public abstract class BaseSpawner {
// Spigot End
}
entity.spawnedViaMobSpawner = true; // Paper
+ flag = true; // Paper
// Spigot Start
if (org.bukkit.craftbukkit.event.CraftEventFactory.callSpawnerSpawnEvent(entity, pos).isCancelled()) {
Entity vehicle = entity.getVehicle();
@@ -191,7 +192,7 @@ public abstract class BaseSpawner {
((Mob) entity).spawnAnim();
}
- flag = true;
+ //flag = true; // Paper - moved up above cancellable event
}
}

View file

@ -1,43 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kashike <kashike@vq.lc>
Date: Thu, 17 Aug 2017 16:08:20 -0700
Subject: [PATCH] Allow specifying a custom "authentication servers down" kick
message
diff --git a/src/main/java/com/destroystokyo/paper/PaperConfig.java b/src/main/java/com/destroystokyo/paper/PaperConfig.java
index 7a69f9d9bb9c05474d8fbab22d626529a41a66a1..f4735cc330822183e098a67f2c0f00f21db9e137 100644
--- a/src/main/java/com/destroystokyo/paper/PaperConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperConfig.java
@@ -1,5 +1,6 @@
package com.destroystokyo.paper;
+import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import java.io.File;
@@ -285,4 +286,9 @@ public class PaperConfig {
private static void suggestPlayersWhenNull() {
suggestPlayersWhenNullTabCompletions = getBoolean("settings.suggest-player-names-when-null-tab-completions", suggestPlayersWhenNullTabCompletions);
}
+
+ public static String authenticationServersDownKickMessage = ""; // empty = use translatable message
+ private static void authenticationServersDownKickMessage() {
+ authenticationServersDownKickMessage = Strings.emptyToNull(getString("messages.kick.authentication-servers-down", authenticationServersDownKickMessage));
+ }
}
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index ab3409dd3a7671b46cba210cfa326311d10a7ef4..82d0979e3239dddf3951df4a8b65ae7319d3d5b5 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -297,6 +297,10 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
ServerLoginPacketListenerImpl.this.gameProfile = ServerLoginPacketListenerImpl.this.createFakeProfile(gameprofile);
ServerLoginPacketListenerImpl.this.state = ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT;
} else {
+ // Paper start
+ if (com.destroystokyo.paper.PaperConfig.authenticationServersDownKickMessage != null) {
+ ServerLoginPacketListenerImpl.this.disconnect(new TextComponent(com.destroystokyo.paper.PaperConfig.authenticationServersDownKickMessage));
+ } else // Paper end
ServerLoginPacketListenerImpl.this.disconnect(new TranslatableComponent("multiplayer.disconnect.authservers_down"));
ServerLoginPacketListenerImpl.LOGGER.error("Couldn't verify username because servers are unavailable");
}

View file

@ -1,71 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Minecrell <minecrell@minecrell.net>
Date: Thu, 21 Sep 2017 16:14:55 +0200
Subject: [PATCH] Handle plugin prefixes using Log4J configuration
Display logger name in the console for all loggers except the
root logger, Bukkit's logger ("Minecraft") and Minecraft loggers.
Since plugins now use the plugin name as logger name this will
restore the plugin prefixes without having to prepend them manually
to the log messages.
Logger prefixes are shown by default for all loggers except for
the root logger, the Minecraft/Mojang loggers and the Bukkit loggers.
This may cause additional prefixes to be disabled for plugins bypassing
the plugin logger.
diff --git a/build.gradle.kts b/build.gradle.kts
index 9b70376813531718c02082633e9f8105f4879a63..fc8ffeea3e808eb1381f85972adffc614937ef6d 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -25,7 +25,7 @@ dependencies {
all its classes to check if they are plugins.
Scanning takes about 1-2 seconds so adding this speeds up the server start.
*/
- runtimeOnly("org.apache.logging.log4j:log4j-core:2.14.1")
+ implementation("org.apache.logging.log4j:log4j-core:2.14.1") // Paper - implementation
// Paper end
implementation("org.apache.logging.log4j:log4j-iostreams:2.14.1") // Paper
implementation("org.apache.logging.log4j:log4j-api:2.14.1") // Paper
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
index f8a9d6a394f796634e4663ef4078a4c98447e13c..d73dfe72a54b621c0f944c90904df3e3bc709445 100644
--- a/src/main/java/org/spigotmc/SpigotConfig.java
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
@@ -290,7 +290,7 @@ public class SpigotConfig
private static void playerSample()
{
SpigotConfig.playerSample = SpigotConfig.getInt( "settings.sample-count", 12 );
- System.out.println( "Server Ping Player Sample Count: " + SpigotConfig.playerSample );
+ Bukkit.getLogger().log( Level.INFO, "Server Ping Player Sample Count: {0}", playerSample ); // Paper - Use logger
}
public static int playerShuffle;
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
index 620b9490e5f159080e50289d127404a1b56adbef..a8bdaaeaa1a9316848416f0533739b9b083ca151 100644
--- a/src/main/resources/log4j2.xml
+++ b/src/main/resources/log4j2.xml
@@ -5,10 +5,22 @@
<PatternLayout pattern="[%d{HH:mm:ss} %level]: %msg%n" />
</Queue>
<TerminalConsole name="TerminalConsole">
- <PatternLayout pattern="%highlightError{[%d{HH:mm:ss} %level]: %minecraftFormatting{%msg}%n%xEx}" />
+ <PatternLayout>
+ <LoggerNamePatternSelector defaultPattern="%highlightError{[%d{HH:mm:ss} %level]: [%logger] %minecraftFormatting{%msg}%n%xEx}">
+ <!-- Log root, Minecraft, Mojang and Bukkit loggers without prefix -->
+ <PatternMatch key=",net.minecraft.,Minecraft,com.mojang."
+ pattern="%highlightError{[%d{HH:mm:ss} %level]: %minecraftFormatting{%msg}%n%xEx}" />
+ </LoggerNamePatternSelector>
+ </PatternLayout>
</TerminalConsole>
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
- <PatternLayout pattern="[%d{HH:mm:ss}] [%t/%level]: %minecraftFormatting{%msg}{strip}%n" />
+ <PatternLayout>
+ <LoggerNamePatternSelector defaultPattern="[%d{HH:mm:ss}] [%t/%level]: [%logger] %minecraftFormatting{%msg}{strip}%n">
+ <!-- Log root, Minecraft, Mojang and Bukkit loggers without prefix -->
+ <PatternMatch key=",net.minecraft.,Minecraft,com.mojang."
+ pattern="[%d{HH:mm:ss}] [%t/%level]: %minecraftFormatting{%msg}{strip}%n" />
+ </LoggerNamePatternSelector>
+ </PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
<OnStartupTriggeringPolicy />

View file

@ -1,47 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Minecrell <minecrell@minecrell.net>
Date: Sat, 23 Sep 2017 21:07:20 +0200
Subject: [PATCH] Improve Log4J Configuration / Plugin Loggers
Add full exceptions to log4j to not truncate stack traces
Disable logger prefix for various plugins bypassing the plugin logger
Some plugins bypass the plugin logger and add the plugin prefix
manually to the log message. Since they use other logger names
(e.g. qualified class names) these would now also appear in the
log. Disable the logger prefix for these plugins so the messages
show up correctly.
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
index a8bdaaeaa1a9316848416f0533739b9b083ca151..476f4a5cbe664ddd05474cb88553018bd334a5b8 100644
--- a/src/main/resources/log4j2.xml
+++ b/src/main/resources/log4j2.xml
@@ -6,19 +6,21 @@
</Queue>
<TerminalConsole name="TerminalConsole">
<PatternLayout>
- <LoggerNamePatternSelector defaultPattern="%highlightError{[%d{HH:mm:ss} %level]: [%logger] %minecraftFormatting{%msg}%n%xEx}">
+ <LoggerNamePatternSelector defaultPattern="%highlightError{[%d{HH:mm:ss} %level]: [%logger] %minecraftFormatting{%msg}%n%xEx{full}}">
<!-- Log root, Minecraft, Mojang and Bukkit loggers without prefix -->
- <PatternMatch key=",net.minecraft.,Minecraft,com.mojang."
- pattern="%highlightError{[%d{HH:mm:ss} %level]: %minecraftFormatting{%msg}%n%xEx}" />
+ <!-- Disable prefix for various plugins that bypass the plugin logger -->
+ <PatternMatch key=",net.minecraft.,Minecraft,com.mojang.,com.sk89q.,ru.tehkode.,Minecraft.AWE"
+ pattern="%highlightError{[%d{HH:mm:ss} %level]: %minecraftFormatting{%msg}%n%xEx{full}}" />
</LoggerNamePatternSelector>
</PatternLayout>
</TerminalConsole>
<RollingRandomAccessFile name="File" fileName="logs/latest.log" filePattern="logs/%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout>
- <LoggerNamePatternSelector defaultPattern="[%d{HH:mm:ss}] [%t/%level]: [%logger] %minecraftFormatting{%msg}{strip}%n">
+ <LoggerNamePatternSelector defaultPattern="[%d{HH:mm:ss}] [%t/%level]: [%logger] %minecraftFormatting{%msg}{strip}%n%xEx{full}">
<!-- Log root, Minecraft, Mojang and Bukkit loggers without prefix -->
- <PatternMatch key=",net.minecraft.,Minecraft,com.mojang."
- pattern="[%d{HH:mm:ss}] [%t/%level]: %minecraftFormatting{%msg}{strip}%n" />
+ <!-- Disable prefix for various plugins that bypass the plugin logger -->
+ <PatternMatch key=",net.minecraft.,Minecraft,com.mojang.,com.sk89q.,ru.tehkode.,Minecraft.AWE"
+ pattern="[%d{HH:mm:ss}] [%t/%level]: %minecraftFormatting{%msg}{strip}%n%xEx{full}" />
</LoggerNamePatternSelector>
</PatternLayout>
<Policies>

View file

@ -1,46 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Thu, 28 Sep 2017 17:21:44 -0400
Subject: [PATCH] Add PlayerJumpEvent
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 41f1b355a8a90216964e89432244a7d6929c9152..7759bf2afb9edeaca24726aace9358a8d5eafc64 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1174,7 +1174,34 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
boolean flag = d8 > 0.0D;
if (this.player.isOnGround() && !packet.isOnGround() && flag) {
- this.player.jumpFromGround();
+ // Paper start - Add player jump event
+ Player player = this.getCraftPlayer();
+ Location from = new Location(player.getWorld(), lastPosX, lastPosY, lastPosZ, lastYaw, lastPitch); // Get the Players previous Event location.
+ Location to = player.getLocation().clone(); // Start off the To location as the Players current location.
+
+ // If the packet contains movement information then we update the To location with the correct XYZ.
+ if (packet.hasPos) {
+ to.setX(packet.x);
+ to.setY(packet.y);
+ to.setZ(packet.z);
+ }
+
+ // If the packet contains look information then we update the To location with the correct Yaw & Pitch.
+ if (packet.hasRot) {
+ to.setYaw(packet.yRot);
+ to.setPitch(packet.xRot);
+ }
+
+ com.destroystokyo.paper.event.player.PlayerJumpEvent event = new com.destroystokyo.paper.event.player.PlayerJumpEvent(player, from, to);
+
+ if (event.callEvent()) {
+ this.player.jumpFromGround();
+ } else {
+ from = event.getFrom();
+ this.internalTeleport(from.getX(), from.getY(), from.getZ(), from.getYaw(), from.getPitch(), Collections.emptySet(), false);
+ return;
+ }
+ // Paper end
}
this.player.move(MoverType.PLAYER, new Vec3(d7, d8, d9));

View file

@ -1,40 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Thu, 5 Oct 2017 01:54:07 +0100
Subject: [PATCH] handle PacketPlayInKeepAlive async
In 1.12.2, Mojang moved the processing of PacketPlayInKeepAlive off the main
thread, while entirely correct for the server, this causes issues with
plugins which are expecting the PlayerQuitEvent on the main thread.
In order to counteract some bad behavior, we will post handling of the
disconnection to the main thread, but leave the actual processing of the packet
off the main thread.
also adding some additional logging in order to help work out what is causing
random disconnections for clients.
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 89588d6478ebd7d4892dceb03026dff89e1844db..7b6e6e646511bc47d2215c512b4d839b3f3a1c55 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2771,14 +2771,18 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
@Override
public void handleKeepAlive(ServerboundKeepAlivePacket packet) {
- PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel()); // CraftBukkit
+ //PlayerConnectionUtils.ensureMainThread(packetplayinkeepalive, this, this.player.getWorldServer()); // CraftBukkit // Paper - This shouldn't be on the main thread
if (this.keepAlivePending && packet.getId() == this.keepAliveChallenge) {
int i = (int) (Util.getMillis() - this.keepAliveTime);
this.player.latency = (this.player.latency * 3 + i) / 4;
this.keepAlivePending = false;
} else if (!this.isSingleplayerOwner()) {
+ // Paper start - This needs to be handled on the main thread for plugins
+ server.submit(() -> {
this.disconnect(new TranslatableComponent("disconnect.timeout"));
+ });
+ // Paper end
}
}

View file

@ -1,116 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Minecrell <minecrell@minecrell.net>
Date: Tue, 10 Oct 2017 18:45:20 +0200
Subject: [PATCH] Expose client protocol version and virtual host
diff --git a/src/main/java/com/destroystokyo/paper/network/PaperNetworkClient.java b/src/main/java/com/destroystokyo/paper/network/PaperNetworkClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..a5a7624f1f372a26b982836cd31cff15e2589e9b
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/network/PaperNetworkClient.java
@@ -0,0 +1,49 @@
+package com.destroystokyo.paper.network;
+
+import java.net.InetSocketAddress;
+
+import javax.annotation.Nullable;
+import net.minecraft.network.Connection;
+
+public class PaperNetworkClient implements NetworkClient {
+
+ private final Connection networkManager;
+
+ PaperNetworkClient(Connection networkManager) {
+ this.networkManager = networkManager;
+ }
+
+ @Override
+ public InetSocketAddress getAddress() {
+ return (InetSocketAddress) this.networkManager.getRemoteAddress();
+ }
+
+ @Override
+ public int getProtocolVersion() {
+ return this.networkManager.protocolVersion;
+ }
+
+ @Nullable
+ @Override
+ public InetSocketAddress getVirtualHost() {
+ return this.networkManager.virtualHost;
+ }
+
+ public static InetSocketAddress prepareVirtualHost(String host, int port) {
+ int len = host.length();
+
+ // FML appends a marker to the host to recognize FML clients (\0FML\0)
+ int pos = host.indexOf('\0');
+ if (pos >= 0) {
+ len = pos;
+ }
+
+ // When clients connect with a SRV record, their host contains a trailing '.'
+ if (len > 0 && host.charAt(len - 1) == '.') {
+ len--;
+ }
+
+ return InetSocketAddress.createUnresolved(host.substring(0, len), port);
+ }
+
+}
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
index b62e373445406ae84b37ec0570ebb1da02cff0b7..06e965996a5c50bce617847e594ae0dd83403484 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -83,6 +83,10 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
private float averageSentPackets;
private int tickCount;
private boolean handlingFault;
+ // Paper start - NetworkClient implementation
+ public int protocolVersion;
+ public java.net.InetSocketAddress virtualHost;
+ // Paper end
public Connection(PacketFlow side) {
this.receiving = side;
diff --git a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
index c4ba069f5124ec151e05813beddf293fddc3b804..484221e5a9c246aa91e0eacef3911b0e9ecff401 100644
--- a/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
@@ -150,6 +150,10 @@ public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketL
throw new UnsupportedOperationException("Invalid intention " + packet.getIntention());
}
+ // Paper start - NetworkClient implementation
+ this.connection.protocolVersion = packet.getProtocolVersion();
+ this.connection.virtualHost = com.destroystokyo.paper.network.PaperNetworkClient.prepareVirtualHost(packet.hostName, packet.port);
+ // Paper end
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 4233f5ffa673801c57e3f929cd9ae919d6c7169f..e5e12d1672588138e4f56007fcdd14a1bb8ec1ca 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -193,6 +193,20 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
}
+ // Paper start - Implement NetworkClient
+ @Override
+ public int getProtocolVersion() {
+ if (getHandle().connection == null) return -1;
+ return getHandle().connection.connection.protocolVersion;
+ }
+
+ @Override
+ public InetSocketAddress getVirtualHost() {
+ if (getHandle().connection == null) return null;
+ return getHandle().connection.connection.virtualHost;
+ }
+ // Paper end
+
@Override
public double getEyeHeight(boolean ignorePose) {
if (ignorePose) {

View file

@ -1,77 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Sun, 15 Oct 2017 00:29:07 +0100
Subject: [PATCH] revert serverside behavior of keepalives
This patch intends to bump up the time that a client has to reply to the
server back to 30 seconds as per pre 1.12.2, which allowed clients
more than enough time to reply potentially allowing them to be less
tempermental due to lag spikes on the network thread, e.g. that caused
by plugins that are interacting with netty.
We also add a system property to allow people to tweak how long the server
will wait for a reply. There is a compromise here between lower and higher
values, lower values will mean that dead connections can be closed sooner,
whereas higher values will make this less sensitive to issues such as spikes
from networking or during connections flood of chunk packets on slower clients,
at the cost of dead connections being kept open for longer.
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 652703b1582e63148658a3a9d2604afa55674c23..cf42d59254f2786bfe8785249ad270d35996417a 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -221,9 +221,9 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
private final MinecraftServer server;
public ServerPlayer player;
private int tickCount;
- private long keepAliveTime; @Deprecated private void setLastPing(long lastPing) { this.keepAliveTime = lastPing;}; @Deprecated private long getLastPing() { return this.keepAliveTime;}; // Paper - OBFHELPER
- private boolean keepAlivePending; @Deprecated private void setPendingPing(boolean isPending) { this.keepAlivePending = isPending;}; @Deprecated private boolean isPendingPing() { return this.keepAlivePending;}; // Paper - OBFHELPER
- private long keepAliveChallenge; @Deprecated private void setKeepAliveID(long keepAliveID) { this.keepAliveChallenge = keepAliveID;}; @Deprecated private long getKeepAliveID() {return this.keepAliveChallenge; }; // Paper - OBFHELPER
+ private long keepAliveTime = Util.getMillis();
+ private boolean keepAlivePending;
+ private long keepAliveChallenge;
// CraftBukkit start - multithreaded fields
private AtomicInteger chatSpamTickCount = new AtomicInteger();
// CraftBukkit end
@@ -252,6 +252,7 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
private int aboveGroundVehicleTickCount;
private int receivedMovePacketCount;
private int knownMovePacketCount;
+ private static final long KEEPALIVE_LIMIT = Long.getLong("paper.playerconnection.keepalive", 30) * 1000; // Paper - provide property to set keepalive limit
public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player) {
this.server = server;
@@ -334,18 +335,25 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
}
this.server.getProfiler().push("keepAlive");
- long i = Util.getMillis();
-
- if (i - this.keepAliveTime >= 25000L) { // CraftBukkit
- if (this.keepAlivePending) {
- this.disconnect(new TranslatableComponent("disconnect.timeout"));
- } else {
+ // Paper Start - give clients a longer time to respond to pings as per pre 1.12.2 timings
+ // This should effectively place the keepalive handling back to "as it was" before 1.12.2
+ long currentTime = Util.getMillis();
+ long elapsedTime = currentTime - this.keepAliveTime;
+
+ if (this.keepAlivePending) {
+ if (!this.processedDisconnect && elapsedTime >= KEEPALIVE_LIMIT) { // check keepalive limit, don't fire if already disconnected
+ ServerGamePacketListenerImpl.LOGGER.warn("{} was kicked due to keepalive timeout!", this.player.getScoreboardName()); // more info
+ this.disconnect(new TranslatableComponent("disconnect.timeout", new Object[0]));
+ }
+ } else {
+ if (elapsedTime >= 15000L) { // 15 seconds
this.keepAlivePending = true;
- this.keepAliveTime = i;
- this.keepAliveChallenge = i;
+ this.keepAliveTime = currentTime;
+ this.keepAliveChallenge = currentTime;
this.send(new ClientboundKeepAlivePacket(this.keepAliveChallenge));
}
}
+ // Paper end
this.server.getProfiler().pop();
// CraftBukkit start

View file

@ -1,80 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Brokkonaut <hannos17@gmx.de>
Date: Tue, 31 Oct 2017 03:26:18 +0100
Subject: [PATCH] Send attack SoundEffects only to players who can see the
attacker
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 193d73c53c7c3cc31246dd19c6d7ff4cb39cac1b..8c20af91c9298cb36fdb2700d042b1e2fccf5f54 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -30,6 +30,7 @@ import net.minecraft.network.chat.MutableComponent;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket;
+import net.minecraft.network.protocol.game.ClientboundSoundPacket;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
@@ -1181,7 +1182,7 @@ public abstract class Player extends LivingEntity {
int i = b0 + EnchantmentHelper.getKnockbackBonus((LivingEntity) this);
if (this.isSprinting() && flag) {
- this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_KNOCKBACK, this.getSoundSource(), 1.0F, 1.0F);
+ sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_KNOCKBACK, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
++i;
flag1 = true;
}
@@ -1256,7 +1257,7 @@ public abstract class Player extends LivingEntity {
}
}
- this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_SWEEP, this.getSoundSource(), 1.0F, 1.0F);
+ sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_SWEEP, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
this.sweepAttack();
}
@@ -1284,15 +1285,15 @@ public abstract class Player extends LivingEntity {
}
if (flag2) {
- this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_CRIT, this.getSoundSource(), 1.0F, 1.0F);
+ sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_CRIT, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
this.crit(target);
}
if (!flag2 && !flag3) {
if (flag) {
- this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_STRONG, this.getSoundSource(), 1.0F, 1.0F);
+ sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_STRONG, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
} else {
- this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_WEAK, this.getSoundSource(), 1.0F, 1.0F);
+ sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_WEAK, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
}
}
@@ -1344,7 +1345,7 @@ public abstract class Player extends LivingEntity {
this.applyExhaustion(level.spigotConfig.combatExhaustion, EntityExhaustionEvent.ExhaustionReason.ATTACK); // CraftBukkit - EntityExhaustionEvent // Spigot - Change to use configurable value
} else {
- this.level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource(), 1.0F, 1.0F);
+ sendSoundEffect(this, this.getX(), this.getY(), this.getZ(), SoundEvents.PLAYER_ATTACK_NODAMAGE, this.getSoundSource(), 1.0F, 1.0F); // Paper - send while respecting visibility
if (flag4) {
target.clearFire();
}
@@ -1791,6 +1792,14 @@ public abstract class Player extends LivingEntity {
public int getXpNeededForNextLevel() {
return this.experienceLevel >= 30 ? 112 + (this.experienceLevel - 30) * 9 : (this.experienceLevel >= 15 ? 37 + (this.experienceLevel - 15) * 5 : 7 + this.experienceLevel * 2);
}
+ // Paper start - send SoundEffect to everyone who can see fromEntity
+ private static void sendSoundEffect(Player fromEntity, double x, double y, double z, SoundEvent soundEffect, SoundSource soundCategory, float volume, float pitch) {
+ fromEntity.level.playSound(fromEntity, x, y, z, soundEffect, soundCategory, volume, pitch); // This will not send the effect to the entity himself
+ if (fromEntity instanceof ServerPlayer) {
+ ((ServerPlayer) fromEntity).connection.send(new ClientboundSoundPacket(soundEffect, soundCategory, x, y, z, volume, pitch));
+ }
+ }
+ // Paper end
// CraftBukkit start
public void causeFoodExhaustion(float exhaustion) {

View file

@ -1,31 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: pkt77 <parkerkt77@gmail.com>
Date: Fri, 10 Nov 2017 23:46:34 -0500
Subject: [PATCH] Add PlayerArmorChangeEvent
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 5f24963bd2681cab15d20221154a9a758be53b03..375959ed616596e604dc07d3b30d708b08d7ce57 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -1,5 +1,6 @@
package net.minecraft.world.entity;
+import com.destroystokyo.paper.event.player.PlayerArmorChangeEvent; // Paper
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -2941,6 +2942,13 @@ public abstract class LivingEntity extends Entity {
ItemStack itemstack1 = this.getItemBySlot(enumitemslot);
if (!ItemStack.matches(itemstack1, itemstack)) {
+ // Paper start - PlayerArmorChangeEvent
+ if (this instanceof ServerPlayer && enumitemslot.getType() == EquipmentSlot.Type.ARMOR) {
+ final org.bukkit.inventory.ItemStack oldItem = CraftItemStack.asBukkitCopy(itemstack);
+ final org.bukkit.inventory.ItemStack newItem = CraftItemStack.asBukkitCopy(itemstack1);
+ new PlayerArmorChangeEvent((Player) this.getBukkitEntity(), PlayerArmorChangeEvent.SlotType.valueOf(enumitemslot.name()), oldItem, newItem).callEvent();
+ }
+ // Paper end
if (map == null) {
map = Maps.newEnumMap(EquipmentSlot.class);
}

View file

@ -1,24 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: killme <killme-git@ibts.me>
Date: Sun, 12 Nov 2017 19:40:01 +0100
Subject: [PATCH] Prevent logins from being processed when the player has
disconnected
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index 82d0979e3239dddf3951df4a8b65ae7319d3d5b5..109d7f1bf37e442ff80f7f63d50e27e6e30e0b5e 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -76,7 +76,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
}
// Paper end
if (this.state == ServerLoginPacketListenerImpl.State.READY_TO_ACCEPT) {
- this.handleAcceptedLogin();
+ // Paper start - prevent logins to be processed even though disconnect was called
+ if (connection.isConnected()) {
+ this.handleAcceptedLogin();
+ }
+ // Paper end
} else if (this.state == ServerLoginPacketListenerImpl.State.DELAY_ACCEPT) {
ServerPlayer entityplayer = this.server.getPlayerList().getPlayer(this.gameProfile.getId());

View file

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: mezz <tehgeek@gmail.com>
Date: Wed, 9 Aug 2017 17:51:22 -0500
Subject: [PATCH] Fix MC-117075: TE Unload Lag Spike
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index acfa844c87e5814c033cad4318813800f57885fd..b327e10a5708d523b9d4a6c77c1359521f2927d5 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -730,6 +730,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// Spigot start
// Iterator iterator = this.blockEntityTickers.iterator();
int tilesThisCycle = 0;
+ var toRemove = new it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet<TickingBlockEntity>(net.minecraft.Util.identityStrategy()); // Paper - use removeAll
+ toRemove.add(null);
for (tileTickPosition = 0; tileTickPosition < this.blockEntityTickers.size(); tileTickPosition++) { // Paper - Disable tick limiters
this.tileTickPosition = (this.tileTickPosition < this.blockEntityTickers.size()) ? this.tileTickPosition : 0;
TickingBlockEntity tickingblockentity = (TickingBlockEntity) this.blockEntityTickers.get(tileTickPosition);
@@ -737,7 +739,6 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
if (tickingblockentity == null) {
this.getCraftServer().getLogger().severe("Spigot has detected a null entity and has removed it, preventing a crash");
tilesThisCycle--;
- this.blockEntityTickers.remove(this.tileTickPosition--);
continue;
}
// Spigot end
@@ -745,12 +746,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
if (tickingblockentity.isRemoved()) {
// Spigot start
tilesThisCycle--;
- this.blockEntityTickers.remove(this.tileTickPosition--);
+ toRemove.add(tickingblockentity); // Paper - use removeAll
// Spigot end
} else {
tickingblockentity.tick();
}
}
+ this.blockEntityTickers.removeAll(toRemove);
timings.tileEntityTick.stopTiming(); // Spigot
this.tickingBlockEntities = false;

View file

@ -1,60 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Thu, 16 Nov 2017 12:12:41 +0000
Subject: [PATCH] use CB BlockState implementations for captured blocks
When modifying the world, CB will store a copy of the affected
blocks in order to restore their state in the case that the event
is cancelled. This change only modifies the collection of blocks
in the world by normal means, e.g. not during tree population,
as the potentially marginal overheads would serve no advantage.
CB was using a CraftBlockState for all blocks, which causes issues
should any block that uses information beyond a data ID would suffer
from missing information, e.g. Skulls.
By using CBs CraftBlock#getState(), we will maintain a proper copy of
the blockstate that will be valid for restoration, as opposed to dropping
information on restoration when the event is cancelled.
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index b327e10a5708d523b9d4a6c77c1359521f2927d5..233a8fcfae4ac568ad1f73cc61d8ae5b66a01ac2 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -141,7 +141,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
public boolean preventPoiUpdated = false; // CraftBukkit - SPIGOT-5710
public boolean captureBlockStates = false;
public boolean captureTreeGeneration = false;
- public Map<BlockPos, CapturedBlockState> capturedBlockStates = new java.util.LinkedHashMap<>();
+ public Map<BlockPos, org.bukkit.craftbukkit.block.CraftBlockState> capturedBlockStates = new java.util.LinkedHashMap<>(); // Paper
public Map<BlockPos, BlockEntity> capturedTileEntities = new HashMap<>();
public List<ItemEntity> captureDrops;
public long ticksPerAnimalSpawns;
@@ -361,7 +361,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) {
// CraftBukkit start - tree generation
if (this.captureTreeGeneration) {
- CapturedBlockState blockstate = this.capturedBlockStates.get(pos);
+ CraftBlockState blockstate = this.capturedBlockStates.get(pos);
if (blockstate == null) {
blockstate = CapturedBlockState.getTreeBlockState(this, pos, flags);
this.capturedBlockStates.put(pos.immutable(), blockstate);
@@ -381,7 +381,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
// CraftBukkit start - capture blockstates
boolean captured = false;
if (this.captureBlockStates && !this.capturedBlockStates.containsKey(pos)) {
- CapturedBlockState blockstate = CapturedBlockState.getBlockState(this, pos, flags);
+ CraftBlockState blockstate = (CraftBlockState) world.getBlockAt(pos.getX(), pos.getY(), pos.getZ()).getState(); // Paper - use CB getState to get a suitable snapshot
+ blockstate.setFlag(flags); // Paper - set flag
this.capturedBlockStates.put(pos.immutable(), blockstate);
captured = true;
}
@@ -650,7 +651,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
public BlockState getBlockState(BlockPos pos) {
// CraftBukkit start - tree generation
if (this.captureTreeGeneration) {
- CapturedBlockState previous = this.capturedBlockStates.get(pos);
+ CraftBlockState previous = this.capturedBlockStates.get(pos); // Paper
if (previous != null) {
return previous.getHandle();
}

View file

@ -1,125 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Mon, 6 Nov 2017 21:08:22 -0500
Subject: [PATCH] API to get a BlockState without a snapshot
This allows you to get a BlockState without creating a snapshot, operating
on the real tile entity.
This is useful for where performance is needed
also Avoid NPE during CraftBlockEntityState load if could not get TE
If Tile Entity was null, correct Sign to return empty lines instead of null
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
index 27895fbe1cd7ee6ee025ed3e320671e3e971764d..1d1764766d2b4a0b7bf4078ce428bb1474f709df 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -42,6 +42,7 @@ public abstract class BlockEntity implements net.minecraft.server.KeyedObject {
this.type = type;
this.worldPosition = pos.immutable();
this.blockState = state;
+ this.persistentDataContainer = new CraftPersistentDataContainer(DATA_TYPE_REGISTRY); // Paper - always init
}
// Paper start
@@ -79,7 +80,7 @@ public abstract class BlockEntity implements net.minecraft.server.KeyedObject {
// CraftBukkit start - read container
public void load(CompoundTag nbt) {
- this.persistentDataContainer = new CraftPersistentDataContainer(BlockEntity.DATA_TYPE_REGISTRY);
+ this.persistentDataContainer.clear(); // Paper - clear instead of init
net.minecraft.nbt.Tag persistentDataTag = nbt.get("PublicBukkitValues");
if (persistentDataTag instanceof CompoundTag) {
@@ -222,10 +223,15 @@ public abstract class BlockEntity implements net.minecraft.server.KeyedObject {
// CraftBukkit start - add method
public InventoryHolder getOwner() {
+ // Paper start
+ return getOwner(true);
+ }
+ public InventoryHolder getOwner(boolean useSnapshot) {
+ // Paper end
if (this.level == null) return null;
org.bukkit.block.Block block = this.level.getWorld().getBlockAt(this.worldPosition.getX(), this.worldPosition.getY(), this.worldPosition.getZ());
if (block.getType() == org.bukkit.Material.AIR) return null;
- org.bukkit.block.BlockState state = block.getState();
+ org.bukkit.block.BlockState state = block.getState(useSnapshot); // Paper
if (state instanceof InventoryHolder) return (InventoryHolder) state;
return null;
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
index e6b8dd52cd503f45ca9bb868891ae4c8b29b3fcb..f1c4c3a3392c2d4d836fa10d7a38558d08084d9d 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
@@ -314,7 +314,20 @@ public class CraftBlock implements Block {
@Override
public BlockState getState() {
+ // Paper start
+ return this.getState(true);
+ }
+
+ @Override
+ public BlockState getState(boolean useSnapshot) {
+ boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT;
+ CraftBlockEntityState.DISABLE_SNAPSHOT = !useSnapshot;
+ try {
return CraftBlockStates.getBlockState(this);
+ } finally {
+ CraftBlockEntityState.DISABLE_SNAPSHOT = prev;
+ }
+ // Paper end
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
index 2fb445e6edc43eb8e3e169cca3fc3b46ced94202..059a122ef7038f7c4e269b476eb6e013b3eb4531 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
@@ -10,15 +10,26 @@ public abstract class CraftBlockEntityState<T extends BlockEntity> extends Craft
private final T tileEntity;
private final T snapshot;
+ public final boolean snapshotDisabled; // Paper
+ public static boolean DISABLE_SNAPSHOT = false; // Paper
public CraftBlockEntityState(World world, T tileEntity) {
super(world, tileEntity.getBlockPos(), tileEntity.getBlockState());
this.tileEntity = tileEntity;
+ // Paper start
+ this.snapshotDisabled = DISABLE_SNAPSHOT;
+ if (DISABLE_SNAPSHOT) {
+ this.snapshot = this.tileEntity;
+ } else {
+ this.snapshot = this.createSnapshot(tileEntity);
+ }
// copy tile entity data:
- this.snapshot = this.createSnapshot(tileEntity);
- this.load(snapshot);
+ if (this.snapshot != null) {
+ this.load(this.snapshot);
+ }
+ // Paper end
}
public void refreshSnapshot() {
diff --git a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
index ddd7b63f0452042baa3fca04bb9fbdb42fcecbfd..b638351581fa09c488425a2318b782a5812140ce 100644
--- a/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
+++ b/src/main/java/org/bukkit/craftbukkit/persistence/CraftPersistentDataContainer.java
@@ -155,4 +155,10 @@ public final class CraftPersistentDataContainer implements PersistentDataContain
public Map<String, Object> serialize() {
return (Map<String, Object>) CraftNBTTagConfigSerializer.serialize(this.toTagCompound());
}
+
+ // Paper start
+ public void clear() {
+ this.customDataTags.clear();
+ }
+ // Paper end
}

View file

@ -1,130 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 26 Nov 2017 13:19:58 -0500
Subject: [PATCH] AsyncTabCompleteEvent
Let plugins be able to control tab completion of commands and chat async.
This will be useful for frameworks like ACF so we can define async safe completion handlers,
and avoid going to main for tab completions.
Especially useful if you need to query a database in order to obtain the results for tab
completion, such as offline players.
Also adds isCommand and getLocation to the sync TabCompleteEvent
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index cf42d59254f2786bfe8785249ad270d35996417a..8c2242d7e443bee26741608c65d314d8902f5765 100644
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -702,10 +702,10 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
@Override
public void handleCustomCommandSuggestions(ServerboundCommandSuggestionPacket packet) {
- PacketUtils.ensureRunningOnSameThread(packet, this, this.player.getLevel());
+ // PlayerConnectionUtils.ensureMainThread(packetplayintabcomplete, this, this.player.getWorldServer()); // Paper - run this async
// CraftBukkit start
if (this.chatSpamTickCount.addAndGet(1) > 500 && !this.server.getPlayerList().isOp(this.player.getGameProfile())) {
- this.disconnect(new TranslatableComponent("disconnect.spam", new Object[0]));
+ server.scheduleOnMain(() -> this.disconnect(new TranslatableComponent("disconnect.spam", new Object[0]))); // Paper
return;
}
// CraftBukkit end
@@ -715,12 +715,35 @@ public class ServerGamePacketListenerImpl implements ServerPlayerConnection, Ser
stringreader.skip();
}
- ParseResults<CommandSourceStack> parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack());
+ // Paper start - async tab completion
+ com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event;
+ java.util.List<String> completions = new java.util.ArrayList<>();
+ String buffer = packet.getCommand();
+ event = new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(this.getCraftPlayer(), completions,
+ buffer, true, null);
+ event.callEvent();
+ completions = event.isCancelled() ? com.google.common.collect.ImmutableList.of() : event.getCompletions();
+ // If the event isn't handled, we can assume that we have no completions, and so we'll ask the server
+ if (!event.isHandled()) {
+ if (!event.isCancelled()) {
+
+ this.server.scheduleOnMain(() -> { // Paper - This needs to be on main
+ ParseResults<CommandSourceStack> parseresults = this.server.getCommands().getDispatcher().parse(stringreader, this.player.createCommandSourceStack());
- this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> {
- if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [<args>] from showing for plugins with nothing more to offer
- this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions));
- });
+ this.server.getCommands().getDispatcher().getCompletionSuggestions(parseresults).thenAccept((suggestions) -> {
+ if (suggestions.isEmpty()) return; // CraftBukkit - don't send through empty suggestions - prevents [<args>] from showing for plugins with nothing more to offer
+ this.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), suggestions));
+ });
+ });
+ }
+ } else if (!completions.isEmpty()) {
+ com.mojang.brigadier.suggestion.SuggestionsBuilder builder = new com.mojang.brigadier.suggestion.SuggestionsBuilder(packet.getCommand(), stringreader.getTotalLength());
+
+ builder = builder.createOffset(builder.getInput().lastIndexOf(' ') + 1);
+ completions.forEach(builder::suggest);
+ player.connection.send(new ClientboundCommandSuggestionsPacket(packet.getId(), builder.buildFuture().join()));
+ }
+ // Paper end - async tab completion
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index a337967295f61f4892a2ae7dd65aeaba75a06172..435a68e6c99bffdc8d6ded9deda68d4e970a2d49 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -2015,7 +2015,7 @@ public final class CraftServer implements Server {
offers = this.tabCompleteChat(player, message);
}
- TabCompleteEvent tabEvent = new TabCompleteEvent(player, message, offers);
+ TabCompleteEvent tabEvent = new TabCompleteEvent(player, message, offers, message.startsWith("/") || forceCommand, pos != null ? net.minecraft.server.MCUtil.toLocation(((CraftWorld) player.getWorld()).getHandle(), new BlockPos(pos)) : null); // Paper
this.getPluginManager().callEvent(tabEvent);
return tabEvent.isCancelled() ? Collections.EMPTY_LIST : tabEvent.getCompletions();
diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
index b996fde481cebbbcce80a6c267591136db7cc0bc..e5af155d75f717d33c23e22ff8b96bb3ff87844d 100644
--- a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
+++ b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java
@@ -28,6 +28,39 @@ public class ConsoleCommandCompleter implements Completer {
public void complete(LineReader reader, ParsedLine line, List<Candidate> candidates) {
final CraftServer server = this.server.server;
final String buffer = line.line();
+ // Async Tab Complete
+ com.destroystokyo.paper.event.server.AsyncTabCompleteEvent event;
+ java.util.List<String> completions = new java.util.ArrayList<>();
+ event = new com.destroystokyo.paper.event.server.AsyncTabCompleteEvent(server.getConsoleSender(), completions,
+ buffer, true, null);
+ event.callEvent();
+ completions = event.isCancelled() ? com.google.common.collect.ImmutableList.of() : event.getCompletions();
+
+ if (event.isCancelled() || event.isHandled()) {
+ // Still fire sync event with the provided completions, if someone is listening
+ if (!event.isCancelled() && TabCompleteEvent.getHandlerList().getRegisteredListeners().length > 0) {
+ List<String> finalCompletions = completions;
+ Waitable<List<String>> syncCompletions = new Waitable<List<String>>() {
+ @Override
+ protected List<String> evaluate() {
+ org.bukkit.event.server.TabCompleteEvent syncEvent = new org.bukkit.event.server.TabCompleteEvent(server.getConsoleSender(), buffer, finalCompletions);
+ return syncEvent.callEvent() ? syncEvent.getCompletions() : com.google.common.collect.ImmutableList.of();
+ }
+ };
+ server.getServer().processQueue.add(syncCompletions);
+ try {
+ completions = syncCompletions.get();
+ } catch (InterruptedException | ExecutionException e1) {
+ e1.printStackTrace();
+ }
+ }
+
+ if (!completions.isEmpty()) {
+ candidates.addAll(completions.stream().map(Candidate::new).collect(java.util.stream.Collectors.toList()));
+ }
+ return;
+ }
+
// Paper end
Waitable<List<String>> waitable = new Waitable<List<String>>() {
@Override

View file

@ -1,20 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 19 Dec 2017 22:02:53 -0500
Subject: [PATCH] PlayerPickupExperienceEvent
Allows plugins to cancel a player picking up an experience orb
diff --git a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
index 5220e3ee9fab4c4cbc95e0cf1928392316a35e34..1fdfeaa7758497e93fc13b44996e11d74a812546 100644
--- a/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
+++ b/src/main/java/net/minecraft/world/entity/ExperienceOrb.java
@@ -300,7 +300,7 @@ public class ExperienceOrb extends Entity {
@Override
public void playerTouch(Player player) {
if (!this.level.isClientSide) {
- if (player.takeXpDelay == 0) {
+ if (player.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper
player.takeXpDelay = 2;
player.take(this, 1);
int i = this.repairPlayerItems(player, this.value);

View file

@ -1,87 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 20 Dec 2017 17:36:49 -0500
Subject: [PATCH] Ability to apply mending to XP API
This allows plugins that give players the ability to apply the experience
points to the Item Mending formula, which will repair an item instead
of giving the player experience points.
Both an API To standalone mend, and apply mending logic to .giveExp has been added.
diff --git a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java
index 6f25e9f41d93a225acaa6575954967438a6cabbf..d439e8ce87bf7da03683a336941c7673b8b166e4 100644
--- a/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java
+++ b/src/main/java/net/minecraft/world/item/enchantment/EnchantmentHelper.java
@@ -270,8 +270,11 @@ public class EnchantmentHelper {
return getItemEnchantmentLevel(Enchantments.CHANNELING, stack) > 0;
}
- @Nullable
- public static Entry<EquipmentSlot, ItemStack> getRandomItemWith(Enchantment enchantment, LivingEntity entity) {
+ @Deprecated public static @javax.annotation.Nonnull ItemStack getRandomEquippedItemWithEnchant(Enchantment enchantment, LivingEntity entityliving) {
+ Entry<EquipmentSlot, ItemStack> entry = getRandomItemWith(enchantment, entityliving);
+ return entry != null ? entry.getValue() : ItemStack.EMPTY;
+ } // Paper - OBFHELPER
+ @Nullable public static Entry<EquipmentSlot, ItemStack> getRandomItemWith(Enchantment enchantment, LivingEntity entity) {
return getRandomItemWith(enchantment, entity, (stack) -> {
return true;
});
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 6b8ee829306ad22f52844ba29bf2a549558048bd..4c8617fbd2cd8e34c87634fe448d204ee7fb8a0f 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -61,11 +61,14 @@ import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.server.players.UserWhiteListEntry;
import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.ExperienceOrb;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.ai.attributes.AttributeMap;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.inventory.AbstractContainerMenu;
+import net.minecraft.world.item.enchantment.EnchantmentHelper;
+import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.SignBlockEntity;
@@ -1216,8 +1219,37 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
return GameMode.getByValue(this.getHandle().gameMode.getGameModeForPlayer().getId());
}
+ // Paper start
+ @Override
+ public int applyMending(int amount) {
+ ServerPlayer handle = getHandle();
+ // Logic copied from EntityExperienceOrb and remapped to unobfuscated methods/properties
+ net.minecraft.world.item.ItemStack itemstack = EnchantmentHelper.getRandomEquippedItemWithEnchant(Enchantments.MENDING, handle);
+ if (!itemstack.isEmpty() && itemstack.getItem().canBeDepleted()) {
+
+ ExperienceOrb orb = net.minecraft.world.entity.EntityType.EXPERIENCE_ORB.create(handle.level);
+ orb.value = amount;
+ orb.spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.CUSTOM;
+ orb.setPosRaw(handle.getX(), handle.getY(), handle.getZ());
+
+ int i = Math.min(orb.xpToDurability(amount), itemstack.getDamageValue());
+ org.bukkit.event.player.PlayerItemMendEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemMendEvent(handle, orb, itemstack, i);
+ i = event.getRepairAmount();
+ orb.discard();
+ if (!event.isCancelled()) {
+ amount -= orb.durabilityToXp(i);
+ itemstack.setDamageValue(itemstack.getDamageValue() - i);
+ }
+ }
+ return amount;
+ }
+
@Override
- public void giveExp(int exp) {
+ public void giveExp(int exp, boolean applyMending) {
+ if (applyMending) {
+ exp = this.applyMending(exp);
+ }
+ // Paper end
this.getHandle().giveExperiencePoints(exp);
}

View file

@ -1,36 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Thu, 11 Jan 2018 16:47:28 -0600
Subject: [PATCH] Make max squid spawn height configurable
I don't know why upstream made only the minimum height configurable but
whatever
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index e2894138d3efb32161087ad2a1093b8c15c56a65..5892823425055efb92bf635b035d62981942b966 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -383,4 +383,9 @@ public class PaperWorldConfig {
disableCreeperLingeringEffect = getBoolean("disable-creeper-lingering-effect", false);
log("Creeper lingering effect: " + disableCreeperLingeringEffect);
}
+
+ public double squidMaxSpawnHeight;
+ private void squidMaxSpawnHeight() {
+ squidMaxSpawnHeight = getDouble("squid-spawn-height.maximum", 0.0D);
+ }
}
diff --git a/src/main/java/net/minecraft/world/entity/animal/Squid.java b/src/main/java/net/minecraft/world/entity/animal/Squid.java
index 3ffc1ee8a9ae63c8678c12736fab5d6ba0a21a5b..4da560f6e4da0750bda78b900b2d916d58adfccb 100644
--- a/src/main/java/net/minecraft/world/entity/animal/Squid.java
+++ b/src/main/java/net/minecraft/world/entity/animal/Squid.java
@@ -211,7 +211,8 @@ public class Squid extends WaterAnimal {
}
public static boolean checkSquidSpawnRules(EntityType<Squid> type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, Random random) {
- return pos.getY() > world.getMinecraftWorld().spigotConfig.squidSpawnRangeMin && pos.getY() < world.getSeaLevel(); // Spigot
+ final double maxHeight = world.getMinecraftWorld().paperConfig.squidMaxSpawnHeight > 0 ? world.getMinecraftWorld().paperConfig.squidMaxSpawnHeight : world.getSeaLevel(); // Paper
+ return pos.getY() > world.getMinecraftWorld().spigotConfig.squidSpawnRangeMin && pos.getY() < maxHeight; // Spigot // Paper
}
@Override

View file

@ -1,76 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 14 Jan 2018 17:36:02 -0500
Subject: [PATCH] PlayerNaturallySpawnCreaturesEvent
This event can be used for when you want to exclude a certain player
from triggering monster spawns on a server.
Also a highly more effecient way to blanket block spawns in a world
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 4a2739edb01c97c99524dc96decbdcb12e0b7d4f..5e53ef4b71969737f900063ab631f4a1ce74cb90 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1024,11 +1024,21 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
chunkRange = (chunkRange > 8) ? 8 : chunkRange;
- double blockRange = (reducedRange) ? Math.pow(chunkRange << 4, 2) : 16384.0D;
+ final int finalChunkRange = chunkRange; // Paper for lambda below
+ //double blockRange = (reducedRange) ? Math.pow(chunkRange << 4, 2) : 16384.0D; // Paper - use from event
// Spigot end
long i = chunkcoordintpair.toLong();
return !this.distanceManager.hasPlayersNearby(i) ? true : this.playerMap.getPlayers(i).noneMatch((entityplayer) -> {
+ // Paper start - add PlayerNaturallySpawnCreaturesEvent
+ com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent event;
+ double blockRange = 16384.0D;
+ if (reducedRange) {
+ event = entityplayer.playerNaturallySpawnedEvent;
+ if (event == null || event.isCancelled()) return false;
+ blockRange = (double) ((event.getSpawnRadius() << 4) * (event.getSpawnRadius() << 4));
+ }
+ // Paper end
return !entityplayer.isSpectator() && ChunkMap.euclideanDistanceSquared(chunkcoordintpair, (Entity) entityplayer) < blockRange; // Spigot
});
}
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 3e2a5f83afcc3b9c9fe62748895d489135af03bf..1f3fe980e71c13b5e7852349cba1cb0e4aa42dcd 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -791,6 +791,15 @@ public class ServerChunkCache extends ChunkSource {
List<ChunkHolder> list = Lists.newArrayList(this.chunkMap.getChunks());
Collections.shuffle(list);
+ // Paper start - call player naturally spawn event
+ int chunkRange = level.spigotConfig.mobSpawnRange;
+ chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;
+ chunkRange = Math.min(chunkRange, 8);
+ for (ServerPlayer entityPlayer : this.level.players()) {
+ entityPlayer.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(entityPlayer.getBukkitEntity(), (byte) chunkRange);
+ entityPlayer.playerNaturallySpawnedEvent.callEvent();
+ };
+ // Paper end
this.level.timings.chunkTicks.startTiming(); // Paper
list.forEach((playerchunk) -> {
Optional<LevelChunk> optional = ((Either) playerchunk.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK)).left();
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index d4614faa22485dce226f3dc17ef984212ac8fcb9..66434418fae67ff63450bc246796c7f3d4d09ae6 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -1,5 +1,6 @@
package net.minecraft.server.level;
+import com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent;
import com.google.common.collect.Lists;
import com.mojang.authlib.GameProfile;
import com.mojang.datafixers.util.Either;
@@ -233,6 +234,7 @@ public class ServerPlayer extends Player {
public boolean sentListPacket = false;
public Integer clientViewDistance;
// CraftBukkit end
+ public PlayerNaturallySpawnCreaturesEvent playerNaturallySpawnedEvent; // Paper
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper

View file

@ -1,145 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 14 Jan 2018 17:01:31 -0500
Subject: [PATCH] PreCreatureSpawnEvent
Adds an event to fire before an Entity is created, so that plugins that need to cancel
CreatureSpawnEvent can do so from this event instead.
Cancelling CreatureSpawnEvent rapidly causes a lot of garbage collection and CPU waste
as it's done after the Entity object has been fully created.
Mob Limiting plugins and blanket "ban this type of monster" plugins should use this event
instead and save a lot of server resources.
See: https://github.com/PaperMC/Paper/issues/917
diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
index 28f1a53a2b9ebe9948509dabbf1a4ae84d8e147c..345ecbc7fc080e8581d285b638db1ee6e684010a 100644
--- a/src/main/java/net/minecraft/world/entity/EntityType.java
+++ b/src/main/java/net/minecraft/world/entity/EntityType.java
@@ -335,6 +335,20 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T> {
@Nullable
public T spawnCreature(ServerLevel worldserver, @Nullable CompoundTag nbttagcompound, @Nullable Component ichatbasecomponent, @Nullable Player entityhuman, BlockPos blockposition, MobSpawnType enummobspawn, boolean flag, boolean flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
+ // Paper start - Call PreCreatureSpawnEvent
+ org.bukkit.entity.EntityType type = org.bukkit.entity.EntityType.fromName(EntityType.getKey(this).getPath());
+ if (type != null) {
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
+ event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
+ net.minecraft.server.MCUtil.toLocation(worldserver, blockposition),
+ type,
+ spawnReason
+ );
+ if (!event.callEvent()) {
+ return null;
+ }
+ }
+ // Paper end
T t0 = this.create(worldserver, nbttagcompound, ichatbasecomponent, entityhuman, blockposition, enummobspawn, flag, flag1);
if (t0 != 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 3839bacbd5f4d06eb13d0e604651232d9fbd7b6a..206aee8bf14ffc4ddbb8a7001bc3baae6a2ea849 100644
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
@@ -987,6 +987,21 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
BlockPos blockposition1 = this.findSpawnPositionForGolemInColumn(blockposition, d0, d1);
if (blockposition1 != null) {
+ // Paper start - Call PreCreatureSpawnEvent
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
+ event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
+ net.minecraft.server.MCUtil.toLocation(level, blockposition1),
+ org.bukkit.entity.EntityType.IRON_GOLEM,
+ org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_DEFENSE
+ );
+ if (!event.callEvent()) {
+ if (event.shouldAbortSpawn()) {
+ GolemSensor.golemDetected(this); // Set Golem Last Seen to stop it from spawning another one
+ return null;
+ }
+ break;
+ }
+ // Paper end
IronGolem entityirongolem = (IronGolem) EntityType.IRON_GOLEM.create(world, (CompoundTag) null, (Component) null, (Player) null, blockposition1, MobSpawnType.MOB_SUMMONED, false, false);
if (entityirongolem != null) {
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
index 14188ac6f158b36755abe23c0a967763cf7367d8..572328fafb2347886900352983fd5b6490b0dd68 100644
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
@@ -133,6 +133,27 @@ public abstract class BaseSpawner {
double d2 = j >= 3 ? nbttaglist.getDouble(2) : (double) pos.getZ() + (world.random.nextDouble() - world.random.nextDouble()) * (double) this.spawnRange + 0.5D;
if (world.noCollision(((EntityType) optional.get()).getAABB(d0, d1, d2)) && SpawnPlacements.checkSpawnRules((EntityType) optional.get(), world, MobSpawnType.SPAWNER, new BlockPos(d0, d1, d2), world.getRandom())) {
+ // Paper start
+ EntityType<?> entityType = optional.get();
+ String key = EntityType.getKey(entityType).getPath();
+
+ org.bukkit.entity.EntityType type = org.bukkit.entity.EntityType.fromName(key);
+ if (type != null) {
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
+ event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
+ net.minecraft.server.MCUtil.toLocation(world, d0, d1, d2),
+ type,
+ org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER
+ );
+ if (!event.callEvent()) {
+ flag = true;
+ if (event.shouldAbortSpawn()) {
+ break;
+ }
+ continue;
+ }
+ }
+ // Paper end
Entity entity = EntityType.loadEntityRecursive(nbttagcompound, world, (entity1) -> {
entity1.moveTo(d0, d1, d2, entity1.getYRot(), entity1.getXRot());
return entity1;
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
index 0432ad7ab00c336e7c566f24c3ec92b399cb6e9d..ca0fcf46e67deb07a3fdb071b771a7603e0fc3d0 100644
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
@@ -236,7 +236,13 @@ public final class NaturalSpawner {
j1 = biomesettingsmobs_c.minCount + world.random.nextInt(1 + biomesettingsmobs_c.maxCount - biomesettingsmobs_c.minCount);
}
- if (NaturalSpawner.isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2) && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) {
+ // Paper start
+ Boolean doSpawning = isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2);
+ if (doSpawning == null) {
+ return;
+ }
+ if (doSpawning && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) {
+ // Paper end
Mob entityinsentient = NaturalSpawner.getMobForSpawn(world, biomesettingsmobs_c.type);
if (entityinsentient == null) {
@@ -283,9 +289,25 @@ public final class NaturalSpawner {
return squaredDistance <= 576.0D ? false : (world.getSharedSpawnPos().closerThan((Position) (new Vec3((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D)), 24.0D) ? false : Objects.equals(new ChunkPos(pos), chunk.getPos()) || world.isPositionEntityTicking((BlockPos) pos));
}
- private static boolean isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureFeatureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) {
+ private static Boolean isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureFeatureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) { // Paper
EntityType<?> entitytypes = spawnEntry.type;
+ // Paper start
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
+ org.bukkit.entity.EntityType type = org.bukkit.entity.EntityType.fromName(EntityType.getKey(entitytypes).getPath());
+ if (type != null) {
+ event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
+ net.minecraft.server.MCUtil.toLocation(world, pos),
+ type, SpawnReason.NATURAL
+ );
+ if (!event.callEvent()) {
+ if (event.shouldAbortSpawn()) {
+ return null;
+ }
+ return false;
+ }
+ }
+ // Paper end
if (entitytypes.getCategory() == MobCategory.MISC) {
return false;
} else if (!entitytypes.canSpawnFarFromPlayer() && squaredDistance > (double) (entitytypes.getCategory().getDespawnDistance() * entitytypes.getCategory().getDespawnDistance())) {

View file

@ -1,90 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Fri, 19 Jan 2018 00:36:25 -0500
Subject: [PATCH] Add setPlayerProfile API for Skulls
This allows you to create already filled textures on Skulls to avoid texture lookups
which commonly cause rate limit issues with Mojang API
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java b/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java
index d6a4638271644e31fbc38f5ae9150ded63a6d62f..e89eb5d631b4226d79caf49c89ebb44155e72a0f 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftSkull.java
@@ -1,5 +1,7 @@
package org.bukkit.craftbukkit.block;
+import com.destroystokyo.paper.profile.CraftPlayerProfile;
+import com.destroystokyo.paper.profile.PlayerProfile;
import com.google.common.base.Preconditions;
import com.mojang.authlib.GameProfile;
import net.minecraft.server.MinecraftServer;
@@ -100,6 +102,20 @@ public class CraftSkull extends CraftBlockEntityState<SkullBlockEntity> implemen
}
}
+ // Paper start
+ @Override
+ public void setPlayerProfile(PlayerProfile profile) {
+ Preconditions.checkNotNull(profile, "profile");
+ this.profile = CraftPlayerProfile.asAuthlibCopy(profile);
+ }
+
+ @javax.annotation.Nullable
+ @Override
+ public PlayerProfile getPlayerProfile() {
+ return profile != null ? CraftPlayerProfile.asBukkitCopy(profile) : null;
+ }
+ // Paper end
+
@Override
public BlockFace getRotation() {
BlockData blockData = getBlockData();
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
index 490df0dcfd0e1e0ab05943410493522f86444ef8..7cacc61fed0c610845c67894d1cc68e44f5e46fe 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
@@ -4,10 +4,8 @@ import com.google.common.collect.ImmutableMap.Builder;
import com.mojang.authlib.GameProfile;
import java.util.Map;
import java.util.UUID;
-import net.minecraft.nbt.CompoundTag;
-import net.minecraft.nbt.NbtUtils;
-import net.minecraft.nbt.Tag;
-import net.minecraft.world.level.block.entity.SkullBlockEntity;
+import com.destroystokyo.paper.profile.CraftPlayerProfile;
+import com.destroystokyo.paper.profile.PlayerProfile;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
@@ -18,6 +16,11 @@ import org.bukkit.craftbukkit.inventory.CraftMetaItem.SerializableMeta;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.inventory.meta.SkullMeta;
+import javax.annotation.Nullable;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.NbtUtils;
+import net.minecraft.nbt.Tag;
+import net.minecraft.world.level.block.entity.SkullBlockEntity;
@DelegateDeserialization(SerializableMeta.class)
class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
@@ -151,6 +154,19 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
return this.hasOwner() ? this.profile.getName() : null;
}
+ // Paper start
+ @Override
+ public void setPlayerProfile(@Nullable PlayerProfile profile) {
+ setProfile((profile == null) ? null : CraftPlayerProfile.asAuthlibCopy(profile));
+ }
+
+ @Nullable
+ @Override
+ public PlayerProfile getPlayerProfile() {
+ return profile != null ? CraftPlayerProfile.asBukkitCopy(profile) : null;
+ }
+ // Paper end
+
@Override
public OfflinePlayer getOwningPlayer() {
if (this.hasOwner()) {

View file

@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Tue, 2 Jan 2018 00:31:26 -0500
Subject: [PATCH] Fill Profile Property Events
Allows plugins to populate profile properties from local sources to avoid calls out to Mojang API
to fill in textures for example.
If Mojang API does need to be hit, event fire so you can get the results.
This is useful for implementing a ProfileCache for Player Skulls
diff --git a/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java b/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java
index 93d73c27340645c7502acafdc0b2cfbc1a759dd8..5c7d2ee19243d0911a3a00af3ae42078a2ccba94 100644
--- a/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java
+++ b/src/main/java/com/destroystokyo/paper/profile/PaperMinecraftSessionService.java
@@ -1,6 +1,8 @@
package com.destroystokyo.paper.profile;
import com.mojang.authlib.Environment;
+import com.destroystokyo.paper.event.profile.FillProfileEvent;
+import com.destroystokyo.paper.event.profile.PreFillProfileEvent;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.minecraft.MinecraftProfileTexture;
import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
@@ -20,7 +22,15 @@ public class PaperMinecraftSessionService extends YggdrasilMinecraftSessionServi
@Override
public GameProfile fillProfileProperties(GameProfile profile, boolean requireSecure) {
- return super.fillProfileProperties(profile, requireSecure);
+ CraftPlayerProfile playerProfile = (CraftPlayerProfile) CraftPlayerProfile.asBukkitMirror(profile);
+ new PreFillProfileEvent(playerProfile).callEvent();
+ profile = playerProfile.getGameProfile();
+ if (profile.isComplete() && profile.getProperties().containsKey("textures")) {
+ return profile;
+ }
+ GameProfile gameProfile = super.fillProfileProperties(profile, requireSecure);
+ new FillProfileEvent(CraftPlayerProfile.asBukkitMirror(gameProfile)).callEvent();
+ return gameProfile;
}
@Override

View file

@ -1,23 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: BillyGalbreath <Blake.Galbreath@GMail.com>
Date: Fri, 19 Jan 2018 08:15:29 -0600
Subject: [PATCH] PlayerAdvancementCriterionGrantEvent
diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java
index f26bdd3d6eb0ae38c1d7b50f29942fcf2207e3a1..3d82f984648605d58fae3c57f145d0da8a2ae225 100644
--- a/src/main/java/net/minecraft/server/PlayerAdvancements.java
+++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java
@@ -277,6 +277,12 @@ public class PlayerAdvancements {
boolean flag1 = advancementprogress.isDone();
if (advancementprogress.grantProgress(criterionName)) {
+ // Paper start
+ if (!new com.destroystokyo.paper.event.player.PlayerAdvancementCriterionGrantEvent(this.player.getBukkitEntity(), advancement.bukkit, criterionName).callEvent()) {
+ advancementprogress.revokeProgress(criterionName);
+ return false;
+ }
+ // Paper end
this.unregisterListeners(advancement);
this.progressChanged.add(advancement);
flag = true;

View file

@ -1,288 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Zach Brown <zach.brown@destroystokyo.com>
Date: Sat, 27 Jan 2018 17:04:14 -0500
Subject: [PATCH] Add ArmorStand Item Meta
This is adds basic item meta for armor stands. It does not add all
possible metadata however.
There are armor, hand, and equipment types, as well as position data
that can also be added here. This initial addition should serve a
starting point for future additions in this area.
Fixes GH-559
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java
index aee796567f11c8b93ac9ec0b8cb8f3a8412b23ce..39b98305632271e7375afe6c7001f241c17e103d 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaArmorStand.java
@@ -9,9 +9,22 @@ import org.bukkit.configuration.serialization.DelegateDeserialization;
import org.bukkit.craftbukkit.inventory.CraftMetaItem.ItemMetaKey;
@DelegateDeserialization(CraftMetaItem.SerializableMeta.class)
-public class CraftMetaArmorStand extends CraftMetaItem {
+public class CraftMetaArmorStand extends CraftMetaItem implements com.destroystokyo.paper.inventory.meta.ArmorStandMeta { // Paper
static final ItemMetaKey ENTITY_TAG = new ItemMetaKey("EntityTag", "entity-tag");
+ // Paper start
+ static final ItemMetaKey INVISIBLE = new ItemMetaKey("Invisible", "invisible");
+ static final ItemMetaKey NO_BASE_PLATE = new ItemMetaKey("NoBasePlate", "no-base-plate");
+ static final ItemMetaKey SHOW_ARMS = new ItemMetaKey("ShowArms", "show-arms");
+ static final ItemMetaKey SMALL = new ItemMetaKey("Small", "small");
+ static final ItemMetaKey MARKER = new ItemMetaKey("Marker", "marker");
+
+ private boolean invisible;
+ private boolean noBasePlate;
+ private boolean showArms;
+ private boolean small;
+ private boolean marker;
+ // Paper end
CompoundTag entityTag;
CraftMetaArmorStand(CraftMetaItem meta) {
@@ -22,6 +35,13 @@ public class CraftMetaArmorStand extends CraftMetaItem {
}
CraftMetaArmorStand armorStand = (CraftMetaArmorStand) meta;
+ // Paper start
+ this.invisible = armorStand.invisible;
+ this.noBasePlate = armorStand.noBasePlate;
+ this.showArms = armorStand.showArms;
+ this.small = armorStand.small;
+ this.marker = armorStand.marker;
+ // Paper end
this.entityTag = armorStand.entityTag;
}
@@ -30,11 +50,40 @@ public class CraftMetaArmorStand extends CraftMetaItem {
if (tag.contains(ENTITY_TAG.NBT)) {
this.entityTag = tag.getCompound(ENTITY_TAG.NBT);
+
+ // Paper start
+ if (entityTag.contains(INVISIBLE.NBT)) {
+ invisible = entityTag.getBoolean(INVISIBLE.NBT);
+ }
+
+ if (entityTag.contains(NO_BASE_PLATE.NBT)) {
+ noBasePlate = entityTag.getBoolean(NO_BASE_PLATE.NBT);
+ }
+
+ if (entityTag.contains(SHOW_ARMS.NBT)) {
+ showArms = entityTag.getBoolean(SHOW_ARMS.NBT);
+ }
+
+ if (entityTag.contains(SMALL.NBT)) {
+ small = entityTag.getBoolean(SMALL.NBT);
+ }
+
+ if (entityTag.contains(MARKER.NBT)) {
+ marker = entityTag.getBoolean(MARKER.NBT);
+ }
+ // Paper end
}
}
CraftMetaArmorStand(Map<String, Object> map) {
super(map);
+ // Paper start
+ this.invisible = SerializableMeta.getBoolean(map, INVISIBLE.BUKKIT);
+ this.noBasePlate = SerializableMeta.getBoolean(map, NO_BASE_PLATE.BUKKIT);
+ this.showArms = SerializableMeta.getBoolean(map, SHOW_ARMS.BUKKIT);
+ this.small = SerializableMeta.getBoolean(map, SMALL.BUKKIT);
+ this.marker = SerializableMeta.getBoolean(map, MARKER.BUKKIT);
+ // Paper end
}
@Override
@@ -57,6 +106,31 @@ public class CraftMetaArmorStand extends CraftMetaItem {
void applyToItem(CompoundTag tag) {
super.applyToItem(tag);
+ // Paper start
+ if (!isArmorStandEmpty() && this.entityTag == null) {
+ this.entityTag = new CompoundTag();
+ }
+
+ if (isInvisible()) {
+ this.entityTag.putBoolean(INVISIBLE.NBT, this.invisible);
+ }
+
+ if (hasNoBasePlate()) {
+ this.entityTag.putBoolean(NO_BASE_PLATE.NBT, this.noBasePlate);
+ }
+
+ if (shouldShowArms()) {
+ this.entityTag.putBoolean(SHOW_ARMS.NBT, this.showArms);
+ }
+
+ if (isSmall()) {
+ this.entityTag.putBoolean(SMALL.NBT, this.small);
+ }
+
+ if (isMarker()) {
+ this.entityTag.putBoolean(MARKER.NBT, this.marker);
+ }
+ // Paper end
if (this.entityTag != null) {
tag.put(ENTITY_TAG.NBT, entityTag);
}
@@ -78,7 +152,7 @@ public class CraftMetaArmorStand extends CraftMetaItem {
}
boolean isArmorStandEmpty() {
- return !(this.entityTag != null);
+ return !(this.isInvisible() || this.hasNoBasePlate() || this.shouldShowArms() || this.isSmall() || this.isMarker() || this.entityTag != null);
}
@Override
@@ -89,7 +163,13 @@ public class CraftMetaArmorStand extends CraftMetaItem {
if (meta instanceof CraftMetaArmorStand) {
CraftMetaArmorStand that = (CraftMetaArmorStand) meta;
- return this.entityTag != null ? that.entityTag != null && this.entityTag.equals(that.entityTag) : this.entityTag == null;
+ // Paper start
+ return this.invisible == that.invisible &&
+ this.noBasePlate == that.noBasePlate &&
+ this.showArms == that.showArms &&
+ this.small == that.small &&
+ this.marker == that.marker;
+ // Paper end
}
return true;
}
@@ -104,9 +184,14 @@ public class CraftMetaArmorStand extends CraftMetaItem {
final int original;
int hash = original = super.applyHash();
- if (this.entityTag != null) {
- hash = 73 * hash + this.entityTag.hashCode();
- }
+ // Paper start
+ hash += this.entityTag != null ? 73 * hash + this.entityTag.hashCode() : 0;
+ hash += this.isInvisible() ? 61 * hash + 1231 : 0;
+ hash += this.hasNoBasePlate() ? 61 * hash + 1231 : 0;
+ hash += this.shouldShowArms() ? 61 * hash + 1231 : 0;
+ hash += this.isSmall() ? 61 * hash + 1231 : 0;
+ hash += this.isMarker() ? 61 * hash + 1231 : 0;
+ // Paper end
return original != hash ? CraftMetaArmorStand.class.hashCode() ^ hash : hash;
}
@@ -115,6 +200,28 @@ public class CraftMetaArmorStand extends CraftMetaItem {
Builder<String, Object> serialize(Builder<String, Object> builder) {
super.serialize(builder);
+ // Paper start
+ if (this.isInvisible()) {
+ builder.put(INVISIBLE.BUKKIT, invisible);
+ }
+
+ if (this.hasNoBasePlate()) {
+ builder.put(NO_BASE_PLATE.BUKKIT, noBasePlate);
+ }
+
+ if (this.shouldShowArms()) {
+ builder.put(SHOW_ARMS.BUKKIT, showArms);
+ }
+
+ if (this.isSmall()) {
+ builder.put(SMALL.BUKKIT, small);
+ }
+
+ if (this.isMarker()) {
+ builder.put(MARKER.BUKKIT, marker);
+ }
+ // Paper end
+
return builder;
}
@@ -128,4 +235,56 @@ public class CraftMetaArmorStand extends CraftMetaItem {
return clone;
}
+
+ // Paper start
+ @Override
+ public boolean isInvisible() {
+ return invisible;
+ }
+
+ @Override
+ public boolean hasNoBasePlate() {
+ return noBasePlate;
+ }
+
+ @Override
+ public boolean shouldShowArms() {
+ return showArms;
+ }
+
+ @Override
+ public boolean isSmall() {
+ return small;
+ }
+
+ @Override
+ public boolean isMarker() {
+ return marker;
+ }
+
+ @Override
+ public void setInvisible(boolean invisible) {
+ this.invisible = invisible;
+ }
+
+ @Override
+ public void setNoBasePlate(boolean noBasePlate) {
+ this.noBasePlate = noBasePlate;
+ }
+
+ @Override
+ public void setShowArms(boolean showArms) {
+ this.showArms = showArms;
+ }
+
+ @Override
+ public void setSmall(boolean small) {
+ this.small = small;
+ }
+
+ @Override
+ public void setMarker(boolean marker) {
+ this.marker = marker;
+ }
+ // Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
index 05d54f0eff89b721f01e90e79d2571baab297799..71320d9484842be3a694117de25159f3581bd2a3 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
@@ -1444,6 +1444,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
CraftMetaCrossbow.CHARGED.NBT,
CraftMetaCrossbow.CHARGED_PROJECTILES.NBT,
CraftMetaSuspiciousStew.EFFECTS.NBT,
+ // Paper start
+ CraftMetaArmorStand.ENTITY_TAG.NBT,
+ CraftMetaArmorStand.INVISIBLE.NBT,
+ CraftMetaArmorStand.NO_BASE_PLATE.NBT,
+ CraftMetaArmorStand.SHOW_ARMS.NBT,
+ CraftMetaArmorStand.SMALL.NBT,
+ CraftMetaArmorStand.MARKER.NBT,
+ // Paper end
CraftMetaCompass.LODESTONE_DIMENSION.NBT,
CraftMetaCompass.LODESTONE_POS.NBT,
CraftMetaCompass.LODESTONE_TRACKED.NBT,
diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java
index a7505a08b952431d1dd7e4b332ede0c0d15eea64..f3a0578f53863dd0866b4c2cb957a30fa3bc6cc5 100644
--- a/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java
+++ b/src/test/java/org/bukkit/craftbukkit/inventory/ItemMetaTest.java
@@ -324,6 +324,7 @@ public class ItemMetaTest extends AbstractTestingBase {
final CraftMetaArmorStand meta = (CraftMetaArmorStand) cleanStack.getItemMeta();
meta.entityTag = new CompoundTag();
meta.entityTag.putBoolean("Small", true);
+ meta.setInvisible(true); // Paper
cleanStack.setItemMeta(meta);
return cleanStack;
}

View file

@ -1,44 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shane Freeder <theboyetronic@gmail.com>
Date: Sun, 11 Feb 2018 10:43:46 +0000
Subject: [PATCH] Extend Player Interact cancellation
GUIs are opened on the client, meaning that the server cannot block them from opening,
However, it is possible to close these GUIs from the server.
Flower pots are also not updated on the client when interaction is cancelled, this patch
also resolves this.
Update adjacent blocks of doors, double plants, pistons and beds
when cancelling interaction.
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
index ecfb88b4d9727ad20a2c33475cc6b1ec88821a19..315dad4789f5f2582ee9b4fc176affd1f57537ef 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -187,6 +187,11 @@ public class ServerPlayerGameMode {
PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, pos, direction, this.player.getInventory().getSelected(), InteractionHand.MAIN_HAND);
if (event.isCancelled()) {
// Let the client know the block still exists
+ // Paper start - brute force neighbor blocks for any attached blocks
+ for (Direction dir : Direction.values()) {
+ this.player.connection.send(new ClientboundBlockUpdatePacket(level, pos.relative(dir)));
+ }
+ // Paper end
this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos));
// Update any tile entity data for this block
BlockEntity tileentity = this.level.getBlockEntity(pos);
@@ -502,7 +507,13 @@ public class ServerPlayerGameMode {
// send a correcting update to the client for the block above as well, this because of replaceable blocks (such as grass, sea grass etc)
player.connection.send(new ClientboundBlockUpdatePacket(world, blockposition.above()));
+ // Paper start - extend Player Interact cancellation // TODO: consider merging this into the extracted method
+ } else if (iblockdata.getBlock() instanceof net.minecraft.world.level.block.StructureBlock) {
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerClosePacket(this.player.containerMenu.containerId));
+ } else if (iblockdata.getBlock() instanceof net.minecraft.world.level.block.CommandBlock) {
+ player.connection.send(new net.minecraft.network.protocol.game.ClientboundContainerClosePacket(this.player.containerMenu.containerId));
}
+ // Paper end - extend Player Interact cancellation
player.getBukkitEntity().updateInventory(); // SPIGOT-2867
enuminteractionresult = (event.useItemInHand() != Event.Result.ALLOW) ? InteractionResult.SUCCESS : InteractionResult.PASS;
} else if (this.gameModeForPlayer == GameType.SPECTATOR) {

View file

@ -1,38 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sat, 24 Feb 2018 01:14:55 -0500
Subject: [PATCH] Tameable#getOwnerUniqueId API
This is faster if all you need is the UUID, as .getOwner() will cause
an OfflinePlayer to be loaded from disk.
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java
index 27a1ca43792644fc239af81dea5510f25d3328e9..69c95644b2531c1fe1c4a6cf7fee12e997dd67f4 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractHorse.java
@@ -89,6 +89,10 @@ public abstract class CraftAbstractHorse extends CraftAnimals implements Abstrac
}
}
+ @Override
+ public UUID getOwnerUniqueId() {
+ return getOwnerUUID();
+ }
public UUID getOwnerUUID() {
return this.getHandle().getOwnerUUID();
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTameableAnimal.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTameableAnimal.java
index cc90c09c26b04689e4fffa890baf0e89c38665a3..0b152d8d20924fc1ce7f5bafb050216d250f6536 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftTameableAnimal.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTameableAnimal.java
@@ -17,6 +17,10 @@ public class CraftTameableAnimal extends CraftAnimals implements Tameable, Creat
return (TamableAnimal) super.getHandle();
}
+ @Override
+ public UUID getOwnerUniqueId() {
+ return getOwnerUUID();
+ }
public UUID getOwnerUUID() {
try {
return this.getHandle().getOwnerUUID();

View file

@ -1,34 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MiniDigger <admin@minidigger.me>
Date: Sat, 10 Mar 2018 00:50:24 +0100
Subject: [PATCH] Toggleable player crits, helps mitigate hacked clients.
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
index 5892823425055efb92bf635b035d62981942b966..0e08f6e566d1c93cc89a179583d0b0939127de8b 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -233,6 +233,11 @@ public class PaperWorldConfig {
disableChestCatDetection = getBoolean("game-mechanics.disable-chest-cat-detection", false);
}
+ public boolean disablePlayerCrits;
+ private void disablePlayerCrits() {
+ disablePlayerCrits = getBoolean("game-mechanics.disable-player-crits", false);
+ }
+
public boolean allChunksAreSlimeChunks;
private void allChunksAreSlimeChunks() {
allChunksAreSlimeChunks = getBoolean("all-chunks-are-slime-chunks", 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 8c20af91c9298cb36fdb2700d042b1e2fccf5f54..dbab4d28c49d22807dfc582fb83353232396555b 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -1189,6 +1189,7 @@ public abstract class Player extends LivingEntity {
boolean flag2 = flag && this.fallDistance > 0.0F && !this.onGround && !this.onClimbable() && !this.isInWater() && !this.hasEffect(MobEffects.BLINDNESS) && !this.isPassenger() && target instanceof LivingEntity;
+ flag2 = flag2 && !level.paperConfig.disablePlayerCrits; // Paper
flag2 = flag2 && !this.isSprinting();
if (flag2) {
f *= 1.5F;

View file

@ -1,34 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 11 Mar 2018 14:13:33 -0400
Subject: [PATCH] Disable Explicit Network Manager Flushing
This seems completely pointless, as packet dispatch uses .writeAndFlush.
Things seem to work fine without explicit flushing, but incase issues arise,
provide a System property to re-enable it using improved logic of doing the
flushing on the netty event loop, so it won't do the flush on the main thread.
Renable flushing by passing -Dpaper.explicit-flush=true
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
index 06e965996a5c50bce617847e594ae0dd83403484..636ac646bec67dbd933f00614693af03481b6173 100644
--- a/src/main/java/net/minecraft/network/Connection.java
+++ b/src/main/java/net/minecraft/network/Connection.java
@@ -86,6 +86,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
// Paper start - NetworkClient implementation
public int protocolVersion;
public java.net.InetSocketAddress virtualHost;
+ private static boolean enableExplicitFlush = Boolean.getBoolean("paper.explicit-flush");
// Paper end
public Connection(PacketFlow side) {
@@ -259,7 +260,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
}
if (this.channel != null) {
- this.channel.flush();
+ if (enableExplicitFlush) this.channel.eventLoop().execute(() -> this.channel.flush()); // Paper - we don't need to explicit flush here, but allow opt in incase issues are found to a better version
}
if (this.tickCount++ % 20 == 0) {

View file

@ -1,250 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Minecrell <minecrell@minecrell.net>
Date: Wed, 11 Oct 2017 15:56:26 +0200
Subject: [PATCH] Implement extended PaperServerListPingEvent
diff --git a/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java b/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..4ecd0c5bbea55f68549c85aa27e80e2c7e6265d4
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java
@@ -0,0 +1,31 @@
+package com.destroystokyo.paper.network;
+
+import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerPlayer;
+import org.bukkit.entity.Player;
+import org.bukkit.util.CachedServerIcon;
+
+import javax.annotation.Nullable;
+
+class PaperServerListPingEventImpl extends PaperServerListPingEvent {
+
+ private final MinecraftServer server;
+
+ PaperServerListPingEventImpl(MinecraftServer server, StatusClient client, int protocolVersion, @Nullable CachedServerIcon icon) {
+ super(client, server.getMotd(), server.getPlayerCount(), server.getMaxPlayers(),
+ server.getServerModName() + ' ' + server.getServerVersion(), protocolVersion, icon);
+ this.server = server;
+ }
+
+ @Override
+ protected final Object[] getOnlinePlayers() {
+ return this.server.getPlayerList().players.toArray();
+ }
+
+ @Override
+ protected final Player getBukkitPlayer(Object player) {
+ return ((ServerPlayer) player).getBukkitEntity();
+ }
+
+}
diff --git a/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java b/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..d926ad804355ee2fdc5910b2505e8671602acdab
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/network/PaperStatusClient.java
@@ -0,0 +1,11 @@
+package com.destroystokyo.paper.network;
+
+import net.minecraft.network.Connection;
+
+class PaperStatusClient extends PaperNetworkClient implements StatusClient {
+
+ PaperStatusClient(Connection networkManager) {
+ super(networkManager);
+ }
+
+}
diff --git a/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java b/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c2351b03b58511b80017b58ee9b20ab5193adc9
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/network/StandardPaperServerListPingEventImpl.java
@@ -0,0 +1,110 @@
+package com.destroystokyo.paper.network;
+
+import com.destroystokyo.paper.profile.CraftPlayerProfile;
+import com.destroystokyo.paper.profile.PlayerProfile;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Strings;
+import com.mojang.authlib.GameProfile;
+import io.papermc.paper.adventure.AdventureComponent;
+import java.util.List;
+import java.util.UUID;
+import javax.annotation.Nonnull;
+import net.minecraft.network.Connection;
+import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket;
+import net.minecraft.network.protocol.status.ServerStatus;
+import net.minecraft.server.MinecraftServer;
+
+public final class StandardPaperServerListPingEventImpl extends PaperServerListPingEventImpl {
+
+ private static final GameProfile[] EMPTY_PROFILES = new GameProfile[0];
+ private static final UUID FAKE_UUID = new UUID(0, 0);
+
+ private GameProfile[] originalSample;
+
+ private StandardPaperServerListPingEventImpl(MinecraftServer server, Connection networkManager, ServerStatus ping) {
+ super(server, new PaperStatusClient(networkManager), ping.getVersion() != null ? ping.getVersion().getProtocol() : -1, server.server.getServerIcon());
+ this.originalSample = ping.getPlayers() == null ? null : ping.getPlayers().getSample(); // GH-1473 - pre-tick race condition NPE
+ }
+
+ @Nonnull
+ @Override
+ public List<PlayerProfile> getPlayerSample() {
+ List<PlayerProfile> sample = super.getPlayerSample();
+
+ if (this.originalSample != null) {
+ for (GameProfile profile : this.originalSample) {
+ sample.add(CraftPlayerProfile.asBukkitCopy(profile));
+ }
+ this.originalSample = null;
+ }
+
+ return sample;
+ }
+
+ private GameProfile[] getPlayerSampleHandle() {
+ if (this.originalSample != null) {
+ return this.originalSample;
+ }
+
+ List<PlayerProfile> entries = super.getPlayerSample();
+ if (entries.isEmpty()) {
+ return EMPTY_PROFILES;
+ }
+
+ GameProfile[] profiles = new GameProfile[entries.size()];
+ for (int i = 0; i < profiles.length; i++) {
+ /*
+ * Avoid null UUIDs/names since that will make the response invalid
+ * on the client.
+ * Instead, fall back to a fake/empty UUID and an empty string as name.
+ * This can be used to create custom lines in the player list that do not
+ * refer to a specific player.
+ */
+
+ PlayerProfile profile = entries.get(i);
+ if (profile.getId() != null && profile.getName() != null) {
+ profiles[i] = CraftPlayerProfile.asAuthlib(profile);
+ } else {
+ profiles[i] = new GameProfile(MoreObjects.firstNonNull(profile.getId(), FAKE_UUID), Strings.nullToEmpty(profile.getName()));
+ }
+ }
+
+ return profiles;
+ }
+
+ @SuppressWarnings("deprecation")
+ public static void processRequest(MinecraftServer server, Connection networkManager) {
+ StandardPaperServerListPingEventImpl event = new StandardPaperServerListPingEventImpl(server, networkManager, server.getStatus());
+ server.server.getPluginManager().callEvent(event);
+
+ // Close connection immediately if event is cancelled
+ if (event.isCancelled()) {
+ networkManager.disconnect(null);
+ return;
+ }
+
+ // Setup response
+ ServerStatus ping = new ServerStatus();
+
+ // Description
+ ping.setDescription(new AdventureComponent(event.motd()));
+
+ // Players
+ if (!event.shouldHidePlayers()) {
+ ping.setPlayers(new ServerStatus.Players(event.getMaxPlayers(), event.getNumPlayers()));
+ ping.getPlayers().setSample(event.getPlayerSampleHandle());
+ }
+
+ // Version
+ ping.setVersion(new ServerStatus.Version(event.getVersion(), event.getProtocolVersion()));
+
+ // Favicon
+ if (event.getServerIcon() != null) {
+ ping.setFavicon(event.getServerIcon().getData());
+ }
+
+ // Send response
+ networkManager.send(new ClientboundStatusResponsePacket(ping));
+ }
+
+}
diff --git a/src/main/java/net/minecraft/network/protocol/status/ClientboundStatusResponsePacket.java b/src/main/java/net/minecraft/network/protocol/status/ClientboundStatusResponsePacket.java
index 67455a5ba75c9b816213e44d6872c5ddf8e27e98..23efad80934930beadf15e65781551d4ba7ff81b 100644
--- a/src/main/java/net/minecraft/network/protocol/status/ClientboundStatusResponsePacket.java
+++ b/src/main/java/net/minecraft/network/protocol/status/ClientboundStatusResponsePacket.java
@@ -10,7 +10,9 @@ import net.minecraft.util.GsonHelper;
import net.minecraft.util.LowerCaseEnumTypeAdapterFactory;
public class ClientboundStatusResponsePacket implements Packet<ClientStatusPacketListener> {
- private static final Gson GSON = (new GsonBuilder()).registerTypeAdapter(ServerStatus.Version.class, new ServerStatus.Version.Serializer()).registerTypeAdapter(ServerStatus.Players.class, new ServerStatus.Players.Serializer()).registerTypeAdapter(ServerStatus.class, new ServerStatus.Serializer()).registerTypeHierarchyAdapter(Component.class, new Component.Serializer()).registerTypeHierarchyAdapter(Style.class, new Style.Serializer()).registerTypeAdapterFactory(new LowerCaseEnumTypeAdapterFactory()).create();
+ private static final Gson GSON = (new GsonBuilder()).registerTypeAdapter(ServerStatus.Version.class, new ServerStatus.Version.Serializer()).registerTypeAdapter(ServerStatus.Players.class, new ServerStatus.Players.Serializer()).registerTypeAdapter(ServerStatus.class, new ServerStatus.Serializer()).registerTypeHierarchyAdapter(Component.class, new Component.Serializer()).registerTypeHierarchyAdapter(Style.class, new Style.Serializer()).registerTypeAdapterFactory(new LowerCaseEnumTypeAdapterFactory())
+ .registerTypeAdapter(io.papermc.paper.adventure.AdventureComponent.class, new io.papermc.paper.adventure.AdventureComponent.Serializer())
+ .create();
private final ServerStatus status;
public ClientboundStatusResponsePacket(ServerStatus metadata) {
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 031bd2ed5c6fd2a859e8a69c48db3938cf71d61b..d9fab29a066367a5cf4a3486989fa7f35451801e 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -2,6 +2,9 @@ package net.minecraft.server;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
+import co.aikar.timings.Timings;
+import com.destroystokyo.paper.event.server.PaperServerListPingEvent;
+import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
@@ -1331,7 +1334,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
if (i - this.lastServerStatus >= 5000000000L) {
this.lastServerStatus = i;
this.status.setPlayers(new ServerStatus.Players(this.getMaxPlayers(), this.getPlayerCount()));
- GameProfile[] agameprofile = new GameProfile[Math.min(this.getPlayerCount(), 12)];
+ GameProfile[] agameprofile = new GameProfile[Math.min(this.getPlayerCount(), org.spigotmc.SpigotConfig.playerSample)]; // Paper
int j = Mth.nextInt(this.random, 0, this.getPlayerCount() - agameprofile.length);
for (int k = 0; k < agameprofile.length; ++k) {
diff --git a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
index 9baa56d6da9c24706f1dbc8851fd68ca752cab26..d65191a50349ec86fe35df4ac1070f94fbb77b4c 100644
--- a/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
@@ -47,6 +47,8 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene
this.connection.disconnect(ServerStatusPacketListenerImpl.DISCONNECT_REASON);
} else {
this.hasRequestedStatus = true;
+ // Paper start - Replace everything
+ /*
// CraftBukkit start
// this.networkManager.sendPacket(new PacketStatusOutServerInfo(this.minecraftServer.getServerPing()));
final Object[] players = this.server.getPlayerList().players.toArray();
@@ -142,6 +144,9 @@ public class ServerStatusPacketListenerImpl implements ServerStatusPacketListene
ping.setVersion(new ServerStatus.Version(this.server.getServerModName() + " " + this.server.getServerVersion(), version));
this.connection.send(new ClientboundStatusResponsePacket(ping));
+ */
+ com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.processRequest(this.server, this.connection);
+ // Paper end
}
// CraftBukkit end
}
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
index d73dfe72a54b621c0f944c90904df3e3bc709445..8e7630de11637a75a4a54a22283cbb2d0c7e6438 100644
--- a/src/main/java/org/spigotmc/SpigotConfig.java
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
@@ -289,7 +289,7 @@ public class SpigotConfig
public static int playerSample;
private static void playerSample()
{
- SpigotConfig.playerSample = SpigotConfig.getInt( "settings.sample-count", 12 );
+ SpigotConfig.playerSample = Math.max( SpigotConfig.getInt( "settings.sample-count", 12 ), 0 ); // Paper - Avoid negative counts
Bukkit.getLogger().log( Level.INFO, "Server Ping Player Sample Count: {0}", playerSample ); // Paper - Use logger
}

View file

@ -1,45 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 18 Mar 2018 11:45:57 -0400
Subject: [PATCH] Ability to change PlayerProfile in AsyncPreLoginEvent
This will allow you to change the players name or skin on login.
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index 109d7f1bf37e442ff80f7f63d50e27e6e30e0b5e..261ebb134a5ff40406e74237f730aad1c78a8215 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -1,5 +1,7 @@
package net.minecraft.server.network;
+import com.destroystokyo.paper.profile.CraftPlayerProfile;
+import com.destroystokyo.paper.profile.PlayerProfile;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.exceptions.AuthenticationUnavailableException;
import java.math.BigInteger;
@@ -37,6 +39,7 @@ import org.apache.commons.lang3.Validate;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import io.papermc.paper.adventure.PaperAdventure; // Paper
+import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.util.Waitable;
import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
import org.bukkit.event.player.PlayerPreLoginEvent;
@@ -336,8 +339,16 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
java.util.UUID uniqueId = ServerLoginPacketListenerImpl.this.gameProfile.getId();
final org.bukkit.craftbukkit.CraftServer server = ServerLoginPacketListenerImpl.this.server.server;
- AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, uniqueId);
+ // Paper start
+ PlayerProfile profile = Bukkit.createProfile(uniqueId, playerName);
+ AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, uniqueId, profile);
server.getPluginManager().callEvent(asyncEvent);
+ profile = asyncEvent.getPlayerProfile();
+ profile.complete();
+ gameProfile = CraftPlayerProfile.asAuthlibCopy(profile);
+ playerName = gameProfile.getName();
+ uniqueId = gameProfile.getId();
+ // Paper end
if (PlayerPreLoginEvent.getHandlerList().getRegisteredListeners().length != 0) {
final PlayerPreLoginEvent event = new PlayerPreLoginEvent(playerName, address, uniqueId);

View file

@ -1,133 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 18 Mar 2018 12:29:48 -0400
Subject: [PATCH] Player.setPlayerProfile API
This can be useful for changing name or skins after a player has logged in.
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index 261ebb134a5ff40406e74237f730aad1c78a8215..39bdda56aaa5503efc15207261634127b462c3e7 100644
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -340,12 +340,12 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener
final org.bukkit.craftbukkit.CraftServer server = ServerLoginPacketListenerImpl.this.server.server;
// Paper start
- PlayerProfile profile = Bukkit.createProfile(uniqueId, playerName);
+ PlayerProfile profile = CraftPlayerProfile.asBukkitMirror(ServerLoginPacketListenerImpl.this.gameProfile);
AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, uniqueId, profile);
server.getPluginManager().callEvent(asyncEvent);
profile = asyncEvent.getPlayerProfile();
- profile.complete();
- gameProfile = CraftPlayerProfile.asAuthlibCopy(profile);
+ profile.complete(true);
+ ServerLoginPacketListenerImpl.this.gameProfile = CraftPlayerProfile.asAuthlib(profile);
playerName = gameProfile.getName();
uniqueId = gameProfile.getId();
// Paper end
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 dbab4d28c49d22807dfc582fb83353232396555b..0ef9c95d40cd0cdff0d150121511e6f9efd65f4d 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -173,7 +173,7 @@ public abstract class Player extends LivingEntity {
protected int enchantmentSeed;
protected final float defaultFlySpeed = 0.02F;
private int lastLevelUpTime;
- private final GameProfile gameProfile;
+ public GameProfile gameProfile; // Paper - private->public
private boolean reducedDebugInfo;
private ItemStack lastItemInMainHand;
private final ItemCooldowns cooldowns;
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 4c8617fbd2cd8e34c87634fe448d204ee7fb8a0f..95a1d83fb7cb9947beb56b951b0081e4db2de6c9 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -71,6 +71,7 @@ import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.enchantment.Enchantments;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.block.entity.SignBlockEntity;
import net.minecraft.world.level.saveddata.maps.MapDecoration;
import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
@@ -1347,8 +1348,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
this.hiddenPlayers.put(player.getUniqueId(), hidingPlugins);
// Remove this player from the hidden player's EntityTrackerEntry
- ChunkMap tracker = ((ServerLevel) entity.level).getChunkSource().chunkMap;
+ // Paper start
ServerPlayer other = ((CraftPlayer) player).getHandle();
+ unregisterPlayer(other);
+ }
+ private void unregisterPlayer(ServerPlayer other) {
+ ChunkMap tracker = ((ServerLevel) entity.level).getChunkSource().chunkMap;
+ // Paper end
ChunkMap.TrackedEntity entry = tracker.entityMap.get(other.getId());
if (entry != null) {
entry.removePlayer(this.getHandle());
@@ -1389,8 +1395,13 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
}
this.hiddenPlayers.remove(player.getUniqueId());
- ChunkMap tracker = ((ServerLevel) entity.level).getChunkSource().chunkMap;
+ // Paper start
ServerPlayer other = ((CraftPlayer) player).getHandle();
+ registerPlayer(other);
+ }
+ private void registerPlayer(ServerPlayer other) {
+ ChunkMap tracker = ((ServerLevel) entity.level).getChunkSource().chunkMap;
+ // Paper end
this.getHandle().connection.send(new ClientboundPlayerInfoPacket(ClientboundPlayerInfoPacket.Action.ADD_PLAYER, other));
@@ -1399,6 +1410,50 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
entry.updatePlayer(this.getHandle());
}
}
+ // Paper start
+ private void reregisterPlayer(ServerPlayer player) {
+ if (!hiddenPlayers.containsKey(player.getUUID())) {
+ unregisterPlayer(player);
+ registerPlayer(player);
+ }
+ }
+ public void setPlayerProfile(com.destroystokyo.paper.profile.PlayerProfile profile) {
+ ServerPlayer self = getHandle();
+ self.gameProfile = com.destroystokyo.paper.profile.CraftPlayerProfile.asAuthlibCopy(profile);
+ if (!self.sentListPacket) {
+ return;
+ }
+ List<ServerPlayer> players = server.getServer().getPlayerList().players;
+ for (ServerPlayer player : players) {
+ player.getBukkitEntity().reregisterPlayer(self);
+ }
+ refreshPlayer();
+ }
+ public com.destroystokyo.paper.profile.PlayerProfile getPlayerProfile() {
+ return new com.destroystokyo.paper.profile.CraftPlayerProfile(this).clone();
+ }
+
+ private void refreshPlayer() {
+ ServerPlayer handle = getHandle();
+
+ Location loc = getLocation();
+
+ ServerGamePacketListenerImpl connection = handle.connection;
+ reregisterPlayer(handle);
+
+ //Respawn the player then update their position and selected slot
+ ServerLevel worldserver = handle.getLevel();
+ connection.send(new net.minecraft.network.protocol.game.ClientboundRespawnPacket(worldserver.dimensionType(), worldserver.dimension(), BiomeManager.obfuscateSeed(worldserver.getSeed()), handle.gameMode.getGameModeForPlayer(), handle.gameMode.getPreviousGameModeForPlayer(), worldserver.isDebug(), worldserver.isFlat(), true));
+ handle.onUpdateAbilities();
+ connection.send(new net.minecraft.network.protocol.game.ClientboundPlayerPositionPacket(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch(), java.util.Collections.emptySet(), 0, false));
+ net.minecraft.server.MinecraftServer.getServer().getPlayerList().sendAllPlayerInfo(handle);
+
+ if (this.isOp()) {
+ this.setOp(false);
+ this.setOp(true);
+ }
+ }
+ // Paper end
public void removeDisconnectingPlayer(Player player) {
this.hiddenPlayers.remove(player.getUniqueId());

View file

@ -1,40 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Thu, 22 Mar 2018 01:40:24 -0400
Subject: [PATCH] getPlayerUniqueId API
Gets the unique ID of the player currently known as the specified player name
In Offline Mode, will return an Offline UUID
This is a more performant way to obtain a UUID for a name than loading an OfflinePlayer
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 435a68e6c99bffdc8d6ded9deda68d4e970a2d49..d10da7acb03a2e4a67cee41a6f6fc6357eb8efd6 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1668,6 +1668,25 @@ public final class CraftServer implements Server {
return recipients.size();
}
+ // Paper start
+ @Nullable
+ public UUID getPlayerUniqueId(String name) {
+ Player player = Bukkit.getPlayerExact(name);
+ if (player != null) {
+ return player.getUniqueId();
+ }
+ GameProfile profile;
+ // Only fetch an online UUID in online mode
+ if (com.destroystokyo.paper.PaperConfig.isProxyOnlineMode()) {
+ profile = console.getProfileCache().get(name).orElse(null);
+ } 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);
+ }
+ return profile != null ? profile.getId() : null;
+ }
+ // Paper end
+
@Override
@Deprecated
public OfflinePlayer getOfflinePlayer(String name) {