Files
MiraiMC/patches/server/0015-Slice-Patches.patch
Etil 6d4e96dd1a Add Pufferfish patches
It includes async mob spawning (up to 15% improvement)
2021-11-13 16:53:43 +01:00

559 lines
27 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Etil <81570777+etil2jz@users.noreply.github.com>
Date: Fri, 12 Nov 2021 21:43:06 +0100
Subject: [PATCH] Slice Patches
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEntityDataPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEntityDataPacket.java
index 3e17f6131bf590d7c4a16b79c1c145cb4f565bc9..6029102a2e3631d563b5f1846bc2eab8268c9ac6 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEntityDataPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetEntityDataPacket.java
@@ -21,6 +21,13 @@ public class ClientboundSetEntityDataPacket implements Packet<ClientGamePacketLi
}
}
+
+ // Slice start
+ public ClientboundSetEntityDataPacket(int id, List<SynchedEntityData.DataItem<?>> packedItems) {
+ this.id = id;
+ this.packedItems = packedItems;
+ }
+ // Slice end
public ClientboundSetEntityDataPacket(FriendlyByteBuf buf) {
this.id = buf.readVarInt();
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
index 4c9660176e783999301565790b8cf6f47b0d02a2..2741e4f58ab0c239f791d00aa813cde4d378feea 100644
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetPlayerTeamPacket.java
@@ -41,6 +41,12 @@ public class ClientboundSetPlayerTeamPacket implements Packet<ClientGamePacketLi
public static ClientboundSetPlayerTeamPacket createPlayerPacket(PlayerTeam team, String playerName, ClientboundSetPlayerTeamPacket.Action operation) {
return new ClientboundSetPlayerTeamPacket(team.getName(), operation == ClientboundSetPlayerTeamPacket.Action.ADD ? 3 : 4, Optional.empty(), ImmutableList.of(playerName));
}
+
+ // Slice start
+ public static ClientboundSetPlayerTeamPacket createMultiplePlayerPacket(PlayerTeam team, Collection<String> players, ClientboundSetPlayerTeamPacket.Action operation) {
+ return new ClientboundSetPlayerTeamPacket(team.getName(), operation == ClientboundSetPlayerTeamPacket.Action.ADD ? 3 : 4, Optional.empty(), players);
+ }
+ // Slice end
public ClientboundSetPlayerTeamPacket(FriendlyByteBuf buf) {
this.name = buf.readUtf(16);
diff --git a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
index 4df12454001f0de5f358c88d876e34c35a736c42..a26f3538e286407f655f075f6aa63033b3b748c6 100644
--- a/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
+++ b/src/main/java/net/minecraft/network/syncher/SynchedEntityData.java
@@ -136,6 +136,12 @@ public class SynchedEntityData {
}
public <T> void set(EntityDataAccessor<T> key, T value) {
+ // Slice start
+ set(key, value, null);
+ }
+
+ public <T> void set(EntityDataAccessor<T> key, T value, @Nullable T foreignValue) {
+ // Slice end
SynchedEntityData.DataItem<T> datawatcher_item = this.getItem(key);
if (ObjectUtils.notEqual(value, datawatcher_item.getValue())) {
@@ -144,7 +150,12 @@ public class SynchedEntityData {
datawatcher_item.setDirty(true);
this.isDirty = true;
}
-
+
+ // Slice start
+ if (foreignValue != null && ObjectUtils.notEqual(foreignValue, datawatcher_item.getForeignValue())) {
+ datawatcher_item.setForeignValue(foreignValue);
+ }
+ // Slice end
}
// CraftBukkit start - add method from above
@@ -199,6 +210,28 @@ public class SynchedEntityData {
this.isDirty = false;
return list;
}
+
+ // Slice start
+ @Nullable
+ public List<SynchedEntityData.DataItem<?>> packForeignDirty(List<DataItem<?>> unpackedData) {
+ List<SynchedEntityData.DataItem<?>> list = null;
+
+ for (DataItem<?> dataItem : unpackedData) {
+ DataItem<?> item = itemsById.get(dataItem.accessor.getId());
+ if (item.isDirty(true)) {
+ item.setForeignDirty(false);
+
+ if (list == null) {
+ list = Lists.newArrayList();
+ }
+
+ list.add(item.copy(true));
+ }
+ }
+
+ return list;
+ }
+ // Slice end
@Nullable
public List<SynchedEntityData.DataItem<?>> getAll() {
@@ -313,11 +346,14 @@ public class SynchedEntityData {
final EntityDataAccessor<T> accessor;
T value;
private boolean dirty;
+ @Nullable T foreignValue = null; // Slice
+ private boolean foreignDirty; // Slice
public DataItem(EntityDataAccessor<T> data, T value) {
this.accessor = data;
this.value = value;
this.dirty = true;
+ this.foreignDirty = true; // Slice
}
public EntityDataAccessor<T> getAccessor() {
@@ -343,5 +379,34 @@ public class SynchedEntityData {
public SynchedEntityData.DataItem<T> copy() {
return new SynchedEntityData.DataItem<>(this.accessor, this.accessor.getSerializer().copy(this.value));
}
+
+ // Slice start
+ public void setForeignValue(T foreignValue) {
+ this.foreignValue = foreignValue;
+ this.foreignDirty = true;
+ }
+
+ public @Nullable T getForeignValue() {
+ return foreignValue;
+ }
+
+ public boolean isDirty(boolean foreign) {
+ if (foreign) {
+ // There must be a foreign value in order for this to be dirty, otherwise we consider this a normal
+ // value and check the normal dirty flag.
+ return foreignValue == null || this.foreignDirty;
+ }
+
+ return this.dirty;
+ }
+
+ public void setForeignDirty(boolean dirty) {
+ this.foreignDirty = dirty;
+ }
+
+ public SynchedEntityData.DataItem<T> copy(boolean foreign) {
+ return new SynchedEntityData.DataItem<>(this.accessor, this.accessor.getSerializer().copy((foreign && this.foreignValue != null ? this.foreignValue : this.value)));
+ }
+ // Slice end
}
}
diff --git a/src/main/java/net/minecraft/server/ServerScoreboard.java b/src/main/java/net/minecraft/server/ServerScoreboard.java
index 130a928f156961bae9ca184b3ca31004dbba1012..063e4f9f140a39c519b1d4892bfa331d1265755c 100644
--- a/src/main/java/net/minecraft/server/ServerScoreboard.java
+++ b/src/main/java/net/minecraft/server/ServerScoreboard.java
@@ -3,6 +3,7 @@ package net.minecraft.server;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.Iterator;
+import java.util.Collection; // Slice
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -91,6 +92,19 @@ public class ServerScoreboard extends Scoreboard {
return false;
}
}
+
+ // Slice start
+ @Override
+ public boolean addPlayersToTeam(Collection<String> players, PlayerTeam team) {
+ if (super.addPlayersToTeam(players, team)) {
+ this.sendAll(ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket(team, players, ClientboundSetPlayerTeamPacket.Action.ADD));
+ this.setDirty();
+ return true;
+ } else {
+ return false;
+ }
+ }
+ // Slice end
@Override
public void removePlayerFromTeam(String playerName, PlayerTeam team) {
@@ -98,6 +112,19 @@ public class ServerScoreboard extends Scoreboard {
this.sendAll(ClientboundSetPlayerTeamPacket.createPlayerPacket(team, playerName, ClientboundSetPlayerTeamPacket.Action.REMOVE));
this.setDirty();
}
+
+ // Slice start
+ @Override
+ public boolean removePlayersFromTeam(Collection<String> players, PlayerTeam team) {
+ if (super.removePlayersFromTeam(players, team)) {
+ this.sendAll(ClientboundSetPlayerTeamPacket.createMultiplePlayerPacket(team, players, ClientboundSetPlayerTeamPacket.Action.REMOVE));
+ this.setDirty();
+ return true;
+ } else {
+ return false;
+ }
+ }
+ // Slice end
@Override
public void onObjectiveAdded(Objective objective) {
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
index 96b11907d99e058041e81a29f8727465e3fa6723..0a3edd5c6a3ef8341855d138dadf24e6db09e54d 100644
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
@@ -387,7 +387,19 @@ public class ServerEntity {
SynchedEntityData datawatcher = this.entity.getEntityData();
if (datawatcher.isDirty()) {
- this.broadcastAndSend(new ClientboundSetEntityDataPacket(this.entity.getId(), datawatcher, false));
+ // Slice start
+ ClientboundSetEntityDataPacket dataPacket = new ClientboundSetEntityDataPacket(this.entity.getId(), datawatcher, false);
+ if (this.entity instanceof ServerPlayer serverPlayer) {
+ serverPlayer.connection.send(dataPacket);
+ }
+
+ // Get the packedData that the original packet has, and then determine if any of those are changed in
+ // the foreign version. If null, nothing to notify foreign trackers about.
+ List<SynchedEntityData.DataItem<?>> dirtyItems = datawatcher.packForeignDirty(dataPacket.getUnpackedData());
+ if (dirtyItems != null) {
+ this.broadcast(new ClientboundSetEntityDataPacket(this.entity.getId(), dirtyItems));
+ }
+ // Slice end
}
if (this.entity instanceof LivingEntity) {
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
index 1ae7a10df7460f223413c38ac6bd85dba15fb347..e9fb961f20486f522a679e35d1fe4c586e379420 100644
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
@@ -200,6 +200,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
public final UUID uuid;
public boolean hasPhysicsEvent = true; // Paper
public boolean hasEntityMoveEvent = false; // Paper
+ public boolean instance; // Slice
public static Throwable getAddToWorldStackTrace(Entity entity) {
return new Throwable(entity + " Added to world at " + new java.util.Date());
}
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 24a8c047b717c26b6efb4cd67c061527bc6c9cd4..def69c8b959f859952d7f1d1443f1e4c17843bfb 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -263,6 +263,7 @@ public class ServerPlayer extends Player {
public final com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> cachedSingleHashSet; // Paper
public boolean needsChunkCenterUpdate; // Paper - no-tick view distance // Paper - public
public org.bukkit.event.player.PlayerQuitEvent.QuitReason quitReason = null; // Paper - there are a lot of changes to do if we change all methods leading to the event
+ public boolean smoothWorldTeleport; // Slice
public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile) {
super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile);
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 4caef00726f3e421cec2ef955c3db8d074348c49..370af31206bb1cd9fa50541a95baa7a12aec8cd0 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -952,11 +952,11 @@ public abstract class PlayerList {
}
// CraftBukkit start
LevelData worlddata = worldserver1.getLevelData();
- entityplayer1.connection.send(new ClientboundRespawnPacket(worldserver1.dimensionType(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), entityplayer1.gameMode.getGameModeForPlayer(), entityplayer1.gameMode.getPreviousGameModeForPlayer(), worldserver1.isDebug(), worldserver1.isFlat(), flag));
+ if (!entityplayer.smoothWorldTeleport) entityplayer1.connection.send(new ClientboundRespawnPacket(worldserver1.dimensionType(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), entityplayer1.gameMode.getGameModeForPlayer(), entityplayer1.gameMode.getPreviousGameModeForPlayer(), worldserver1.isDebug(), worldserver1.isFlat(), flag));
entityplayer1.connection.send(new ClientboundSetChunkCacheRadiusPacket(worldserver1.getChunkSource().chunkMap.playerChunkManager.getLoadDistance())); // Spigot // Paper - no-tick view distance// Paper - replace old player chunk management
entityplayer1.setLevel(worldserver1);
entityplayer1.unsetRemoved();
- entityplayer1.connection.teleport(new Location(worldserver1.getWorld(), entityplayer1.getX(), entityplayer1.getY(), entityplayer1.getZ(), entityplayer1.getYRot(), entityplayer1.getXRot()));
+ if (!entityplayer.smoothWorldTeleport) entityplayer1.connection.teleport(new Location(worldserver1.getWorld(), entityplayer1.getX(), entityplayer1.getY(), entityplayer1.getZ(), entityplayer1.getYRot(), entityplayer1.getXRot()));
entityplayer1.setShiftKeyDown(false);
// entityplayer1.connection.b(entityplayer1.locX(), entityplayer1.locY(), entityplayer1.locZ(), entityplayer1.getYRot(), entityplayer1.getXRot());
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
index 4e5a8be29816b96ce1738e6cedffd99b00909036..2c0ca9194e8ad3b53776455db54cca16dc1095e4 100644
--- a/src/main/java/net/minecraft/world/entity/Entity.java
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
@@ -787,7 +787,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
this.checkOutOfWorld();
if (!this.level.isClientSide) {
- this.setSharedFlagOnFire(this.remainingFireTicks > 0);
+ if (this instanceof net.minecraft.world.entity.LivingEntity livingEntity) {
+ this.setSharedFlagOnFire(this.remainingFireTicks > 0 && !livingEntity.hasEffect(net.minecraft.world.effect.MobEffects.FIRE_RESISTANCE));
+ } else {
+ this.setSharedFlagOnFire(this.remainingFireTicks > 0);
+ }
}
this.firstTick = false;
@@ -2969,7 +2973,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, n
if (event.isCancelled()) {
return;
}
- this.entityData.set(Entity.DATA_AIR_SUPPLY_ID, event.getAmount());
+ this.entityData.set(Entity.DATA_AIR_SUPPLY_ID, event.getAmount(), getMaxAirSupply()); // Slice
// CraftBukkit end
}
diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java
index 8576d7f4acba258a9d42218e7d50cc3067236b52..82678fd59a4a49cca6e5a90b850197d93d5fa18f 100644
--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java
+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java
@@ -3024,7 +3024,7 @@ public abstract class LivingEntity extends Entity {
ItemStack itemstack1 = this.getItemBySlot(enumitemslot);
- if (!ItemStack.matches(itemstack1, itemstack)) {
+ if (!ItemStack.isSameIgnoreDurability(itemstack1, itemstack)) {
// Paper start - PlayerArmorChangeEvent
if (this instanceof ServerPlayer && enumitemslot.getType() == EquipmentSlot.Type.ARMOR) {
final org.bukkit.inventory.ItemStack oldItem = CraftItemStack.asBukkitCopy(itemstack);
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 94e76e295dbd0f3bac4b30a3e7338cd56a971207..4484c6dc092f5fc8e1a33b0e7096f618e45df879 100644
--- a/src/main/java/net/minecraft/world/entity/player/Player.java
+++ b/src/main/java/net/minecraft/world/entity/player/Player.java
@@ -633,7 +633,7 @@ public abstract class Player extends LivingEntity {
public void increaseScore(int score) {
int j = this.getScore();
- this.entityData.set(Player.DATA_SCORE_ID, j + score);
+ this.entityData.set(Player.DATA_SCORE_ID, j + score, 0); // Slice
}
@Override
diff --git a/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java b/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java
index 86528ff031014e788d72a8bf7c1c9443512096bb..51d3557db8caa9852ec2627ab53d802be2b59745 100644
--- a/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java
+++ b/src/main/java/net/minecraft/world/level/biome/MobSpawnSettings.java
@@ -41,9 +41,10 @@ public class MobSpawnSettings {
}), Codec.BOOL.fieldOf("player_spawn_friendly").orElse(false).forGetter(MobSpawnSettings::playerSpawnFriendly)).apply(instance, MobSpawnSettings::new);
});
private final float creatureGenerationProbability;
- private final Map<MobCategory, WeightedRandomList<MobSpawnSettings.SpawnerData>> spawners;
- private final Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> mobSpawnCosts;
+ private Map<MobCategory, WeightedRandomList<MobSpawnSettings.SpawnerData>> spawners; // Slice
+ private Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> mobSpawnCosts; // Slice
private final boolean playerSpawnFriendly;
+ private boolean stripped; // Slice
MobSpawnSettings(float creatureSpawnProbability, Map<MobCategory, WeightedRandomList<MobSpawnSettings.SpawnerData>> spawners, Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> spawnCosts, boolean playerSpawnFriendly) {
this.creatureGenerationProbability = creatureSpawnProbability;
@@ -51,13 +52,50 @@ public class MobSpawnSettings {
this.mobSpawnCosts = ImmutableMap.copyOf(spawnCosts);
this.playerSpawnFriendly = playerSpawnFriendly;
}
+
+ // Slice start
+ // This very stupid thing is because Mob Spawning Biome data is statically registered before CraftServer
+ // is even created. As a result, we need to lazily rebuild our spawning data here which is very cool and very
+ // stupid. But it should only really happen once up front, so isn't the end of the world
+ private void stripSpawnData() {
+ if (wtf.etil.mirai.MiraiConfig.globalBlockedMobSpawnTypes.isEmpty()) {
+ stripped = true;
+ return;
+ }
+
+ Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> finalMobSpawnCosts = new java.util.HashMap<>();
+ for (Entry<EntityType<?>, MobSpawnSettings.MobSpawnCost> entry : mobSpawnCosts.entrySet()) {
+ if (!wtf.etil.mirai.MiraiConfig.globalBlockedMobSpawnTypes.contains(entry.getKey())) {
+ finalMobSpawnCosts.put(entry.getKey(), entry.getValue());
+ }
+ }
+ this.mobSpawnCosts = ImmutableMap.copyOf(finalMobSpawnCosts);
+
+ Map<MobCategory, WeightedRandomList<MobSpawnSettings.SpawnerData>> finalSpawners = new java.util.HashMap<>();
+ for (Entry<MobCategory, WeightedRandomList<SpawnerData>> entry : spawners.entrySet()) {
+ List<SpawnerData> finalSpawnerData = new java.util.ArrayList<>();
+ for (SpawnerData spawnerData : entry.getValue().unwrap()) {
+ if (!wtf.etil.mirai.MiraiConfig.globalBlockedMobSpawnTypes.contains(spawnerData.type)) {
+ finalSpawnerData.add(spawnerData);
+ }
+ }
+
+ finalSpawners.put(entry.getKey(), finalSpawnerData.isEmpty() ? EMPTY_MOB_LIST : WeightedRandomList.create(finalSpawnerData));
+ }
+
+ this.spawners = ImmutableMap.copyOf(finalSpawners);
+ stripped = true;
+ }
+ // Slice end
public WeightedRandomList<MobSpawnSettings.SpawnerData> getMobs(MobCategory spawnGroup) {
+ if (!stripped) stripSpawnData(); // Slice
return this.spawners.getOrDefault(spawnGroup, EMPTY_MOB_LIST);
}
@Nullable
public MobSpawnSettings.MobSpawnCost getMobSpawnCost(EntityType<?> entityType) {
+ if (!stripped) stripSpawnData(); // Slice
return this.mobSpawnCosts.get(entityType);
}
diff --git a/src/main/java/net/minecraft/world/scores/Scoreboard.java b/src/main/java/net/minecraft/world/scores/Scoreboard.java
index 3e75ea4d5a6c83ca570b29e3c1a5d51fb132379a..8a55e56a3aa1a8aa4c0780f46a98110c7b931155 100644
--- a/src/main/java/net/minecraft/world/scores/Scoreboard.java
+++ b/src/main/java/net/minecraft/world/scores/Scoreboard.java
@@ -223,6 +223,28 @@ public class Scoreboard {
return team.getPlayers().add(playerName);
}
}
+
+ // Slice start
+ public boolean addPlayersToTeam(Collection<String> players, PlayerTeam team) {
+ boolean anyAdded = false;
+ for (String playerName : players) {
+ if (playerName.length() > 40) {
+ net.minecraft.server.MinecraftServer.LOGGER.warn("The player name '" + playerName + "' is too long!");
+ } else {
+ if (this.getPlayersTeam(playerName) != null) {
+ this.removePlayerFromTeam(playerName);
+ }
+
+ this.teamsByPlayer.put(playerName, team);
+ if (team.getPlayers().add(playerName)) {
+ anyAdded = true;
+ }
+ }
+ }
+
+ return anyAdded;
+ }
+ // Slice end
public boolean removePlayerFromTeam(String playerName) {
PlayerTeam playerTeam = this.getPlayersTeam(playerName);
@@ -242,6 +264,24 @@ public class Scoreboard {
team.getPlayers().remove(playerName);
}
}
+
+ // Slice start
+ public boolean removePlayersFromTeam(Collection<String> players, PlayerTeam team) {
+ boolean anyRemoved = false;
+ for (String playerName : players) {
+ if (this.getPlayersTeam(playerName) != team) {
+ net.minecraft.server.MinecraftServer.LOGGER.warn("Player " + playerName + " is either on another team or not on any team. Cannot remove from team '" + team.getName() + "'.");
+ } else {
+ this.teamsByPlayer.remove(playerName);
+ if (team.getPlayers().remove(playerName)) {
+ anyRemoved = true;
+ }
+ }
+ }
+
+ return anyRemoved;
+ }
+ // Slice end
public Collection<String> getTeamNames() {
return this.teamsByName.keySet();
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index 3b386ecc7630ab50cac1ae6fcb3141d444a74434..c7a33c379b29a39db8cfcfd4c6298b26fc4663e6 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -1195,6 +1195,18 @@ public class CraftWorld extends CraftRegionAccessor implements World {
public void setAutoSave(boolean value) {
world.noSave = !value;
}
+
+ // Slice start
+ @Override
+ public boolean isInstance() {
+ return world.instance;
+ }
+
+ @Override
+ public void setInstance(boolean value) {
+ world.instance = value;
+ }
+ // Slice end
@Override
public void setDifficulty(Difficulty difficulty) {
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 2176269aa602049d69ec65bb1c1629a6680ccfa2..9c69d26ccdf6bf2b5f2128328ac792c175047b2c 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -2010,7 +2010,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
this.sendHealthUpdate();
}
}
- this.getHandle().getEntityData().set(LivingEntity.DATA_HEALTH_ID, (float) this.getScaledHealth());
+ this.getHandle().getEntityData().set(LivingEntity.DATA_HEALTH_ID, (float) this.getScaledHealth(), isDead() ? 0f : 20f); // Slice
this.getHandle().maxHealthCache = getMaxHealth();
}
diff --git a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
index 2b87a652798cb632fe76bf20e9e7f8cb8bfb3b7b..1b10b3628e09b6c831e4907bf79e87a503e92dcf 100644
--- a/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
+++ b/src/main/java/org/bukkit/craftbukkit/scoreboard/CraftTeam.java
@@ -1,6 +1,7 @@
package org.bukkit.craftbukkit.scoreboard;
import com.google.common.collect.ImmutableSet;
+import java.util.Collection; // Slice
import java.util.Set;
import net.minecraft.world.scores.PlayerTeam;
import net.minecraft.world.scores.Team.Visibility;
@@ -225,6 +226,16 @@ final class CraftTeam extends CraftScoreboardComponent implements Team {
scoreboard.board.addPlayerToTeam(entry, team);
}
+
+ // Slice start
+ @Override
+ public void addEntries(Collection<String> entries) throws IllegalStateException, IllegalArgumentException {
+ Validate.notNull(entries, "Entries cannot be null");
+ CraftScoreboard scoreboard = checkState();
+
+ scoreboard.board.addPlayersToTeam(entries, team);
+ }
+ // Slice end
@Override
public boolean removePlayer(OfflinePlayer player) throws IllegalStateException, IllegalArgumentException {
@@ -244,6 +255,25 @@ final class CraftTeam extends CraftScoreboardComponent implements Team {
scoreboard.board.removePlayerFromTeam(entry, team);
return true;
}
+
+ // Slice start
+ @Override
+ public boolean removeEntries(Collection<String> entries) throws IllegalStateException, IllegalArgumentException {
+ Validate.notNull(entries, "Entry cannot be null");
+ CraftScoreboard scoreboard = this.checkState();
+
+ boolean anyRemoved = false;
+ Collection<String> teamPlayers = this.team.getPlayers();
+ for (String entry : entries) {
+ if (teamPlayers.remove(entry)) {
+ anyRemoved = true;
+ }
+ }
+
+ scoreboard.board.removePlayersFromTeam(entries, team);
+ return anyRemoved;
+ }
+ // Slice end
@Override
public boolean hasPlayer(OfflinePlayer player) throws IllegalArgumentException, IllegalStateException {
diff --git a/src/main/java/wtf/etil/mirai/MiraiConfig.java b/src/main/java/wtf/etil/mirai/MiraiConfig.java
index ca61a8b5621f6e5d925bcab997950029e56a6813..a0389406b9e2ff343d926581e05361bc9edaac4e 100644
--- a/src/main/java/wtf/etil/mirai/MiraiConfig.java
+++ b/src/main/java/wtf/etil/mirai/MiraiConfig.java
@@ -243,4 +243,13 @@ public class MiraiConfig {
entitiesCanUsePortals = getBoolean("settings.entities-can-use-portals", entitiesCanUsePortals);
}
+ public static java.util.Set<net.minecraft.world.entity.EntityType<?>> globalBlockedMobSpawnTypes = new java.util.HashSet<>();
+ private static void globalBlockedMobSpawnTypes() {
+ java.util.List<String> list = getList("settings.global-blocked-mobspawn-types", java.util.Collections.emptyList());
+ for (String type : list) {
+ java.util.Optional<net.minecraft.world.entity.EntityType<?>> entityType = net.minecraft.world.entity.EntityType.byString(type.toLowerCase());
+ entityType.ifPresent(eType -> globalBlockedMobSpawnTypes.add(eType));
+ }
+ }
+
}
\ No newline at end of file