add remapped patches as a test

This commit is contained in:
MiniDigger | Martin 2024-01-14 11:04:49 +01:00
parent 0a44692ef6
commit bee74680e6
2618 changed files with 479913 additions and 0 deletions

View file

@ -0,0 +1,16 @@
--- a/net/minecraft/CrashReport.java
+++ b/net/minecraft/CrashReport.java
@@ -33,9 +33,10 @@
private StackTraceElement[] uncategorizedStackTrace = new StackTraceElement[0];
private final SystemReport systemReport = new SystemReport();
- public CrashReport(String s, Throwable throwable) {
- this.title = s;
- this.exception = throwable;
+ public CrashReport(String title, Throwable exception) {
+ this.title = title;
+ this.exception = exception;
+ this.systemReport.setDetail("CraftBukkit Information", new org.bukkit.craftbukkit.CraftCrashReport()); // CraftBukkit
}
public String getTitle() {

View file

@ -0,0 +1,24 @@
--- a/net/minecraft/advancements/AdvancementHolder.java
+++ b/net/minecraft/advancements/AdvancementHolder.java
@@ -2,6 +2,10 @@
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
+// CraftBukkit start
+import org.bukkit.craftbukkit.advancement.CraftAdvancement;
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+// CraftBukkit end
public record AdvancementHolder(ResourceLocation id, Advancement value) {
@@ -44,4 +45,10 @@
public String toString() {
return this.id.toString();
}
+
+ // CraftBukkit start
+ public final org.bukkit.advancement.Advancement toBukkit() {
+ return new CraftAdvancement(this);
+ }
+ // CraftBukkit end
}

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/advancements/AdvancementTree.java
+++ b/net/minecraft/advancements/AdvancementTree.java
@@ -77,7 +77,7 @@
}
}
- AdvancementTree.LOGGER.info("Loaded {} advancements", this.nodes.size());
+ // AdvancementTree.LOGGER.info("Loaded {} advancements", this.nodes.size()); // CraftBukkit - moved to AdvancementDataWorld#reload
}
private boolean tryInsert(AdvancementHolder advancementholder) {

View file

@ -0,0 +1,23 @@
--- a/net/minecraft/commands/CommandSource.java
+++ b/net/minecraft/commands/CommandSource.java
@@ -26,6 +22,13 @@
public boolean shouldInformAdmins() {
return false;
}
+
+ // CraftBukkit start
+ @Override
+ public org.bukkit.command.CommandSender getBukkitSender(CommandSourceStack wrapper) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ // CraftBukkit end
};
void sendSystemMessage(Component component);
@@ -39,4 +42,6 @@
default boolean alwaysAccepts() {
return false;
}
+
+ org.bukkit.command.CommandSender getBukkitSender(CommandSourceStack wrapper); // CraftBukkit
}

View file

@ -0,0 +1,68 @@
--- a/net/minecraft/commands/CommandSourceStack.java
+++ b/net/minecraft/commands/CommandSourceStack.java
@@ -44,6 +43,7 @@
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
+import com.mojang.brigadier.tree.CommandNode; // CraftBukkit
public class CommandSourceStack implements ExecutionCommandSource<CommandSourceStack>, SharedSuggestionProvider {
@@ -64,6 +64,7 @@
private final Vec2 rotation;
private final CommandSigningContext signingContext;
private final TaskChainer chatMessageChainer;
+ public volatile CommandNode currentCommand; // CraftBukkit
public CommandSourceStack(CommandSource commandsource, Vec3 vec3, Vec2 vec2, ServerLevel serverlevel, int i, String s, Component component, MinecraftServer minecraftserver, @Nullable Entity entity) {
this(commandsource, vec3, vec2, serverlevel, i, s, component, minecraftserver, entity, false, CommandResultCallback.EMPTY, EntityAnchorArgument.Anchor.FEET, CommandSigningContext.ANONYMOUS, TaskChainer.immediate(minecraftserver));
@@ -170,11 +170,24 @@
}
@Override
- @Override
- public boolean hasPermission(int i) {
- return this.permissionLevel >= i;
+ public boolean hasPermission(int level) {
+ // CraftBukkit start
+ CommandNode currentCommand = this.currentCommand;
+ if (currentCommand != null) {
+ return hasPermission(level, org.bukkit.craftbukkit.command.VanillaCommandWrapper.getPermission(currentCommand));
+ }
+ // CraftBukkit end
+
+ return this.permissionLevel >= level;
}
+ // CraftBukkit start
+ public boolean hasPermission(int i, String bukkitPermission) {
+ // World is null when loading functions
+ return ((getLevel() == null || !getLevel().getCraftServer().ignoreVanillaPermissions) && this.permissionLevel >= i) || getBukkitSender().hasPermission(bukkitPermission);
+ }
+ // CraftBukkit end
+
public Vec3 getPosition() {
return this.worldPosition;
}
@@ -307,8 +320,8 @@
while (iterator.hasNext()) {
ServerPlayer serverplayer = (ServerPlayer) iterator.next();
- if (serverplayer != this.source && this.server.getPlayerList().isOp(serverplayer.getGameProfile())) {
- serverplayer.sendSystemMessage(mutablecomponent);
+ if (entityplayer != this.source && entityplayer.getBukkitEntity().hasPermission("minecraft.admin.command_feedback")) { // CraftBukkit
+ entityplayer.sendSystemMessage(ichatmutablecomponent);
}
}
}
@@ -413,4 +413,10 @@
public boolean isSilent() {
return this.silent;
}
+
+ // CraftBukkit start
+ public org.bukkit.command.CommandSender getBukkitSender() {
+ return source.getBukkitSender(this);
+ }
+ // CraftBukkit end
}

View file

@ -0,0 +1,171 @@
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -135,6 +134,14 @@
import net.minecraft.world.level.GameRules;
import org.slf4j.Logger;
+// CraftBukkit start
+import com.google.common.base.Joiner;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import org.bukkit.event.player.PlayerCommandSendEvent;
+import org.bukkit.event.server.ServerCommandEvent;
+// CraftBukkit end
+
public class Commands {
private static final ThreadLocal<ExecutionContext<CommandSourceStack>> CURRENT_EXECUTION_CONTEXT = new ThreadLocal();
@@ -146,7 +153,8 @@
public static final int LEVEL_OWNERS = 4;
private final CommandDispatcher<CommandSourceStack> dispatcher = new CommandDispatcher();
- public Commands(Commands.CommandSelection commands_commandselection, CommandBuildContext commandbuildcontext) {
+ public Commands(Commands.CommandSelection selection, CommandBuildContext context) {
+ this(); // CraftBukkit
AdvancementCommands.register(this.dispatcher);
AttributeCommand.register(this.dispatcher, commandbuildcontext);
ExecuteCommand.register(this.dispatcher, commandbuildcontext);
@@ -247,6 +255,11 @@
PublishCommand.register(this.dispatcher);
}
+ // CraftBukkit start
+ }
+
+ public Commands() {
+ // CraftBukkkit end
this.dispatcher.setConsumer(ExecutionCommandSource.resultConsumer());
}
@@ -257,18 +270,64 @@
return new ParseResults(commandcontextbuilder1, parseresults.getReader(), parseresults.getExceptions());
}
- public void performPrefixedCommand(CommandSourceStack commandsourcestack, String s) {
+ // CraftBukkit start
+ public void dispatchServerCommand(CommandSourceStack sender, String command) {
+ Joiner joiner = Joiner.on(" ");
+ if (command.startsWith("/")) {
+ command = command.substring(1);
+ }
+
+ ServerCommandEvent event = new ServerCommandEvent(sender.getBukkitSender(), command);
+ org.bukkit.Bukkit.getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return;
+ }
+ command = event.getCommand();
+
+ String[] args = command.split(" ");
+
+ String cmd = args[0];
+ if (cmd.startsWith("minecraft:")) cmd = cmd.substring("minecraft:".length());
+ if (cmd.startsWith("bukkit:")) cmd = cmd.substring("bukkit:".length());
+
+ // Block disallowed commands
+ if (cmd.equalsIgnoreCase("stop") || cmd.equalsIgnoreCase("kick") || cmd.equalsIgnoreCase("op")
+ || cmd.equalsIgnoreCase("deop") || cmd.equalsIgnoreCase("ban") || cmd.equalsIgnoreCase("ban-ip")
+ || cmd.equalsIgnoreCase("pardon") || cmd.equalsIgnoreCase("pardon-ip") || cmd.equalsIgnoreCase("reload")) {
+ return;
+ }
+
+ // Handle vanilla commands;
+ if (sender.getLevel().getCraftServer().getCommandBlockOverride(args[0])) {
+ args[0] = "minecraft:" + args[0];
+ }
+
+ String newCommand = joiner.join(args);
+ this.performPrefixedCommand(sender, newCommand, newCommand);
+ }
+ // CraftBukkit end
+
+ public void performPrefixedCommand(CommandSourceStack commandlistenerwrapper, String s) {
+ // CraftBukkit start
+ this.performPrefixedCommand(commandlistenerwrapper, s, s);
+ }
+
+ public void performPrefixedCommand(CommandSourceStack commandlistenerwrapper, String s, String label) {
s = s.startsWith("/") ? s.substring(1) : s;
- this.performCommand(this.dispatcher.parse(s, commandsourcestack), s);
+ this.performCommand(this.dispatcher.parse(s, commandlistenerwrapper), s, label);
+ // CraftBukkit end
}
public void performCommand(ParseResults<CommandSourceStack> parseresults, String s) {
CommandSourceStack commandsourcestack = (CommandSourceStack) parseresults.getContext().getSource();
- commandsourcestack.getServer().getProfiler().push(() -> {
+ public void performCommand(ParseResults<CommandSourceStack> parseresults, String s, String label) { // CraftBukkit
+ CommandSourceStack commandlistenerwrapper = (CommandSourceStack) parseresults.getContext().getSource();
+
+ commandlistenerwrapper.getServer().getProfiler().push(() -> {
return "/" + s;
});
- ContextChain contextchain = finishParsing(parseresults, s, commandsourcestack);
+ ContextChain contextchain = finishParsing(parseresults, s, commandlistenerwrapper, label); // CraftBukkit
try {
if (contextchain != null) {
@@ -302,7 +362,7 @@
}
@Nullable
- private static ContextChain<CommandSourceStack> finishParsing(ParseResults<CommandSourceStack> parseresults, String s, CommandSourceStack commandsourcestack) {
+ private static ContextChain<CommandSourceStack> finishParsing(ParseResults<CommandSourceStack> parseresults, String s, CommandSourceStack commandlistenerwrapper, String label) { // CraftBukkit
try {
validateParseResults(parseresults);
return (ContextChain) ContextChain.tryFlatten(parseresults.getContext().build(s)).orElseThrow(() -> {
@@ -312,8 +372,8 @@
commandsourcestack.sendFailure(ComponentUtils.fromMessage(commandsyntaxexception.getRawMessage()));
if (commandsyntaxexception.getInput() != null && commandsyntaxexception.getCursor() >= 0) {
int i = Math.min(commandsyntaxexception.getInput().length(), commandsyntaxexception.getCursor());
- MutableComponent mutablecomponent = Component.empty().withStyle(ChatFormatting.GRAY).withStyle((style) -> {
- return style.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/" + s));
+ MutableComponent ichatmutablecomponent = Component.empty().withStyle(ChatFormatting.GRAY).withStyle((chatmodifier) -> {
+ return chatmodifier.withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, label)); // CraftBukkit
});
if (i > 10) {
@@ -371,13 +431,38 @@
}
- public void sendCommands(ServerPlayer serverplayer) {
- Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> map = Maps.newHashMap();
+ public void sendCommands(ServerPlayer player) {
+ // CraftBukkit start
+ // Register Vanilla commands into builtRoot as before
+ Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> map = Maps.newIdentityHashMap(); // Use identity to prevent aliasing issues
+ RootCommandNode vanillaRoot = new RootCommandNode();
+
+ RootCommandNode<CommandSourceStack> vanilla = player.server.vanillaCommandDispatcher.getDispatcher().getRoot();
+ map.put(vanilla, vanillaRoot);
+ this.fillUsableCommands(vanilla, vanillaRoot, player.createCommandSourceStack(), (Map) map);
+
+ // Now build the global commands in a second pass
RootCommandNode<SharedSuggestionProvider> rootcommandnode = new RootCommandNode();
map.put(this.dispatcher.getRoot(), rootcommandnode);
- this.fillUsableCommands(this.dispatcher.getRoot(), rootcommandnode, serverplayer.createCommandSourceStack(), map);
- serverplayer.connection.send(new ClientboundCommandsPacket(rootcommandnode));
+ this.fillUsableCommands(this.dispatcher.getRoot(), rootcommandnode, player.createCommandSourceStack(), map);
+
+ Collection<String> bukkit = new LinkedHashSet<>();
+ for (CommandNode node : rootcommandnode.getChildren()) {
+ bukkit.add(node.getName());
+ }
+
+ PlayerCommandSendEvent event = new PlayerCommandSendEvent(player.getBukkitEntity(), new LinkedHashSet<>(bukkit));
+ event.getPlayer().getServer().getPluginManager().callEvent(event);
+
+ // Remove labels that were removed during the event
+ for (String orig : bukkit) {
+ if (!event.getCommands().contains(orig)) {
+ rootcommandnode.removeCommand(orig);
+ }
+ }
+ // CraftBukkit end
+ player.connection.send(new ClientboundCommandsPacket(rootcommandnode));
}
private void fillUsableCommands(CommandNode<CommandSourceStack> commandnode, CommandNode<SharedSuggestionProvider> commandnode1, CommandSourceStack commandsourcestack, Map<CommandNode<CommandSourceStack>, CommandNode<SharedSuggestionProvider>> map) {

View file

@ -0,0 +1,23 @@
--- a/net/minecraft/commands/arguments/EntityArgument.java
+++ b/net/minecraft/commands/arguments/EntityArgument.java
@@ -93,11 +93,16 @@
}
}
- @Override
- public EntitySelector parse(StringReader stringreader) throws CommandSyntaxException {
+ public EntitySelector parse(StringReader reader) throws CommandSyntaxException {
+ // CraftBukkit start
+ return parse(reader, false);
+ }
+
+ public EntitySelector parse(StringReader stringreader, boolean overridePermissions) throws CommandSyntaxException {
+ // CraftBukkit end
boolean flag = false;
- EntitySelectorParser entityselectorparser = new EntitySelectorParser(stringreader);
- EntitySelector entityselector = entityselectorparser.parse();
+ EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader);
+ EntitySelector entityselector = argumentparserselector.parse(overridePermissions); // CraftBukkit
if (entityselector.getMaxResults() > 1 && this.single) {
if (this.playersOnly) {

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/commands/arguments/blocks/BlockStateParser.java
+++ b/net/minecraft/commands/arguments/blocks/BlockStateParser.java
@@ -68,7 +68,7 @@
private final StringReader reader;
private final boolean forTesting;
private final boolean allowNbt;
- private final Map<Property<?>, Comparable<?>> properties = Maps.newHashMap();
+ private final Map<Property<?>, Comparable<?>> properties = Maps.newLinkedHashMap(); // CraftBukkit - stable
private final Map<String, String> vagueProperties = Maps.newHashMap();
private ResourceLocation id = new ResourceLocation("");
@Nullable

View file

@ -0,0 +1,13 @@
--- a/net/minecraft/commands/arguments/selector/EntitySelector.java
+++ b/net/minecraft/commands/arguments/selector/EntitySelector.java
@@ -93,8 +91,8 @@
return this.usesSelector;
}
- private void checkPermissions(CommandSourceStack commandsourcestack) throws CommandSyntaxException {
- if (this.usesSelector && !commandsourcestack.hasPermission(2)) {
+ private void checkPermissions(CommandSourceStack source) throws CommandSyntaxException {
+ if (this.usesSelector && !source.hasPermission(2, "minecraft.command.selector")) { // CraftBukkit
throw EntityArgument.ERROR_SELECTORS_NOT_ALLOWED.create();
}
}

View file

@ -0,0 +1,37 @@
--- a/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
+++ b/net/minecraft/commands/arguments/selector/EntitySelectorParser.java
@@ -204,8 +204,10 @@
};
}
- protected void parseSelector() throws CommandSyntaxException {
- this.usesSelectors = true;
+ // CraftBukkit start
+ protected void parseSelector(boolean overridePermissions) throws CommandSyntaxException {
+ this.usesSelectors = !overridePermissions;
+ // CraftBukkit end
this.suggestions = this::suggestSelector;
if (!this.reader.canRead()) {
throw EntitySelectorParser.ERROR_MISSING_SELECTOR_TYPE.createWithContext(this.reader);
@@ -463,6 +465,12 @@
}
public EntitySelector parse() throws CommandSyntaxException {
+ // CraftBukkit start
+ return parse(false);
+ }
+
+ public EntitySelector parse(boolean overridePermissions) throws CommandSyntaxException {
+ // CraftBukkit end
this.startPosition = this.reader.getCursor();
this.suggestions = this::suggestNameOrSelector;
if (this.reader.canRead() && this.reader.peek() == '@') {
@@ -471,7 +479,7 @@
}
this.reader.skip();
- this.parseSelector();
+ this.parseSelector(overridePermissions); // CraftBukkit
} else {
this.parseNameOrUUID();
}

View file

@ -0,0 +1,234 @@
--- a/net/minecraft/core/cauldron/CauldronInteraction.java
+++ b/net/minecraft/core/cauldron/CauldronInteraction.java
@@ -33,6 +33,10 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.gameevent.GameEvent;
+// CraftBukkit start
+import org.bukkit.event.block.CauldronLevelChangeEvent;
+// CraftBukkit end
+
public interface CauldronInteraction {
Map<String, CauldronInteraction.InteractionMap> INTERACTIONS = new Object2ObjectArrayMap();
@@ -47,6 +53,8 @@
CauldronInteraction SHULKER_BOX;
CauldronInteraction BANNER;
CauldronInteraction DYED_ITEM;
+ */
+ // CraftBukkit end
static CauldronInteraction.InteractionMap newInteractionMap(String s) {
Object2ObjectOpenHashMap<Item, CauldronInteraction> object2objectopenhashmap = new Object2ObjectOpenHashMap();
@@ -70,15 +78,20 @@
if (PotionUtils.getPotion(itemstack) != Potions.WATER) {
return InteractionResult.PASS;
} else {
- if (!level.isClientSide) {
+ if (!world.isClientSide) {
+ // CraftBukkit start
+ if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, Blocks.WATER_CAULDRON.defaultBlockState(), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) {
+ return InteractionResult.SUCCESS;
+ }
+ // CraftBukkit end
Item item = itemstack.getItem();
- player.setItemInHand(interactionhand, ItemUtils.createFilledResult(itemstack, player, new ItemStack(Items.GLASS_BOTTLE)));
- player.awardStat(Stats.USE_CAULDRON);
- player.awardStat(Stats.ITEM_USED.get(item));
- level.setBlockAndUpdate(blockpos, Blocks.WATER_CAULDRON.defaultBlockState());
- level.playSound((Player) null, blockpos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
- level.gameEvent((Entity) null, GameEvent.FLUID_PLACE, blockpos);
+ entityhuman.setItemInHand(enumhand, ItemUtils.createFilledResult(itemstack, entityhuman, new ItemStack(Items.GLASS_BOTTLE)));
+ entityhuman.awardStat(Stats.USE_CAULDRON);
+ entityhuman.awardStat(Stats.ITEM_USED.get(item));
+ // world.setBlockAndUpdate(blockposition, Blocks.WATER_CAULDRON.defaultBlockState()); // CraftBukkit
+ world.playSound((Player) null, blockposition, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
+ world.gameEvent((Entity) null, GameEvent.FLUID_PLACE, blockposition);
}
return InteractionResult.sidedSuccess(level.isClientSide);
@@ -92,29 +105,39 @@
return (Integer) blockstate1.getValue(LayeredCauldronBlock.LEVEL) == 3;
}, SoundEvents.BUCKET_FILL);
});
- map1.put(Items.GLASS_BOTTLE, (blockstate, level, blockpos, player, interactionhand, itemstack) -> {
- if (!level.isClientSide) {
+ map1.put(Items.GLASS_BOTTLE, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+ if (!world.isClientSide) {
+ // CraftBukkit start
+ if (!LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition, entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_FILL)) {
+ return InteractionResult.SUCCESS;
+ }
+ // CraftBukkit end
Item item = itemstack.getItem();
- player.setItemInHand(interactionhand, ItemUtils.createFilledResult(itemstack, player, PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER)));
- player.awardStat(Stats.USE_CAULDRON);
- player.awardStat(Stats.ITEM_USED.get(item));
- LayeredCauldronBlock.lowerFillLevel(blockstate, level, blockpos);
- level.playSound((Player) null, blockpos, SoundEvents.BOTTLE_FILL, SoundSource.BLOCKS, 1.0F, 1.0F);
- level.gameEvent((Entity) null, GameEvent.FLUID_PICKUP, blockpos);
+ entityhuman.setItemInHand(enumhand, ItemUtils.createFilledResult(itemstack, entityhuman, PotionUtils.setPotion(new ItemStack(Items.POTION), Potions.WATER)));
+ entityhuman.awardStat(Stats.USE_CAULDRON);
+ entityhuman.awardStat(Stats.ITEM_USED.get(item));
+ // LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition); // CraftBukkit
+ world.playSound((Player) null, blockposition, SoundEvents.BOTTLE_FILL, SoundSource.BLOCKS, 1.0F, 1.0F);
+ world.gameEvent((Entity) null, GameEvent.FLUID_PICKUP, blockposition);
}
return InteractionResult.sidedSuccess(level.isClientSide);
});
- map1.put(Items.POTION, (blockstate, level, blockpos, player, interactionhand, itemstack) -> {
- if ((Integer) blockstate.getValue(LayeredCauldronBlock.LEVEL) != 3 && PotionUtils.getPotion(itemstack) == Potions.WATER) {
- if (!level.isClientSide) {
- player.setItemInHand(interactionhand, ItemUtils.createFilledResult(itemstack, player, new ItemStack(Items.GLASS_BOTTLE)));
- player.awardStat(Stats.USE_CAULDRON);
- player.awardStat(Stats.ITEM_USED.get(itemstack.getItem()));
- level.setBlockAndUpdate(blockpos, (BlockState) blockstate.cycle(LayeredCauldronBlock.LEVEL));
- level.playSound((Player) null, blockpos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
- level.gameEvent((Entity) null, GameEvent.FLUID_PLACE, blockpos);
+ map1.put(Items.POTION, (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+ if ((Integer) iblockdata.getValue(LayeredCauldronBlock.LEVEL) != 3 && PotionUtils.getPotion(itemstack) == Potions.WATER) {
+ if (!world.isClientSide) {
+ // CraftBukkit start
+ if (!LayeredCauldronBlock.changeLevel(iblockdata, world, blockposition, iblockdata.cycle(LayeredCauldronBlock.LEVEL), entityhuman, CauldronLevelChangeEvent.ChangeReason.BOTTLE_EMPTY)) {
+ return InteractionResult.SUCCESS;
+ }
+ // CraftBukkit end
+ entityhuman.setItemInHand(enumhand, ItemUtils.createFilledResult(itemstack, entityhuman, new ItemStack(Items.GLASS_BOTTLE)));
+ entityhuman.awardStat(Stats.USE_CAULDRON);
+ entityhuman.awardStat(Stats.ITEM_USED.get(itemstack.getItem()));
+ // world.setBlockAndUpdate(blockposition, (IBlockData) iblockdata.cycle(LayeredCauldronBlock.LEVEL)); // CraftBukkit
+ world.playSound((Player) null, blockposition, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
+ world.gameEvent((Entity) null, GameEvent.FLUID_PLACE, blockposition);
}
return InteractionResult.sidedSuccess(level.isClientSide);
@@ -188,14 +211,19 @@
return InteractionResult.PASS;
} else {
if (!level.isClientSide) {
- Item item = itemstack.getItem();
+ // CraftBukkit start
+ if (!LayeredCauldronBlock.changeLevel(blockState, level, pos, Blocks.CAULDRON.defaultBlockState(), player, CauldronLevelChangeEvent.ChangeReason.BUCKET_FILL)) {
+ return InteractionResult.SUCCESS;
+ }
+ // CraftBukkit end
+ Item item = emptyStack.getItem();
player.setItemInHand(interactionhand, ItemUtils.createFilledResult(itemstack, player, itemstack1));
player.awardStat(Stats.USE_CAULDRON);
player.awardStat(Stats.ITEM_USED.get(item));
- level.setBlockAndUpdate(blockpos, Blocks.CAULDRON.defaultBlockState());
- level.playSound((Player) null, blockpos, soundevent, SoundSource.BLOCKS, 1.0F, 1.0F);
- level.gameEvent((Entity) null, GameEvent.FLUID_PICKUP, blockpos);
+ // world.setBlockAndUpdate(blockposition, Blocks.CAULDRON.defaultBlockState()); // CraftBukkit
+ level.playSound((Player) null, pos, fillSound, SoundSource.BLOCKS, 1.0F, 1.0F);
+ level.gameEvent((Entity) null, GameEvent.FLUID_PICKUP, pos);
}
return InteractionResult.sidedSuccess(level.isClientSide);
@@ -204,14 +232,19 @@
static InteractionResult emptyBucket(Level level, BlockPos blockpos, Player player, InteractionHand interactionhand, ItemStack itemstack, BlockState blockstate, SoundEvent soundevent) {
if (!level.isClientSide) {
- Item item = itemstack.getItem();
+ // CraftBukkit start
+ if (!LayeredCauldronBlock.changeLevel(state, level, pos, state, player, CauldronLevelChangeEvent.ChangeReason.BUCKET_EMPTY)) {
+ return InteractionResult.SUCCESS;
+ }
+ // CraftBukkit end
+ Item item = filledStack.getItem();
player.setItemInHand(interactionhand, ItemUtils.createFilledResult(itemstack, player, new ItemStack(Items.BUCKET)));
player.awardStat(Stats.FILL_CAULDRON);
player.awardStat(Stats.ITEM_USED.get(item));
- level.setBlockAndUpdate(blockpos, blockstate);
- level.playSound((Player) null, blockpos, soundevent, SoundSource.BLOCKS, 1.0F, 1.0F);
- level.gameEvent((Entity) null, GameEvent.FLUID_PLACE, blockpos);
+ // world.setBlockAndUpdate(blockposition, iblockdata); // CraftBukkit
+ level.playSound((Player) null, pos, emptySound, SoundSource.BLOCKS, 1.0F, 1.0F);
+ level.gameEvent((Entity) null, GameEvent.FLUID_PLACE, pos);
}
return InteractionResult.sidedSuccess(level.isClientSide);
@@ -236,22 +266,28 @@
FILL_POWDER_SNOW = (blockstate, level, blockpos, player, interactionhand, itemstack) -> {
return emptyBucket(level, blockpos, player, interactionhand, itemstack, (BlockState) Blocks.POWDER_SNOW_CAULDRON.defaultBlockState().setValue(LayeredCauldronBlock.LEVEL, 3), SoundEvents.BUCKET_EMPTY_POWDER_SNOW);
};
- SHULKER_BOX = (blockstate, level, blockpos, player, interactionhand, itemstack) -> {
+ CauldronInteraction SHULKER_BOX = (iblockdata, world, blockposition, entityhuman, enumhand, itemstack) -> {
+ // CraftBukkit end
Block block = Block.byItem(itemstack.getItem());
if (!(block instanceof ShulkerBoxBlock)) {
return InteractionResult.PASS;
} else {
- if (!level.isClientSide) {
+ if (!world.isClientSide) {
+ // CraftBukkit start
+ if (!LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition, entityhuman, CauldronLevelChangeEvent.ChangeReason.SHULKER_WASH)) {
+ return InteractionResult.SUCCESS;
+ }
+ // CraftBukkit end
ItemStack itemstack1 = new ItemStack(Blocks.SHULKER_BOX);
if (itemstack.hasTag()) {
itemstack1.setTag(itemstack.getTag().copy());
}
- player.setItemInHand(interactionhand, itemstack1);
- player.awardStat(Stats.CLEAN_SHULKER_BOX);
- LayeredCauldronBlock.lowerFillLevel(blockstate, level, blockpos);
+ entityhuman.setItemInHand(enumhand, itemstack1);
+ entityhuman.awardStat(Stats.CLEAN_SHULKER_BOX);
+ // LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition); // CraftBukkit
}
return InteractionResult.sidedSuccess(level.isClientSide);
@@ -261,7 +297,12 @@
if (BannerBlockEntity.getPatternCount(itemstack) <= 0) {
return InteractionResult.PASS;
} else {
- if (!level.isClientSide) {
+ if (!world.isClientSide) {
+ // CraftBukkit start
+ if (!LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition, entityhuman, CauldronLevelChangeEvent.ChangeReason.BANNER_WASH)) {
+ return InteractionResult.SUCCESS;
+ }
+ // CraftBukkit end
ItemStack itemstack1 = itemstack.copyWithCount(1);
BannerBlockEntity.removeLastPattern(itemstack1);
@@ -277,8 +318,8 @@
player.drop(itemstack1, false);
}
- player.awardStat(Stats.CLEAN_BANNER);
- LayeredCauldronBlock.lowerFillLevel(blockstate, level, blockpos);
+ entityhuman.awardStat(Stats.CLEAN_BANNER);
+ // LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition); // CraftBukkit
}
return InteractionResult.sidedSuccess(level.isClientSide);
@@ -295,10 +336,15 @@
if (!dyeableleatheritem.hasCustomColor(itemstack)) {
return InteractionResult.PASS;
} else {
- if (!level.isClientSide) {
- dyeableleatheritem.clearColor(itemstack);
- player.awardStat(Stats.CLEAN_ARMOR);
- LayeredCauldronBlock.lowerFillLevel(blockstate, level, blockpos);
+ if (!world.isClientSide) {
+ // CraftBukkit start
+ if (!LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition, entityhuman, CauldronLevelChangeEvent.ChangeReason.ARMOR_WASH)) {
+ return InteractionResult.SUCCESS;
+ }
+ // CraftBukkit end
+ idyeable.clearColor(itemstack);
+ entityhuman.awardStat(Stats.CLEAN_ARMOR);
+ // LayeredCauldronBlock.lowerFillLevel(iblockdata, world, blockposition); // CraftBukkit
}
return InteractionResult.sidedSuccess(level.isClientSide);

View file

@ -0,0 +1,58 @@
--- a/net/minecraft/core/dispenser/AbstractProjectileDispenseBehavior.java
+++ b/net/minecraft/core/dispenser/AbstractProjectileDispenseBehavior.java
@@ -7,6 +6,13 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.DispenserBlock;
+// CraftBukkit start
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.projectile.Projectile;
+import org.bukkit.craftbukkit.block.CraftBlock;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.event.block.BlockDispenseEvent;
+// CraftBukkit end
public abstract class AbstractProjectileDispenseBehavior extends DefaultDispenseItemBehavior {
@@ -20,9 +25,38 @@
Direction direction = (Direction) blocksource.state().getValue(DispenserBlock.FACING);
Projectile projectile = this.getProjectile(serverlevel, position, itemstack);
- projectile.shoot((double) direction.getStepX(), (double) ((float) direction.getStepY() + 0.1F), (double) direction.getStepZ(), this.getPower(), this.getUncertainty());
- serverlevel.addFreshEntity(projectile);
- itemstack.shrink(1);
+ // CraftBukkit start
+ // iprojectile.shoot((double) enumdirection.getStepX(), (double) ((float) enumdirection.getStepY() + 0.1F), (double) enumdirection.getStepZ(), this.getPower(), this.getUncertainty());
+ ItemStack itemstack1 = itemstack.split(1);
+ org.bukkit.block.Block block = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) enumdirection.getStepX(), (double) ((float) enumdirection.getStepY() + 0.1F), (double) enumdirection.getStepZ()));
+ if (!DispenserBlock.eventFired) {
+ worldserver.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ itemstack.grow(1);
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ itemstack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+
+ iprojectile.shoot(event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), this.getPower(), this.getUncertainty());
+ ((Entity) iprojectile).projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(sourceblock.blockEntity());
+ // CraftBukkit end
+ worldserver.addFreshEntity(iprojectile);
+ // itemstack.shrink(1); // CraftBukkit - Handled during event processing
return itemstack;
}

View file

@ -0,0 +1,61 @@
--- a/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
@@ -12,6 +12,11 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.DispenserBlock;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.craftbukkit.block.CraftBlock;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.event.block.BlockDispenseEvent;
+// CraftBukkit end
public class BoatDispenseItemBehavior extends DefaultDispenseItemBehavior {
@@ -52,13 +56,41 @@
d4 = 0.0D;
}
- Object object = this.isChestBoat ? new ChestBoat(serverlevel, d1, d2 + d4, d3) : new Boat(serverlevel, d1, d2 + d4, d3);
+ // Object object = this.isChestBoat ? new ChestBoat(worldserver, d1, d2 + d4, d3) : new EntityBoat(worldserver, d1, d2 + d4, d3);
+ // CraftBukkit start
+ ItemStack itemstack1 = itemstack.split(1);
+ org.bukkit.block.Block block = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
- EntityType.createDefaultStackConfig(serverlevel, itemstack, (Player) null).accept(object);
+ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d1, d2 + d4, d3));
+ if (!DispenserBlock.eventFired) {
+ worldserver.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ itemstack.grow(1);
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ itemstack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+
+ Boat object = this.isChestBoat ? new ChestBoat(worldserver, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ()) : new Boat(worldserver, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ());
+ // CraftBukkit end
+
+ EntityType.createDefaultStackConfig(worldserver, itemstack, (Player) null).accept(object);
((Boat) object).setVariant(this.type);
- ((Boat) object).setYRot(direction.toYRot());
- serverlevel.addFreshEntity((Entity) object);
- itemstack.shrink(1);
+ ((Boat) object).setYRot(enumdirection.toYRot());
+ if (!worldserver.addFreshEntity((Entity) object)) itemstack.grow(1); // CraftBukkit
+ // itemstack.shrink(1); // CraftBukkit - handled during event processing
return itemstack;
}

View file

@ -0,0 +1,113 @@
--- a/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
@@ -6,9 +6,23 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.DispenserBlock;
+// CraftBukkit start
+import org.bukkit.craftbukkit.block.CraftBlock;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.craftbukkit.util.CraftVector;
+import org.bukkit.event.block.BlockDispenseEvent;
+// CraftBukkit end
public class DefaultDispenseItemBehavior implements DispenseItemBehavior {
+ // CraftBukkit start
+ private boolean dropper;
+
+ public DefaultDispenseItemBehavior(boolean dropper) {
+ this.dropper = dropper;
+ }
+ // CraftBukkit end
+
public DefaultDispenseItemBehavior() {}
@Override
@@ -26,16 +39,27 @@
Position position = DispenserBlock.getDispensePosition(blocksource);
ItemStack itemstack1 = itemstack.split(1);
- spawnItem(blocksource.level(), itemstack1, 6, direction, position);
+ // CraftBukkit start
+ if (!spawnItem(sourceblock.level(), itemstack1, 6, enumdirection, sourceblock, dropper)) {
+ itemstack.grow(1);
+ }
+ // CraftBukkit end
return itemstack;
}
- public static void spawnItem(Level level, ItemStack itemstack, int i, Direction direction, Position position) {
- double d0 = position.x();
- double d1 = position.y();
- double d2 = position.z();
+ public static void spawnItem(Level level, ItemStack stack, int speed, Direction facing, IPosition position) {
+ // CraftBukkit start
+ ItemEntity entityitem = prepareItem(level, stack, speed, facing, position);
+ level.addFreshEntity(entityitem);
+ }
- if (direction.getAxis() == Direction.Axis.Y) {
+ private static ItemEntity prepareItem(Level world, ItemStack itemstack, int i, Direction enumdirection, IPosition iposition) {
+ // CraftBukkit end
+ double d0 = iposition.x();
+ double d1 = iposition.y();
+ double d2 = iposition.z();
+
+ if (enumdirection.getAxis() == Direction.Axis.Y) {
d1 -= 0.125D;
} else {
d1 -= 0.15625D;
@@ -44,12 +68,48 @@
ItemEntity itementity = new ItemEntity(level, d0, d1, d2, itemstack);
double d3 = level.random.nextDouble() * 0.1D + 0.2D;
- itementity.setDeltaMovement(level.random.triangle((double) direction.getStepX() * d3, 0.0172275D * (double) i), level.random.triangle(0.2D, 0.0172275D * (double) i), level.random.triangle((double) direction.getStepZ() * d3, 0.0172275D * (double) i));
- level.addFreshEntity(itementity);
+ entityitem.setDeltaMovement(world.random.triangle((double) enumdirection.getStepX() * d3, 0.0172275D * (double) i), world.random.triangle(0.2D, 0.0172275D * (double) i), world.random.triangle((double) enumdirection.getStepZ() * d3, 0.0172275D * (double) i));
+ // CraftBukkit start
+ return entityitem;
}
- protected void playSound(BlockSource blocksource) {
- blocksource.level().levelEvent(1000, blocksource.pos(), 0);
+ // CraftBukkit - void -> boolean return, IPosition -> ISourceBlock last argument, dropper
+ public static boolean spawnItem(Level world, ItemStack itemstack, int i, Direction enumdirection, SourceBlock sourceblock, boolean dropper) {
+ if (itemstack.isEmpty()) return true;
+ IPosition iposition = DispenserBlock.getDispensePosition(sourceblock);
+ ItemEntity entityitem = prepareItem(world, itemstack, i, enumdirection, iposition);
+
+ org.bukkit.block.Block block = CraftBlock.at(world, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
+
+ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), CraftVector.toBukkit(entityitem.getDeltaMovement()));
+ if (!DispenserBlock.eventFired) {
+ world.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ return false;
+ }
+
+ entityitem.setItem(CraftItemStack.asNMSCopy(event.getItem()));
+ entityitem.setDeltaMovement(CraftVector.toNMS(event.getVelocity()));
+
+ if (!dropper && !event.getItem().getType().equals(craftItem.getType())) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior.getClass() != DefaultDispenseItemBehavior.class) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ } else {
+ world.addFreshEntity(entityitem);
+ }
+ return false;
+ }
+
+ world.addFreshEntity(entityitem);
+
+ return true;
+ // CraftBukkit end
}
protected void playAnimation(BlockSource blocksource, Direction direction) {

View file

@ -0,0 +1,687 @@
--- a/net/minecraft/core/dispenser/DispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/DispenseItemBehavior.java
@@ -76,6 +79,17 @@
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import org.slf4j.Logger;
+import org.bukkit.Location;
+import org.bukkit.TreeType;
+import org.bukkit.craftbukkit.block.CraftBlock;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.craftbukkit.util.CraftLocation;
+import org.bukkit.craftbukkit.util.DummyGeneratorAccess;
+import org.bukkit.event.block.BlockDispenseArmorEvent;
+import org.bukkit.event.block.BlockDispenseEvent;
+import org.bukkit.event.block.BlockFertilizeEvent;
+import org.bukkit.event.world.StructureGrowEvent;
+// CraftBukkit end
public interface DispenseItemBehavior {
@@ -218,6 +215,33 @@
Direction direction = (Direction) blocksource.state().getValue(DispenserBlock.FACING);
EntityType entitytype = ((SpawnEggItem) itemstack.getItem()).getType(itemstack.getTag());
+ // CraftBukkit start
+ ServerLevel worldserver = sourceblock.level();
+ ItemStack itemstack1 = itemstack.split(1);
+ org.bukkit.block.Block block = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+ if (!DispenserBlock.eventFired) {
+ worldserver.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ itemstack.grow(1);
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ itemstack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+
try {
entitytype.spawn(blocksource.level(), itemstack, (Player) null, blocksource.pos().relative(direction), MobSpawnType.DISPENSER, direction != Direction.UP, false);
} catch (Exception exception) {
@@ -225,8 +249,9 @@
return ItemStack.EMPTY;
}
- itemstack.shrink(1);
- blocksource.level().gameEvent((Entity) null, GameEvent.ENTITY_PLACE, blocksource.pos());
+ // itemstack.shrink(1); // Handled during event processing
+ // CraftBukkit end
+ sourceblock.level().gameEvent((Entity) null, GameEvent.ENTITY_PLACE, sourceblock.pos());
return itemstack;
}
};
@@ -250,10 +270,42 @@
}, serverlevel, itemstack, (Player) null);
ArmorStand armorstand = (ArmorStand) EntityType.ARMOR_STAND.spawn(serverlevel, itemstack.getTag(), consumer, blockpos, MobSpawnType.DISPENSER, false, false);
- if (armorstand != null) {
- itemstack.shrink(1);
+ // CraftBukkit start
+ ItemStack itemstack1 = itemstack.split(1);
+ org.bukkit.block.Block block = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+ if (!DispenserBlock.eventFired) {
+ worldserver.getCraftServer().getPluginManager().callEvent(event);
}
+ if (event.isCancelled()) {
+ itemstack.grow(1);
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ itemstack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+ // CraftBukkit end
+
+ Consumer<ArmorStand> consumer = EntityType.appendDefaultStackConfig((entityarmorstand) -> {
+ entityarmorstand.setYRot(enumdirection.toYRot());
+ }, worldserver, itemstack, (Player) null);
+ ArmorStand entityarmorstand = (ArmorStand) EntityType.ARMOR_STAND.spawn(worldserver, itemstack.getTag(), consumer, blockposition, EnumMobSpawn.DISPENSER, false, false);
+
+ if (entityarmorstand != null) {
+ // itemstack.shrink(1); // CraftBukkit - Handled during event processing
+ }
+
return itemstack;
}
});
@@ -273,8 +324,35 @@
});
if (!list.isEmpty()) {
+ // CraftBukkit start
+ ItemStack itemstack1 = itemstack.split(1);
+ Level world = sourceblock.level();
+ org.bukkit.block.Block block = CraftBlock.at(world, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+ BlockDispenseArmorEvent event = new BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) list.get(0).getBukkitEntity());
+ if (!DispenserBlock.eventFired) {
+ world.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ itemstack.grow(1);
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ itemstack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != ArmorItem.DISPENSE_ITEM_BEHAVIOR) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+ // CraftBukkit end
((Saddleable) list.get(0)).equipSaddle(SoundSource.BLOCKS);
- itemstack.shrink(1);
+ // itemstack.shrink(1); // CraftBukkit - handled above
this.setSuccess(true);
return itemstack;
} else {
@@ -302,7 +379,35 @@
abstracthorse = (AbstractHorse) iterator1.next();
} while (!abstracthorse.isArmor(itemstack) || abstracthorse.isWearingArmor() || !abstracthorse.isTamed());
- abstracthorse.getSlot(401).set(itemstack.split(1));
+ // CraftBukkit start
+ ItemStack itemstack1 = itemstack.split(1);
+ Level world = sourceblock.level();
+ org.bukkit.block.Block block = CraftBlock.at(world, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+ BlockDispenseArmorEvent event = new BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) entityhorseabstract.getBukkitEntity());
+ if (!DispenserBlock.eventFired) {
+ world.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ itemstack.grow(1);
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ itemstack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != ArmorItem.DISPENSE_ITEM_BEHAVIOR) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+
+ entityhorseabstract.getSlot(401).set(CraftItemStack.asNMSCopy(event.getItem()));
+ // CraftBukkit end
this.setSuccess(true);
return itemstack;
}
@@ -345,25 +449,79 @@
return super.execute(blocksource, itemstack);
}
- abstractchestedhorse = (AbstractChestedHorse) iterator1.next();
- } while (!abstractchestedhorse.isTamed() || !abstractchestedhorse.getSlot(499).set(itemstack));
+ entityhorsechestedabstract = (AbstractChestedHorse) iterator1.next();
+ // CraftBukkit start
+ } while (!entityhorsechestedabstract.isTamed());
+ ItemStack itemstack1 = itemstack.split(1);
+ Level world = sourceblock.level();
+ org.bukkit.block.Block block = CraftBlock.at(world, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
- itemstack.shrink(1);
+ BlockDispenseArmorEvent event = new BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) entityhorsechestedabstract.getBukkitEntity());
+ if (!DispenserBlock.eventFired) {
+ world.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != ArmorItem.DISPENSE_ITEM_BEHAVIOR) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+ entityhorsechestedabstract.getSlot(499).set(CraftItemStack.asNMSCopy(event.getItem()));
+ // CraftBukkit end
+
+ // itemstack.shrink(1); // CraftBukkit - handled above
this.setSuccess(true);
return itemstack;
}
});
DispenserBlock.registerBehavior(Items.FIREWORK_ROCKET, new DefaultDispenseItemBehavior() {
@Override
- @Override
- public ItemStack execute(BlockSource blocksource, ItemStack itemstack) {
- Direction direction = (Direction) blocksource.state().getValue(DispenserBlock.FACING);
- Vec3 vec3 = DispenseItemBehavior.getEntityPokingOutOfBlockPos(blocksource, EntityType.FIREWORK_ROCKET, direction);
- FireworkRocketEntity fireworkrocketentity = new FireworkRocketEntity(blocksource.level(), itemstack, vec3.x(), vec3.y(), vec3.z(), true);
+ public ItemStack execute(SourceBlock sourceblock, ItemStack itemstack) {
+ Direction enumdirection = (Direction) sourceblock.state().getValue(DispenserBlock.FACING);
+ // CraftBukkit start
+ ServerLevel worldserver = sourceblock.level();
+ ItemStack itemstack1 = itemstack.split(1);
+ org.bukkit.block.Block block = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
- fireworkrocketentity.shoot((double) direction.getStepX(), (double) direction.getStepY(), (double) direction.getStepZ(), 0.5F, 1.0F);
- blocksource.level().addFreshEntity(fireworkrocketentity);
- itemstack.shrink(1);
+ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(enumdirection.getStepX(), enumdirection.getStepY(), enumdirection.getStepZ()));
+ if (!DispenserBlock.eventFired) {
+ worldserver.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ itemstack.grow(1);
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ itemstack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+
+ itemstack1 = CraftItemStack.asNMSCopy(event.getItem());
+ Vec3 vec3d = DispenseItemBehavior.getEntityPokingOutOfBlockPos(sourceblock, EntityType.FIREWORK_ROCKET, enumdirection);
+ FireworkRocketEntity entityfireworks = new FireworkRocketEntity(sourceblock.level(), itemstack, vec3d.x(), vec3d.y(), vec3d.z(), true);
+
+ entityfireworks.shoot((double) enumdirection.getStepX(), (double) enumdirection.getStepY(), (double) enumdirection.getStepZ(), 0.5F, 1.0F);
+ sourceblock.level().addFreshEntity(entityfireworks);
+ // itemstack.shrink(1); // Handled during event processing
+ // CraftBukkit end
return itemstack;
}
@@ -389,10 +544,39 @@
double d5 = randomsource.triangle((double) direction.getStepZ(), 0.11485000000000001D);
SmallFireball smallfireball = new SmallFireball(serverlevel, d0, d1, d2, d3, d4, d5);
- serverlevel.addFreshEntity((Entity) Util.make(smallfireball, (smallfireball1) -> {
- smallfireball1.setItem(itemstack);
- }));
- itemstack.shrink(1);
+ // CraftBukkit start
+ ItemStack itemstack1 = itemstack.split(1);
+ org.bukkit.block.Block block = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d3, d4, d5));
+ if (!DispenserBlock.eventFired) {
+ worldserver.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ itemstack.grow(1);
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ itemstack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+
+ SmallFireball entitysmallfireball = new SmallFireball(worldserver, d0, d1, d2, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ());
+ entitysmallfireball.setItem(itemstack1);
+ entitysmallfireball.projectileSource = new org.bukkit.craftbukkit.projectiles.CraftBlockProjectileSource(sourceblock.blockEntity());
+
+ worldserver.addFreshEntity(entitysmallfireball);
+ // itemstack.shrink(1); // Handled during event processing
+ // CraftBukkit end
return itemstack;
}
@@ -430,9 +612,51 @@
BlockPos blockpos = blocksource.pos().relative((Direction) blocksource.state().getValue(DispenserBlock.FACING));
ServerLevel serverlevel = blocksource.level();
- if (dispensiblecontaineritem.emptyContents((Player) null, serverlevel, blockpos, (BlockHitResult) null)) {
- dispensiblecontaineritem.checkExtraContent((Player) null, serverlevel, itemstack, blockpos);
- return new ItemStack(Items.BUCKET);
+ // CraftBukkit start
+ int x = blockposition.getX();
+ int y = blockposition.getY();
+ int z = blockposition.getZ();
+ IBlockData iblockdata = worldserver.getBlockState(blockposition);
+ if (iblockdata.isAir() || iblockdata.canBeReplaced() || (dispensiblecontaineritem instanceof BucketItem && iblockdata.getBlock() instanceof LiquidBlockContainer && ((LiquidBlockContainer) iblockdata.getBlock()).canPlaceLiquid((Player) null, worldserver, blockposition, iblockdata, ((BucketItem) dispensiblecontaineritem).content))) {
+ org.bukkit.block.Block block = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
+
+ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(x, y, z));
+ if (!DispenserBlock.eventFired) {
+ worldserver.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+
+ dispensiblecontaineritem = (DispensibleContainerItem) CraftItemStack.asNMSCopy(event.getItem()).getItem();
+ }
+ // CraftBukkit end
+
+ if (dispensiblecontaineritem.emptyContents((Player) null, worldserver, blockposition, (BlockHitResult) null)) {
+ dispensiblecontaineritem.checkExtraContent((Player) null, worldserver, itemstack, blockposition);
+ // CraftBukkit start - Handle stacked buckets
+ Item item = Items.BUCKET;
+ itemstack.shrink(1);
+ if (itemstack.isEmpty()) {
+ itemstack.setItem(Items.BUCKET);
+ itemstack.setCount(1);
+ } else if (sourceblock.blockEntity().addItem(new ItemStack(item)) < 0) {
+ this.defaultDispenseItemBehavior.dispense(sourceblock, new ItemStack(item));
+ }
+ return itemstack;
+ // CraftBukkit end
} else {
return this.defaultDispenseItemBehavior.dispense(blocksource, itemstack);
}
@@ -460,8 +683,8 @@
Block block = blockstate.getBlock();
if (block instanceof BucketPickup) {
- BucketPickup bucketpickup = (BucketPickup) block;
- ItemStack itemstack1 = bucketpickup.pickupBlock((Player) null, serverlevel, blockpos, blockstate);
+ BucketPickup ifluidsource = (BucketPickup) block;
+ ItemStack itemstack1 = ifluidsource.pickupBlock((Player) null, DummyGeneratorAccess.INSTANCE, blockposition, iblockdata); // CraftBukkit
if (itemstack1.isEmpty()) {
return super.execute(blocksource, itemstack);
@@ -469,6 +692,32 @@
serverlevel.gameEvent((Entity) null, GameEvent.FLUID_PICKUP, blockpos);
Item item = itemstack1.getItem();
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
+
+ BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
+ if (!DispenserBlock.eventFired) {
+ worldserver.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+
+ itemstack1 = ifluidsource.pickupBlock((Player) null, worldserver, blockposition, iblockdata); // From above
+ // CraftBukkit end
+
itemstack.shrink(1);
if (itemstack.isEmpty()) {
return new ItemStack(item);
@@ -491,18 +739,46 @@
protected ItemStack execute(BlockSource blocksource, ItemStack itemstack) {
ServerLevel serverlevel = blocksource.level();
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
+
+ BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+ if (!DispenserBlock.eventFired) {
+ worldserver.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+ // CraftBukkit end
+
this.setSuccess(true);
Direction direction = (Direction) blocksource.state().getValue(DispenserBlock.FACING);
BlockPos blockpos = blocksource.pos().relative(direction);
BlockState blockstate = serverlevel.getBlockState(blockpos);
- if (BaseFireBlock.canBePlacedAt(serverlevel, blockpos, direction)) {
- serverlevel.setBlockAndUpdate(blockpos, BaseFireBlock.getState(serverlevel, blockpos));
- serverlevel.gameEvent((Entity) null, GameEvent.BLOCK_PLACE, blockpos);
- } else if (!CampfireBlock.canLight(blockstate) && !CandleBlock.canLight(blockstate) && !CandleCakeBlock.canLight(blockstate)) {
- if (blockstate.getBlock() instanceof TntBlock) {
- TntBlock.explode(serverlevel, blockpos);
- serverlevel.removeBlock(blockpos, false);
+ if (BaseFireBlock.canBePlacedAt(worldserver, blockposition, enumdirection)) {
+ // CraftBukkit start - Ignition by dispensing flint and steel
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(worldserver, blockposition, sourceblock.pos()).isCancelled()) {
+ worldserver.setBlockAndUpdate(blockposition, BaseFireBlock.getState(worldserver, blockposition));
+ worldserver.gameEvent((Entity) null, GameEvent.BLOCK_PLACE, blockposition);
+ }
+ // CraftBukkit end
+ } else if (!CampfireBlock.canLight(iblockdata) && !CandleBlock.canLight(iblockdata) && !CandleCakeBlock.canLight(iblockdata)) {
+ if (iblockdata.getBlock() instanceof TntBlock && org.bukkit.craftbukkit.event.CraftEventFactory.callTNTPrimeEvent(worldserver, blockposition, org.bukkit.event.block.TNTPrimeEvent.PrimeCause.DISPENSER, null, sourceblock.pos())) { // CraftBukkit - TNTPrimeEvent
+ TntBlock.explode(worldserver, blockposition);
+ worldserver.removeBlock(blockposition, false);
} else {
this.setSuccess(false);
}
@@ -523,30 +798,108 @@
@Override
protected ItemStack execute(BlockSource blocksource, ItemStack itemstack) {
this.setSuccess(true);
- ServerLevel serverlevel = blocksource.level();
- BlockPos blockpos = blocksource.pos().relative((Direction) blocksource.state().getValue(DispenserBlock.FACING));
+ ServerLevel worldserver = sourceblock.level();
+ BlockPos blockposition = sourceblock.pos().relative((Direction) sourceblock.state().getValue(DispenserBlock.FACING));
+ // CraftBukkit start
+ org.bukkit.block.Block block = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
- if (!BoneMealItem.growCrop(itemstack, serverlevel, blockpos) && !BoneMealItem.growWaterPlant(itemstack, serverlevel, blockpos, (Direction) null)) {
+ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
+ if (!DispenserBlock.eventFired) {
+ worldserver.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+
+ worldserver.captureTreeGeneration = true;
+ // CraftBukkit end
+
+ if (!BoneMealItem.growCrop(itemstack, worldserver, blockposition) && !BoneMealItem.growWaterPlant(itemstack, worldserver, blockposition, (Direction) null)) {
this.setSuccess(false);
} else if (!serverlevel.isClientSide) {
serverlevel.levelEvent(1505, blockpos, 0);
}
+ // CraftBukkit start
+ worldserver.captureTreeGeneration = false;
+ if (worldserver.capturedBlockStates.size() > 0) {
+ TreeType treeType = SaplingBlock.treeType;
+ SaplingBlock.treeType = null;
+ Location location = CraftLocation.toBukkit(blockposition, worldserver.getWorld());
+ List<org.bukkit.block.BlockState> blocks = new java.util.ArrayList<>(worldserver.capturedBlockStates.values());
+ worldserver.capturedBlockStates.clear();
+ StructureGrowEvent structureEvent = null;
+ if (treeType != null) {
+ structureEvent = new StructureGrowEvent(location, treeType, false, null, blocks);
+ org.bukkit.Bukkit.getPluginManager().callEvent(structureEvent);
+ }
+ BlockFertilizeEvent fertilizeEvent = new BlockFertilizeEvent(location.getBlock(), null, blocks);
+ fertilizeEvent.setCancelled(structureEvent != null && structureEvent.isCancelled());
+ org.bukkit.Bukkit.getPluginManager().callEvent(fertilizeEvent);
+
+ if (!fertilizeEvent.isCancelled()) {
+ for (org.bukkit.block.BlockState blockstate : blocks) {
+ blockstate.update(true);
+ }
+ }
+ }
+ // CraftBukkit end
+
return itemstack;
}
});
DispenserBlock.registerBehavior(Blocks.TNT, new DefaultDispenseItemBehavior() {
@Override
- @Override
- protected ItemStack execute(BlockSource blocksource, ItemStack itemstack) {
- ServerLevel serverlevel = blocksource.level();
- BlockPos blockpos = blocksource.pos().relative((Direction) blocksource.state().getValue(DispenserBlock.FACING));
- PrimedTnt primedtnt = new PrimedTnt(serverlevel, (double) blockpos.getX() + 0.5D, (double) blockpos.getY(), (double) blockpos.getZ() + 0.5D, (LivingEntity) null);
+ protected ItemStack execute(SourceBlock sourceblock, ItemStack itemstack) {
+ ServerLevel worldserver = sourceblock.level();
+ BlockPos blockposition = sourceblock.pos().relative((Direction) sourceblock.state().getValue(DispenserBlock.FACING));
+ // CraftBukkit start
+ // EntityTNTPrimed entitytntprimed = new EntityTNTPrimed(worldserver, (double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D, (EntityLiving) null);
- serverlevel.addFreshEntity(primedtnt);
- serverlevel.playSound((Player) null, primedtnt.getX(), primedtnt.getY(), primedtnt.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F);
- serverlevel.gameEvent((Entity) null, GameEvent.ENTITY_PLACE, blockpos);
- itemstack.shrink(1);
+ ItemStack itemstack1 = itemstack.split(1);
+ org.bukkit.block.Block block = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
+
+ BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D));
+ if (!DispenserBlock.eventFired) {
+ worldserver.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ itemstack.grow(1);
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ itemstack.grow(1);
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+
+ PrimedTnt entitytntprimed = new PrimedTnt(worldserver, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), (LivingEntity) null);
+ // CraftBukkit end
+
+ worldserver.addFreshEntity(entitytntprimed);
+ worldserver.playSound((Player) null, entitytntprimed.getX(), entitytntprimed.getY(), entitytntprimed.getZ(), SoundEvents.TNT_PRIMED, SoundSource.BLOCKS, 1.0F, 1.0F);
+ worldserver.gameEvent((Entity) null, GameEvent.ENTITY_PLACE, blockposition);
+ // itemstack.shrink(1); // CraftBukkit - handled above
return itemstack;
}
});
@@ -573,14 +924,15 @@
Direction direction = (Direction) blocksource.state().getValue(DispenserBlock.FACING);
BlockPos blockpos = blocksource.pos().relative(direction);
- if (serverlevel.isEmptyBlock(blockpos) && WitherSkullBlock.canSpawnMob(serverlevel, blockpos, itemstack)) {
- serverlevel.setBlock(blockpos, (BlockState) Blocks.WITHER_SKELETON_SKULL.defaultBlockState().setValue(SkullBlock.ROTATION, RotationSegment.convertToSegment(direction)), 3);
- serverlevel.gameEvent((Entity) null, GameEvent.BLOCK_PLACE, blockpos);
- BlockEntity blockentity = serverlevel.getBlockEntity(blockpos);
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
if (blockentity instanceof SkullBlockEntity) {
WitherSkullBlock.checkSpawn(serverlevel, blockpos, (SkullBlockEntity) blockentity);
}
+ }
+ // CraftBukkit end
itemstack.shrink(1);
this.setSuccess(true);
@@ -599,11 +973,29 @@
BlockPos blockpos = blocksource.pos().relative((Direction) blocksource.state().getValue(DispenserBlock.FACING));
CarvedPumpkinBlock carvedpumpkinblock = (CarvedPumpkinBlock) Blocks.CARVED_PUMPKIN;
- if (serverlevel.isEmptyBlock(blockpos) && carvedpumpkinblock.canSpawnGolem(serverlevel, blockpos)) {
- if (!serverlevel.isClientSide) {
- serverlevel.setBlock(blockpos, carvedpumpkinblock.defaultBlockState(), 3);
- serverlevel.gameEvent((Entity) null, GameEvent.BLOCK_PLACE, blockpos);
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
+
+ BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
+ if (!DispenserBlock.eventFired) {
+ worldserver.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
}
+ }
+ // CraftBukkit end
itemstack.shrink(1);
this.setSuccess(true);
@@ -649,10 +1046,34 @@
BlockPos blockpos = blocksource.pos().relative((Direction) blocksource.state().getValue(DispenserBlock.FACING));
BlockState blockstate = serverlevel.getBlockState(blockpos);
- if (blockstate.is(BlockTags.BEEHIVES, (blockbehaviour_blockstatebase) -> {
- return blockbehaviour_blockstatebase.hasProperty(BeehiveBlock.HONEY_LEVEL) && blockbehaviour_blockstatebase.getBlock() instanceof BeehiveBlock;
- }) && (Integer) blockstate.getValue(BeehiveBlock.HONEY_LEVEL) >= 5) {
- ((BeehiveBlock) blockstate.getBlock()).releaseBeesAndResetHoneyLevel(serverlevel, blockstate, blockpos, (Player) null, BeehiveBlockEntity.BeeReleaseStatus.BEE_RELEASED);
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
+
+ BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
+ if (!DispenserBlock.eventFired) {
+ worldserver.getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+ // CraftBukkit end
+
+ if (iblockdata.is(BlockTags.BEEHIVES, (blockbase_blockdata) -> {
+ return blockbase_blockdata.hasProperty(BeehiveBlock.HONEY_LEVEL) && blockbase_blockdata.getBlock() instanceof BeehiveBlock;
+ }) && (Integer) iblockdata.getValue(BeehiveBlock.HONEY_LEVEL) >= 5) {
+ ((BeehiveBlock) iblockdata.getBlock()).releaseBeesAndResetHoneyLevel(worldserver, iblockdata, blockposition, (Player) null, BeehiveBlockEntity.ReleaseStatus.BEE_RELEASED);
this.setSuccess(true);
return this.takeLiquid(blocksource, itemstack, new ItemStack(Items.HONEY_BOTTLE));
} else if (serverlevel.getFluidState(blockpos).is(FluidTags.WATER)) {

View file

@ -0,0 +1,84 @@
--- a/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
@@ -21,21 +21,47 @@
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.phys.AABB;
+// CraftBukkit start
+import org.bukkit.craftbukkit.block.CraftBlock;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.event.block.BlockDispenseEvent;
+// CraftBukkit end
public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior {
public ShearsDispenseItemBehavior() {}
@Override
- @Override
- protected ItemStack execute(BlockSource blocksource, ItemStack itemstack) {
- ServerLevel serverlevel = blocksource.level();
+ protected ItemStack execute(SourceBlock sourceblock, ItemStack itemstack) {
+ ServerLevel worldserver = sourceblock.level();
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = CraftBlock.at(worldserver, sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
if (!serverlevel.isClientSide()) {
BlockPos blockpos = blocksource.pos().relative((Direction) blocksource.state().getValue(DispenserBlock.FACING));
- this.setSuccess(tryShearBeehive(serverlevel, blockpos) || tryShearLivingEntity(serverlevel, blockpos));
- if (this.isSuccess() && itemstack.hurt(1, serverlevel.getRandom(), (ServerPlayer) null)) {
+ if (event.isCancelled()) {
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+ // CraftBukkit end
+
+ if (!worldserver.isClientSide()) {
+ BlockPos blockposition = sourceblock.pos().relative((Direction) sourceblock.state().getValue(DispenserBlock.FACING));
+
+ this.setSuccess(tryShearBeehive(worldserver, blockposition) || tryShearLivingEntity(worldserver, blockposition, bukkitBlock, craftItem)); // CraftBukkit
+ if (this.isSuccess() && itemstack.hurt(1, worldserver.getRandom(), (ServerPlayer) null)) {
itemstack.setCount(0);
}
}
@@ -63,8 +91,8 @@
return false;
}
- private static boolean tryShearLivingEntity(ServerLevel serverlevel, BlockPos blockpos) {
- List<LivingEntity> list = serverlevel.getEntitiesOfClass(LivingEntity.class, new AABB(blockpos), EntitySelector.NO_SPECTATORS);
+ private static boolean tryShearLivingEntity(ServerLevel worldserver, BlockPos blockposition, org.bukkit.block.Block bukkitBlock, CraftItemStack craftItem) { // CraftBukkit - add args
+ List<LivingEntity> list = worldserver.getEntitiesOfClass(LivingEntity.class, new AABB(blockposition), EntitySelector.NO_SPECTATORS);
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
@@ -73,9 +101,14 @@
if (livingentity instanceof Shearable) {
Shearable shearable = (Shearable) livingentity;
- if (shearable.readyForShearing()) {
- shearable.shear(SoundSource.BLOCKS);
- serverlevel.gameEvent((Entity) null, GameEvent.SHEAR, blockpos);
+ if (ishearable.readyForShearing()) {
+ // CraftBukkit start
+ if (CraftEventFactory.callBlockShearEntityEvent(entityliving, bukkitBlock, craftItem).isCancelled()) {
+ continue;
+ }
+ // CraftBukkit end
+ ishearable.shear(SoundSource.BLOCKS);
+ worldserver.gameEvent((Entity) null, GameEvent.SHEAR, blockposition);
return true;
}
}

View file

@ -0,0 +1,46 @@
--- a/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
+++ b/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
@@ -10,6 +10,12 @@
import net.minecraft.world.level.block.DispenserBlock;
import org.slf4j.Logger;
+// CraftBukkit start
+import org.bukkit.craftbukkit.block.CraftBlock;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.event.block.BlockDispenseEvent;
+// CraftBukkit end
+
public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior {
private static final Logger LOGGER = LogUtils.getLogger();
@@ -27,6 +32,30 @@
BlockPos blockpos = blocksource.pos().relative(direction);
Direction direction1 = blocksource.level().isEmptyBlock(blockpos.below()) ? direction : Direction.UP;
+ // CraftBukkit start
+ org.bukkit.block.Block bukkitBlock = CraftBlock.at(sourceblock.level(), sourceblock.pos());
+ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack);
+
+ BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ()));
+ if (!DispenserBlock.eventFired) {
+ sourceblock.level().getCraftServer().getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ return itemstack;
+ }
+
+ if (!event.getItem().equals(craftItem)) {
+ // Chain to handler for new item
+ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
+ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
+ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
+ idispensebehavior.dispense(sourceblock, eventStack);
+ return itemstack;
+ }
+ }
+ // CraftBukkit end
+
try {
this.setSuccess(((BlockItem) item).place(new DirectionalPlaceContext(blocksource.level(), blockpos, direction, itemstack, direction1)).consumesAction());
} catch (Exception exception) {

View file

@ -0,0 +1,10 @@
--- a/net/minecraft/network/Connection.java
+++ b/net/minecraft/network/Connection.java
@@ -105,6 +105,7 @@
private volatile Component delayedDisconnect;
@Nullable
BandwidthDebugMonitor bandwidthDebugMonitor;
+ public String hostname = ""; // CraftBukkit - add field
public Connection(PacketFlow packetflow) {
this.receiving = packetflow;

View file

@ -0,0 +1,43 @@
--- a/net/minecraft/network/FriendlyByteBuf.java
+++ b/net/minecraft/network/FriendlyByteBuf.java
@@ -81,6 +81,8 @@
import org.joml.Quaternionf;
import org.joml.Vector3f;
+import org.bukkit.craftbukkit.inventory.CraftItemStack; // CraftBukkit
+
public class FriendlyByteBuf extends ByteBuf {
public static final int DEFAULT_NBT_QUOTA = 2097152;
@@ -584,7 +586,7 @@
try {
NbtIo.writeAnyTag((Tag) tag, new ByteBufOutputStream(this));
return this;
- } catch (IOException ioexception) {
+ } catch (Exception ioexception) { // CraftBukkit - IOException -> Exception
throw new EncoderException(ioexception);
}
}
@@ -611,8 +613,8 @@
}
}
- public FriendlyByteBuf writeItem(ItemStack itemstack) {
- if (itemstack.isEmpty()) {
+ public FriendlyByteBuf writeItem(ItemStack stack) {
+ if (stack.isEmpty() || stack.getItem() == null) { // CraftBukkit - NPE fix itemstack.getItem()
this.writeBoolean(false);
} else {
this.writeBoolean(true);
@@ -641,6 +643,11 @@
ItemStack itemstack = new ItemStack(item, b0);
itemstack.setTag(this.readNbt());
+ // CraftBukkit start
+ if (itemstack.getTag() != null) {
+ CraftItemStack.setItemMeta(itemstack, CraftItemStack.getItemMeta(itemstack));
+ }
+ // CraftBukkit end
return itemstack;
}
}

View file

@ -0,0 +1,27 @@
--- a/net/minecraft/network/chat/Component.java
+++ b/net/minecraft/network/chat/Component.java
@@ -34,9 +34,23 @@
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.FormattedCharSequence;
import net.minecraft.world.level.ChunkPos;
+// CraftBukkit start
+import java.util.stream.Stream;
+// CraftBukkit end
-public interface Component extends Message, FormattedText {
+public interface Component extends Message, FormattedText, Iterable<Component> { // CraftBukkit
+ // CraftBukkit start
+ default Stream<Component> stream() {
+ return com.google.common.collect.Streams.concat(new Stream[]{Stream.of(this), this.getSiblings().stream().flatMap(Component::stream)});
+ }
+
+ @Override
+ default Iterator<Component> iterator() {
+ return this.stream().iterator();
+ }
+ // CraftBukkit end
+
Style getStyle();
ComponentContents getContents();

View file

@ -0,0 +1,32 @@
--- a/net/minecraft/network/chat/TextColor.java
+++ b/net/minecraft/network/chat/TextColor.java
@@ -16,15 +16,18 @@
private static final String CUSTOM_COLOR_PREFIX = "#";
public static final Codec<TextColor> CODEC = Codec.STRING.comapFlatMap(TextColor::parseColor, TextColor::serialize);
- private static final Map<ChatFormatting, TextColor> LEGACY_FORMAT_TO_COLOR = (Map) Stream.of(ChatFormatting.values()).filter(ChatFormatting::isColor).collect(ImmutableMap.toImmutableMap(Function.identity(), (chatformatting) -> {
- return new TextColor(chatformatting.getColor(), chatformatting.getName());
+ private static final Map<ChatFormatting, TextColor> LEGACY_FORMAT_TO_COLOR = (Map) Stream.of(ChatFormatting.values()).filter(ChatFormatting::isColor).collect(ImmutableMap.toImmutableMap(Function.identity(), (enumchatformat) -> {
+ return new TextColor(enumchatformat.getColor(), enumchatformat.getName(), enumchatformat); // CraftBukkit
}));
private static final Map<String, TextColor> NAMED_COLORS = (Map) TextColor.LEGACY_FORMAT_TO_COLOR.values().stream().collect(ImmutableMap.toImmutableMap((textcolor) -> {
return textcolor.name;
}, Function.identity()));
private final int value;
@Nullable
- private final String name;
+ public final String name;
+ // CraftBukkit start
+ @Nullable
+ public final ChatFormatting format;
private TextColor(int i, String s) {
this.value = i & 16777215;
@@ -35,6 +40,7 @@
this.value = i & 16777215;
this.name = null;
}
+ // CraftBukkit end
public int getValue() {
return this.value;

View file

@ -0,0 +1,47 @@
--- a/net/minecraft/network/protocol/PacketUtils.java
+++ b/net/minecraft/network/protocol/PacketUtils.java
@@ -4,8 +4,14 @@
import net.minecraft.CrashReport;
import net.minecraft.ReportedException;
import net.minecraft.network.PacketListener;
-import net.minecraft.server.RunningOnDifferentThreadException;
+import net.minecraft.server.CancelledPacketHandleException;
+import org.slf4j.Logger;
+
+// CraftBukkit start
+import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.network.ServerCommonPacketListenerImpl;
+// CraftBukkit end
import net.minecraft.util.thread.BlockableEventLoop;
import org.slf4j.Logger;
@@ -19,10 +24,11 @@
ensureRunningOnSameThread(packet, t0, (BlockableEventLoop) serverlevel.getServer());
}
- public static <T extends PacketListener> void ensureRunningOnSameThread(Packet<T> packet, T t0, BlockableEventLoop<?> blockableeventloop) throws RunningOnDifferentThreadException {
- if (!blockableeventloop.isSameThread()) {
- blockableeventloop.executeIfPossible(() -> {
- if (t0.shouldHandleMessage(packet)) {
+ public static <T extends PacketListener> void ensureRunningOnSameThread(Packet<T> packet, T processor, BlockableEventLoop<?> executor) throws CancelledPacketHandleException {
+ if (!executor.isSameThread()) {
+ executor.executeIfPossible(() -> {
+ if (MinecraftServer.getServer().hasStopped() || (processor instanceof ServerCommonPacketListenerImpl && ((ServerCommonPacketListenerImpl) processor).processedDisconnect)) return; // CraftBukkit, MC-142590
+ if (processor.shouldHandleMessage(packet)) {
try {
packet.handle(t0);
} catch (Exception exception) {
@@ -59,7 +65,11 @@
}
});
- throw RunningOnDifferentThreadException.RUNNING_ON_DIFFERENT_THREAD;
+ throw CancelledPacketHandleException.RUNNING_ON_DIFFERENT_THREAD;
+ // CraftBukkit start - SPIGOT-5477, MC-142590
+ } else if (MinecraftServer.getServer().hasStopped() || (processor instanceof ServerCommonPacketListenerImpl && ((ServerCommonPacketListenerImpl) processor).processedDisconnect)) {
+ throw CancelledPacketHandleException.RUNNING_ON_DIFFERENT_THREAD;
+ // CraftBukkit end
}
}
}

View file

@ -0,0 +1,44 @@
--- a/net/minecraft/network/protocol/common/ServerboundCustomPayloadPacket.java
+++ b/net/minecraft/network/protocol/common/ServerboundCustomPayloadPacket.java
@@ -12,7 +12,7 @@
public record ServerboundCustomPayloadPacket(CustomPacketPayload payload) implements Packet<ServerCommonPacketListener> {
private static final int MAX_PAYLOAD_SIZE = 32767;
- private static final Map<ResourceLocation, FriendlyByteBuf.Reader<? extends CustomPacketPayload>> KNOWN_TYPES = ImmutableMap.builder().put(BrandPayload.ID, BrandPayload::new).build();
+ private static final Map<ResourceLocation, FriendlyByteBuf.a<? extends CustomPacketPayload>> KNOWN_TYPES = ImmutableMap.<ResourceLocation, FriendlyByteBuf.a<? extends CustomPacketPayload>>builder().build(); // CraftBukkit - no special handling
public ServerboundCustomPayloadPacket(FriendlyByteBuf friendlybytebuf) {
this(readPayload(friendlybytebuf.readResourceLocation(), friendlybytebuf));
@@ -24,12 +24,13 @@
return (CustomPacketPayload) (friendlybytebuf_reader != null ? (CustomPacketPayload) friendlybytebuf_reader.apply(friendlybytebuf) : readUnknownPayload(resourcelocation, friendlybytebuf));
}
- private static DiscardedPayload readUnknownPayload(ResourceLocation resourcelocation, FriendlyByteBuf friendlybytebuf) {
- int i = friendlybytebuf.readableBytes();
+ private static UnknownPayload readUnknownPayload(ResourceLocation minecraftkey, FriendlyByteBuf packetdataserializer) { // CraftBukkit
+ int i = packetdataserializer.readableBytes();
if (i >= 0 && i <= 32767) {
- friendlybytebuf.skipBytes(i);
- return new DiscardedPayload(resourcelocation);
+ // CraftBukkit start
+ return new UnknownPayload(minecraftkey, packetdataserializer.readBytes(i));
+ // CraftBukkit end
} else {
throw new IllegalArgumentException("Payload may not be larger than 32767 bytes");
}
@@ -46,4 +45,14 @@
public void handle(ServerCommonPacketListener servercommonpacketlistener) {
servercommonpacketlistener.handleCustomPayload(this);
}
+
+ // CraftBukkit start
+ public record UnknownPayload(ResourceLocation id, io.netty.buffer.ByteBuf data) implements CustomPacketPayload {
+
+ @Override
+ public void write(FriendlyByteBuf packetdataserializer) {
+ packetdataserializer.writeBytes(data);
+ }
+ }
+ // CraftBukkit end
}

View file

@ -0,0 +1,29 @@
--- a/net/minecraft/network/protocol/game/ClientboundInitializeBorderPacket.java
+++ b/net/minecraft/network/protocol/game/ClientboundInitializeBorderPacket.java
@@ -26,15 +26,17 @@
this.warningTime = friendlybytebuf.readVarInt();
}
- public ClientboundInitializeBorderPacket(WorldBorder worldborder) {
- this.newCenterX = worldborder.getCenterX();
- this.newCenterZ = worldborder.getCenterZ();
- this.oldSize = worldborder.getSize();
- this.newSize = worldborder.getLerpTarget();
- this.lerpTime = worldborder.getLerpRemainingTime();
- this.newAbsoluteMaxSize = worldborder.getAbsoluteMaxSize();
- this.warningBlocks = worldborder.getWarningBlocks();
- this.warningTime = worldborder.getWarningTime();
+ public ClientboundInitializeBorderPacket(WorldBorder worldBorder) {
+ // CraftBukkit start - multiply out nether border
+ this.newCenterX = worldBorder.getCenterX() * worldBorder.world.dimensionType().coordinateScale();
+ this.newCenterZ = worldBorder.getCenterZ() * worldBorder.world.dimensionType().coordinateScale();
+ // CraftBukkit end
+ this.oldSize = worldBorder.getSize();
+ this.newSize = worldBorder.getLerpTarget();
+ this.lerpTime = worldBorder.getLerpRemainingTime();
+ this.newAbsoluteMaxSize = worldBorder.getAbsoluteMaxSize();
+ this.warningBlocks = worldBorder.getWarningBlocks();
+ this.warningTime = worldBorder.getWarningTime();
}
@Override

View file

@ -0,0 +1,25 @@
--- a/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
+++ b/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
@@ -30,14 +30,18 @@
short short0 = (Short) shortiterator.next();
this.positions[j] = short0;
- this.states[j] = levelchunksection.getBlockState(SectionPos.sectionRelativeX(short0), SectionPos.sectionRelativeY(short0), SectionPos.sectionRelativeZ(short0));
+ this.states[j] = (section != null) ? section.getBlockState(SectionPos.sectionRelativeX(short0), SectionPos.sectionRelativeY(short0), SectionPos.sectionRelativeZ(short0)) : net.minecraft.world.level.block.Blocks.AIR.defaultBlockState(); // CraftBukkit - SPIGOT-6076, Mojang bug when empty chunk section notified
}
}
- public ClientboundSectionBlocksUpdatePacket(FriendlyByteBuf friendlybytebuf) {
- this.sectionPos = SectionPos.of(friendlybytebuf.readLong());
- int i = friendlybytebuf.readVarInt();
+ // CraftBukkit start - Add constructor
+ public ClientboundSectionBlocksUpdatePacket(SectionPos sectionposition, ShortSet shortset, IBlockData[] states) {
+ this.sectionPos = sectionposition;
+ this.positions = shortset.toShortArray();
+ this.states = states;
+ }
+ // CraftBukkit end
this.positions = new short[i];
this.states = new BlockState[i];

View file

@ -0,0 +1,17 @@
--- a/net/minecraft/network/protocol/game/ClientboundSetBorderCenterPacket.java
+++ b/net/minecraft/network/protocol/game/ClientboundSetBorderCenterPacket.java
@@ -9,9 +9,11 @@
private final double newCenterX;
private final double newCenterZ;
- public ClientboundSetBorderCenterPacket(WorldBorder worldborder) {
- this.newCenterX = worldborder.getCenterX();
- this.newCenterZ = worldborder.getCenterZ();
+ public ClientboundSetBorderCenterPacket(WorldBorder worldBorder) {
+ // CraftBukkit start - multiply out nether border
+ this.newCenterX = worldBorder.getCenterX() * (worldBorder.world != null ? worldBorder.world.dimensionType().coordinateScale() : 1.0);
+ this.newCenterZ = worldBorder.getCenterZ() * (worldBorder.world != null ? worldBorder.world.dimensionType().coordinateScale() : 1.0);
+ // CraftBukkit end
}
public ClientboundSetBorderCenterPacket(FriendlyByteBuf friendlybytebuf) {

View file

@ -0,0 +1,35 @@
--- a/net/minecraft/network/syncher/SynchedEntityData.java
+++ b/net/minecraft/network/syncher/SynchedEntityData.java
@@ -146,6 +148,13 @@
}
+ // CraftBukkit start - add method from above
+ public <T> void markDirty(EntityDataAccessor<T> datawatcherobject) {
+ this.getItem(datawatcherobject).setDirty(true);
+ this.isDirty = true;
+ }
+ // CraftBukkit end
+
public boolean isDirty() {
return this.isDirty;
}
@@ -235,6 +244,18 @@
return this.itemsById.isEmpty();
}
+ // CraftBukkit start
+ public void refresh(ServerPlayer to) {
+ if (!this.isEmpty()) {
+ List<SynchedEntityData.DataValue<?>> list = this.getNonDefaultValues();
+
+ if (list != null) {
+ to.connection.send(new ClientboundSetEntityDataPacket(this.entity.getId(), list));
+ }
+ }
+ }
+ // CraftBukkit end
+
public static class DataItem<T> {
final EntityDataAccessor<T> accessor;

View file

@ -0,0 +1,96 @@
--- a/net/minecraft/server/Bootstrap.java
+++ b/net/minecraft/server/Bootstrap.java
@@ -41,6 +44,23 @@
public static void bootStrap() {
if (!Bootstrap.isBootstrapped) {
+ // CraftBukkit start
+ String name = Bootstrap.class.getSimpleName();
+ switch (name) {
+ case "DispenserRegistry":
+ break;
+ case "Bootstrap":
+ System.err.println("***************************************************************************");
+ System.err.println("*** WARNING: This server jar may only be used for development purposes. ***");
+ System.err.println("***************************************************************************");
+ break;
+ default:
+ System.err.println("**********************************************************************");
+ System.err.println("*** WARNING: This server jar is unsupported, use at your own risk. ***");
+ System.err.println("**********************************************************************");
+ break;
+ }
+ // CraftBukkit end
Bootstrap.isBootstrapped = true;
Instant instant = Instant.now();
@@ -61,6 +81,69 @@
wrapStreams();
Bootstrap.bootstrapDuration.set(Duration.between(instant, Instant.now()).toMillis());
}
+ // CraftBukkit start - easier than fixing the decompile
+ BlockStateData.register(1008, "{Name:'minecraft:oak_sign',Properties:{rotation:'0'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'0'}}");
+ BlockStateData.register(1009, "{Name:'minecraft:oak_sign',Properties:{rotation:'1'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'1'}}");
+ BlockStateData.register(1010, "{Name:'minecraft:oak_sign',Properties:{rotation:'2'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'2'}}");
+ BlockStateData.register(1011, "{Name:'minecraft:oak_sign',Properties:{rotation:'3'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'3'}}");
+ BlockStateData.register(1012, "{Name:'minecraft:oak_sign',Properties:{rotation:'4'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'4'}}");
+ BlockStateData.register(1013, "{Name:'minecraft:oak_sign',Properties:{rotation:'5'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'5'}}");
+ BlockStateData.register(1014, "{Name:'minecraft:oak_sign',Properties:{rotation:'6'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'6'}}");
+ BlockStateData.register(1015, "{Name:'minecraft:oak_sign',Properties:{rotation:'7'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'7'}}");
+ BlockStateData.register(1016, "{Name:'minecraft:oak_sign',Properties:{rotation:'8'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'8'}}");
+ BlockStateData.register(1017, "{Name:'minecraft:oak_sign',Properties:{rotation:'9'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'9'}}");
+ BlockStateData.register(1018, "{Name:'minecraft:oak_sign',Properties:{rotation:'10'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'10'}}");
+ BlockStateData.register(1019, "{Name:'minecraft:oak_sign',Properties:{rotation:'11'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'11'}}");
+ BlockStateData.register(1020, "{Name:'minecraft:oak_sign',Properties:{rotation:'12'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'12'}}");
+ BlockStateData.register(1021, "{Name:'minecraft:oak_sign',Properties:{rotation:'13'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'13'}}");
+ BlockStateData.register(1022, "{Name:'minecraft:oak_sign',Properties:{rotation:'14'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'14'}}");
+ BlockStateData.register(1023, "{Name:'minecraft:oak_sign',Properties:{rotation:'15'}}", "{Name:'minecraft:standing_sign',Properties:{rotation:'15'}}");
+ ItemIdFix.ITEM_NAMES.put(323, "minecraft:oak_sign");
+
+ BlockStateData.register(1440, "{Name:\'minecraft:portal\',Properties:{axis:\'x\'}}", new String[]{"{Name:\'minecraft:portal\',Properties:{axis:\'x\'}}"});
+
+ ItemIdFix.ITEM_NAMES.put(409, "minecraft:prismarine_shard");
+ ItemIdFix.ITEM_NAMES.put(410, "minecraft:prismarine_crystals");
+ ItemIdFix.ITEM_NAMES.put(411, "minecraft:rabbit");
+ ItemIdFix.ITEM_NAMES.put(412, "minecraft:cooked_rabbit");
+ ItemIdFix.ITEM_NAMES.put(413, "minecraft:rabbit_stew");
+ ItemIdFix.ITEM_NAMES.put(414, "minecraft:rabbit_foot");
+ ItemIdFix.ITEM_NAMES.put(415, "minecraft:rabbit_hide");
+ ItemIdFix.ITEM_NAMES.put(416, "minecraft:armor_stand");
+
+ ItemIdFix.ITEM_NAMES.put(423, "minecraft:mutton");
+ ItemIdFix.ITEM_NAMES.put(424, "minecraft:cooked_mutton");
+ ItemIdFix.ITEM_NAMES.put(425, "minecraft:banner");
+ ItemIdFix.ITEM_NAMES.put(426, "minecraft:end_crystal");
+ ItemIdFix.ITEM_NAMES.put(427, "minecraft:spruce_door");
+ ItemIdFix.ITEM_NAMES.put(428, "minecraft:birch_door");
+ ItemIdFix.ITEM_NAMES.put(429, "minecraft:jungle_door");
+ ItemIdFix.ITEM_NAMES.put(430, "minecraft:acacia_door");
+ ItemIdFix.ITEM_NAMES.put(431, "minecraft:dark_oak_door");
+ ItemIdFix.ITEM_NAMES.put(432, "minecraft:chorus_fruit");
+ ItemIdFix.ITEM_NAMES.put(433, "minecraft:chorus_fruit_popped");
+ ItemIdFix.ITEM_NAMES.put(434, "minecraft:beetroot");
+ ItemIdFix.ITEM_NAMES.put(435, "minecraft:beetroot_seeds");
+ ItemIdFix.ITEM_NAMES.put(436, "minecraft:beetroot_soup");
+ ItemIdFix.ITEM_NAMES.put(437, "minecraft:dragon_breath");
+ ItemIdFix.ITEM_NAMES.put(438, "minecraft:splash_potion");
+ ItemIdFix.ITEM_NAMES.put(439, "minecraft:spectral_arrow");
+ ItemIdFix.ITEM_NAMES.put(440, "minecraft:tipped_arrow");
+ ItemIdFix.ITEM_NAMES.put(441, "minecraft:lingering_potion");
+ ItemIdFix.ITEM_NAMES.put(442, "minecraft:shield");
+ ItemIdFix.ITEM_NAMES.put(443, "minecraft:elytra");
+ ItemIdFix.ITEM_NAMES.put(444, "minecraft:spruce_boat");
+ ItemIdFix.ITEM_NAMES.put(445, "minecraft:birch_boat");
+ ItemIdFix.ITEM_NAMES.put(446, "minecraft:jungle_boat");
+ ItemIdFix.ITEM_NAMES.put(447, "minecraft:acacia_boat");
+ ItemIdFix.ITEM_NAMES.put(448, "minecraft:dark_oak_boat");
+ ItemIdFix.ITEM_NAMES.put(449, "minecraft:totem_of_undying");
+ ItemIdFix.ITEM_NAMES.put(450, "minecraft:shulker_shell");
+ ItemIdFix.ITEM_NAMES.put(452, "minecraft:iron_nugget");
+ ItemIdFix.ITEM_NAMES.put(453, "minecraft:knowledge_book");
+
+ ItemSpawnEggFix.ID_TO_ENTITY[23] = "Arrow";
+ // CraftBukkit end
}
}
}

View file

@ -0,0 +1,194 @@
--- a/net/minecraft/server/Main.java
+++ b/net/minecraft/server/Main.java
@@ -60,6 +60,14 @@
import net.minecraft.world.level.storage.WorldData;
import org.slf4j.Logger;
+// CraftBukkit start
+import com.google.common.base.Charsets;
+import java.io.InputStreamReader;
+import java.util.concurrent.atomic.AtomicReference;
+import net.minecraft.SharedConstants;
+import org.bukkit.configuration.file.YamlConfiguration;
+// CraftBukkit end
+
public class Main {
private static final Logger LOGGER = LogUtils.getLogger();
@@ -67,8 +75,9 @@
public Main() {}
@DontObfuscate
- public static void main(String[] astring) {
+ public static void main(final OptionSet optionset) { // CraftBukkit - replaces main(String[] astring)
SharedConstants.tryDetectVersion();
+ /* CraftBukkit start - Replace everything
OptionParser optionparser = new OptionParser();
OptionSpec<Void> optionspec = optionparser.accepts("nogui");
OptionSpec<Void> optionspec1 = optionparser.accepts("initSettings", "Initializes 'server.properties' and 'eula.txt', then quits");
@@ -93,15 +102,18 @@
optionparser.printHelpOn(System.err);
return;
}
+ */ // CraftBukkit end
Path path = (Path) optionset.valueOf(optionspec13);
+ Path path = (Path) optionset.valueOf("pidFile"); // CraftBukkit
+
if (path != null) {
writePidFile(path);
}
CrashReport.preload();
- if (optionset.has(optionspec12)) {
+ if (optionset.has("jfrProfile")) { // CraftBukkit
JvmProfiler.INSTANCE.start(Environment.SERVER);
}
@@ -109,13 +121,26 @@
Bootstrap.validate();
Util.startTimerHackThread();
Path path1 = Paths.get("server.properties");
- DedicatedServerSettings dedicatedserversettings = new DedicatedServerSettings(path1);
+ DedicatedServerSettings dedicatedserversettings = new DedicatedServerSettings(optionset); // CraftBukkit - CLI argument support
dedicatedserversettings.forceSave();
Path path2 = Paths.get("eula.txt");
Eula eula = new Eula(path2);
- if (optionset.has(optionspec1)) {
+ if (optionset.has("initSettings")) { // CraftBukkit
+ // CraftBukkit start - SPIGOT-5761: Create bukkit.yml and commands.yml if not present
+ File configFile = (File) optionset.valueOf("bukkit-settings");
+ YamlConfiguration configuration = YamlConfiguration.loadConfiguration(configFile);
+ configuration.options().copyDefaults(true);
+ configuration.setDefaults(YamlConfiguration.loadConfiguration(new InputStreamReader(Main.class.getClassLoader().getResourceAsStream("configurations/bukkit.yml"), Charsets.UTF_8)));
+ configuration.save(configFile);
+
+ File commandFile = (File) optionset.valueOf("commands-settings");
+ YamlConfiguration commandsConfiguration = YamlConfiguration.loadConfiguration(commandFile);
+ commandsConfiguration.options().copyDefaults(true);
+ commandsConfiguration.setDefaults(YamlConfiguration.loadConfiguration(new InputStreamReader(Main.class.getClassLoader().getResourceAsStream("configurations/commands.yml"), Charsets.UTF_8)));
+ commandsConfiguration.save(commandFile);
+ // CraftBukkit end
Main.LOGGER.info("Initialized '{}' and '{}'", path1.toAbsolutePath(), path2.toAbsolutePath());
return;
}
@@ -125,11 +150,13 @@
return;
}
- File file = new File((String) optionset.valueOf(optionspec8));
+ File file = (File) optionset.valueOf("universe"); // CraftBukkit
Services services = Services.create(new YggdrasilAuthenticationService(Proxy.NO_PROXY), file);
- String s = (String) Optional.ofNullable((String) optionset.valueOf(optionspec9)).orElse(dedicatedserversettings.getProperties().levelName);
- LevelStorageSource levelstoragesource = LevelStorageSource.createDefault(file.toPath());
- LevelStorageSource.LevelStorageAccess levelstoragesource_levelstorageaccess = levelstoragesource.validateAndCreateAccess(s);
+ // CraftBukkit start
+ String s = (String) Optional.ofNullable((String) optionset.valueOf("world")).orElse(dedicatedserversettings.getProperties().levelName);
+ LevelStorageSource convertable = LevelStorageSource.createDefault(file.toPath());
+ LevelStorageSource.LevelStorageAccess convertable_conversionsession = convertable.validateAndCreateAccess(s, LevelStem.OVERWORLD);
+ // CraftBukkit end
Dynamic dynamic;
if (levelstoragesource_levelstorageaccess.hasWorldData()) {
@@ -170,13 +197,31 @@
}
Dynamic<?> dynamic1 = dynamic;
- boolean flag = optionset.has(optionspec6);
+ boolean flag = optionset.has("safeMode"); // CraftBukkit
if (flag) {
Main.LOGGER.warn("Safe mode active, only vanilla datapack will be loaded");
}
- PackRepository packrepository = ServerPacksSource.createPackRepository(levelstoragesource_levelstorageaccess);
+ PackRepository resourcepackrepository = ServerPacksSource.createPackRepository(convertable_conversionsession);
+ // CraftBukkit start
+ File bukkitDataPackFolder = new File(convertable_conversionsession.getLevelPath(LevelResource.DATAPACK_DIR).toFile(), "bukkit");
+ if (!bukkitDataPackFolder.exists()) {
+ bukkitDataPackFolder.mkdirs();
+ }
+ File mcMeta = new File(bukkitDataPackFolder, "pack.mcmeta");
+ try {
+ com.google.common.io.Files.write("{\n"
+ + " \"pack\": {\n"
+ + " \"description\": \"Data pack for resources provided by Bukkit plugins\",\n"
+ + " \"pack_format\": " + SharedConstants.getCurrentVersion().getPackVersion(PackType.SERVER_DATA) + "\n"
+ + " }\n"
+ + "}\n", mcMeta, com.google.common.base.Charsets.UTF_8);
+ } catch (java.io.IOException ex) {
+ throw new RuntimeException("Could not initialize Bukkit datapack", ex);
+ }
+ AtomicReference<WorldLoader.a> worldLoader = new AtomicReference<>();
+ // CraftBukkit end
WorldStem worldstem;
@@ -184,8 +229,9 @@
WorldLoader.InitConfig worldloader_initconfig = loadOrCreateConfig(dedicatedserversettings.getProperties(), dynamic1, flag, packrepository);
worldstem = (WorldStem) Util.blockUntilDone((executor) -> {
- return WorldLoader.load(worldloader_initconfig, (worldloader_dataloadcontext) -> {
- Registry<LevelStem> registry = worldloader_dataloadcontext.datapackDimensions().registryOrThrow(Registries.LEVEL_STEM);
+ return WorldLoader.load(worldloader_c, (worldloader_a) -> {
+ worldLoader.set(worldloader_a); // CraftBukkit
+ Registry<LevelStem> iregistry = worldloader_a.datapackDimensions().registryOrThrow(Registries.LEVEL_STEM);
if (dynamic1 != null) {
LevelDataAndDimensions leveldataanddimensions = LevelStorageSource.getLevelDataAndDimensions(dynamic1, worldloader_dataloadcontext.dataConfiguration(), registry, worldloader_dataloadcontext.datapackWorldgen());
@@ -197,16 +243,16 @@
WorldOptions worldoptions;
WorldDimensions worlddimensions;
- if (optionset.has(optionspec2)) {
- levelsettings = MinecraftServer.DEMO_SETTINGS;
+ if (optionset.has("demo")) { // CraftBukkit
+ worldsettings = MinecraftServer.DEMO_SETTINGS;
worldoptions = WorldOptions.DEMO_OPTIONS;
worlddimensions = WorldPresets.createNormalWorldDimensions(worldloader_dataloadcontext.datapackWorldgen());
} else {
DedicatedServerProperties dedicatedserverproperties = dedicatedserversettings.getProperties();
- levelsettings = new LevelSettings(dedicatedserverproperties.levelName, dedicatedserverproperties.gamemode, dedicatedserverproperties.hardcore, dedicatedserverproperties.difficulty, false, new GameRules(), worldloader_dataloadcontext.dataConfiguration());
- worldoptions = optionset.has(optionspec3) ? dedicatedserverproperties.worldOptions.withBonusChest(true) : dedicatedserverproperties.worldOptions;
- worlddimensions = dedicatedserverproperties.createDimensions(worldloader_dataloadcontext.datapackWorldgen());
+ worldsettings = new LevelSettings(dedicatedserverproperties.levelName, dedicatedserverproperties.gamemode, dedicatedserverproperties.hardcore, dedicatedserverproperties.difficulty, false, new GameRules(), worldloader_a.dataConfiguration());
+ worldoptions = optionset.has("bonusChest") ? dedicatedserverproperties.worldOptions.withBonusChest(true) : dedicatedserverproperties.worldOptions; // CraftBukkit
+ worlddimensions = dedicatedserverproperties.createDimensions(worldloader_a.datapackWorldgen());
}
WorldDimensions.Complete worlddimensions_complete = worlddimensions.bake(registry);
@@ -246,6 +303,7 @@
return dedicatedserver1;
});
+ /* CraftBukkit start
Thread thread = new Thread("Server Shutdown Thread") {
@Override
public void run() {
@@ -255,6 +312,7 @@
thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(Main.LOGGER));
Runtime.getRuntime().addShutdownHook(thread);
+ */ // CraftBukkit end
} catch (Exception exception1) {
Main.LOGGER.error(LogUtils.FATAL_MARKER, "Failed to start the minecraft server", exception1);
}
@@ -290,10 +348,10 @@
return new WorldLoader.InitConfig(worldloader_packconfig, Commands.CommandSelection.DEDICATED, dedicatedserverproperties.functionPermissionLevel);
}
- private static void forceUpgrade(LevelStorageSource.LevelStorageAccess levelstoragesource_levelstorageaccess, DataFixer datafixer, boolean flag, BooleanSupplier booleansupplier, Registry<LevelStem> registry) {
- Main.LOGGER.info("Forcing world upgrade!");
- WorldUpgrader worldupgrader = new WorldUpgrader(levelstoragesource_levelstorageaccess, datafixer, registry, flag);
- Component component = null;
+ public static void forceUpgrade(LevelStorageSource.LevelStorageAccess levelStorage, DataFixer dataFixer, boolean eraseCache, BooleanSupplier upgradeWorld, Registry<LevelStem> dimesions) {
+ Main.LOGGER.info("Forcing world upgrade! {}", levelStorage.getLevelId()); // CraftBukkit
+ WorldUpgrader worldupgrader = new WorldUpgrader(levelStorage, dataFixer, dimesions, eraseCache);
+ Component ichatbasecomponent = null;
while (!worldupgrader.isFinished()) {
Component component1 = worldupgrader.getStatus();

View file

@ -0,0 +1,682 @@
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -151,6 +150,23 @@
import net.minecraft.world.level.levelgen.WorldOptions;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
+import net.minecraft.world.level.storage.WorldData;
+import net.minecraft.world.level.storage.loot.LootDataManager;
+import org.slf4j.Logger;
+
+// CraftBukkit start
+import com.mojang.serialization.Dynamic;
+import com.mojang.serialization.Lifecycle;
+import java.util.Random;
+import jline.console.ConsoleReader;
+import joptsimple.OptionSet;
+import net.minecraft.nbt.NbtException;
+import net.minecraft.nbt.ReportedNbtException;
+import net.minecraft.server.bossevents.CustomBossEvents;
+import net.minecraft.server.dedicated.DedicatedServer;
+import net.minecraft.server.dedicated.DedicatedServerProperties;
+import net.minecraft.world.level.levelgen.WorldDimensions;
+import net.minecraft.world.level.levelgen.presets.WorldPresets;
import net.minecraft.world.level.storage.CommandStorage;
import net.minecraft.world.level.storage.DerivedLevelData;
import net.minecraft.world.level.storage.DimensionDataStorage;
@@ -163,7 +180,11 @@
import net.minecraft.world.level.storage.loot.LootDataManager;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
-import org.slf4j.Logger;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.CraftServer;
+import org.bukkit.craftbukkit.Main;
+import org.bukkit.event.server.ServerLoadEvent;
+// CraftBukkit end
public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTask> implements ServerInfo, CommandSource, AutoCloseable {
@@ -171,7 +192,7 @@
public static final String VANILLA_BRAND = "vanilla";
private static final float AVERAGE_TICK_TIME_SMOOTHING = 0.8F;
private static final int TICK_STATS_SPAN = 100;
- private static final long OVERLOADED_THRESHOLD_NANOS = 20L * TimeUtil.NANOSECONDS_PER_SECOND / 20L;
+ private static final long OVERLOADED_THRESHOLD_NANOS = 30L * TimeUtil.NANOSECONDS_PER_SECOND / 20L; // CraftBukkit
private static final int OVERLOADED_TICKS_THRESHOLD = 20;
private static final long OVERLOADED_WARNING_INTERVAL_NANOS = 10L * TimeUtil.NANOSECONDS_PER_SECOND;
private static final int OVERLOADED_TICKS_WARNING_INTERVAL = 100;
@@ -254,7 +275,20 @@
protected final WorldData worldData;
private volatile boolean isSaving;
- public static <S extends MinecraftServer> S spin(Function<Thread, S> function) {
+ // CraftBukkit start
+ public final WorldLoader.a worldLoader;
+ public org.bukkit.craftbukkit.CraftServer server;
+ public OptionSet options;
+ public org.bukkit.command.ConsoleCommandSender console;
+ public ConsoleReader reader;
+ public static int currentTick = (int) (System.currentTimeMillis() / 50);
+ public java.util.Queue<Runnable> processQueue = new java.util.concurrent.ConcurrentLinkedQueue<Runnable>();
+ public int autosavePeriod;
+ public Commands vanillaCommandDispatcher;
+ private boolean forceTicks;
+ // CraftBukkit end
+
+ public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
AtomicReference<S> atomicreference = new AtomicReference();
Thread thread = new Thread(() -> {
((MinecraftServer) atomicreference.get()).runServer();
@@ -295,7 +329,7 @@
this.customBossEvents = new CustomBossEvents();
this.registries = worldstem.registries();
this.worldData = worldstem.worldData();
- if (!this.registries.compositeAccess().registryOrThrow(Registries.LEVEL_STEM).containsKey(LevelStem.OVERWORLD)) {
+ if (false && !this.registries.compositeAccess().registryOrThrow(Registries.LEVEL_STEM).containsKey(LevelStem.OVERWORLD)) { // CraftBukkit - initialised later
throw new IllegalStateException("Missing Overworld dimension data");
} else {
this.proxy = proxy;
@@ -319,6 +353,33 @@
this.serverThread = thread;
this.executor = Util.backgroundExecutor();
}
+ // CraftBukkit start
+ this.options = options;
+ this.worldLoader = worldLoader;
+ this.vanillaCommandDispatcher = worldstem.dataPackResources().commands; // CraftBukkit
+ // Try to see if we're actually running in a terminal, disable jline if not
+ if (System.console() == null && System.getProperty("jline.terminal") == null) {
+ System.setProperty("jline.terminal", "jline.UnsupportedTerminal");
+ Main.useJline = false;
+ }
+
+ try {
+ reader = new ConsoleReader(System.in, System.out);
+ reader.setExpandEvents(false); // Avoid parsing exceptions for uncommonly used event designators
+ } catch (Throwable e) {
+ try {
+ // Try again with jline disabled for Windows users without C++ 2008 Redistributable
+ System.setProperty("jline.terminal", "jline.UnsupportedTerminal");
+ System.setProperty("user.language", "en");
+ Main.useJline = false;
+ reader = new ConsoleReader(System.in, System.out);
+ reader.setExpandEvents(false);
+ } catch (IOException ex) {
+ LOGGER.warn((String) null, ex);
+ }
+ }
+ Runtime.getRuntime().addShutdownHook(new org.bukkit.craftbukkit.util.ServerShutdownThread(this));
+ // CraftBukkit end
}
private void readScoreboard(DimensionDataStorage dimensiondatastorage) {
@@ -327,7 +388,7 @@
protected abstract boolean initServer() throws IOException;
- protected void loadLevel() {
+ protected void loadLevel(String s) { // CraftBukkit
if (!JvmProfiler.INSTANCE.isRunning()) {
;
}
@@ -335,8 +396,7 @@
boolean flag = false;
ProfiledDuration profiledduration = JvmProfiler.INSTANCE.onWorldLoadedStarted();
- this.worldData.setModdedInfo(this.getServerModName(), this.getModdedStatus().shouldReportAsModified());
- ChunkProgressListener chunkprogresslistener = this.progressListenerFactory.create(11);
+ loadWorld0(s); // CraftBukkit
this.createLevels(chunkprogresslistener);
this.forceDifficulty();
@@ -357,16 +414,9 @@
protected void forceDifficulty() {}
- protected void createLevels(ChunkProgressListener chunkprogresslistener) {
- ServerLevelData serverleveldata = this.worldData.overworldData();
- boolean flag = this.worldData.isDebugWorld();
- Registry<LevelStem> registry = this.registries.compositeAccess().registryOrThrow(Registries.LEVEL_STEM);
- WorldOptions worldoptions = this.worldData.worldGenOptions();
- long i = worldoptions.seed();
- long j = BiomeManager.obfuscateSeed(i);
- List<CustomSpawner> list = ImmutableList.of(new PhantomSpawner(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(serverleveldata));
- LevelStem levelstem = (LevelStem) registry.get(LevelStem.OVERWORLD);
- ServerLevel serverlevel = new ServerLevel(this, this.executor, this.storageSource, serverleveldata, Level.OVERWORLD, levelstem, chunkprogresslistener, flag, j, list, true, (RandomSequences) null);
+ // CraftBukkit start
+ private void loadWorld0(String s) {
+ LevelStorageSource.LevelStorageAccess worldSession = this.storageSource;
this.levels.put(Level.OVERWORLD, serverlevel);
DimensionDataStorage dimensiondatastorage = serverlevel.getDataStorage();
@@ -375,7 +425,207 @@
this.commandStorage = new CommandStorage(dimensiondatastorage);
WorldBorder worldborder = serverlevel.getWorldBorder();
- if (!serverleveldata.isInitialized()) {
+ if (dimensionKey == LevelStem.NETHER) {
+ if (isNetherEnabled()) {
+ dimension = -1;
+ } else {
+ continue;
+ }
+ } else if (dimensionKey == LevelStem.END) {
+ if (server.getAllowEnd()) {
+ dimension = 1;
+ } else {
+ continue;
+ }
+ } else if (dimensionKey != LevelStem.OVERWORLD) {
+ dimension = -999;
+ }
+
+ String worldType = (dimension == -999) ? dimensionKey.location().getNamespace() + "_" + dimensionKey.location().getPath() : org.bukkit.World.Environment.getEnvironment(dimension).toString().toLowerCase();
+ String name = (dimensionKey == LevelStem.OVERWORLD) ? s : s + "_" + worldType;
+ if (dimension != 0) {
+ File newWorld = LevelStorageSource.getStorageFolder(new File(name).toPath(), dimensionKey).toFile();
+ File oldWorld = LevelStorageSource.getStorageFolder(new File(s).toPath(), dimensionKey).toFile();
+ File oldLevelDat = new File(new File(s), "level.dat"); // The data folders exist on first run as they are created in the PersistentCollection constructor above, but the level.dat won't
+
+ if (!newWorld.isDirectory() && oldWorld.isDirectory() && oldLevelDat.isFile()) {
+ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder required ----");
+ MinecraftServer.LOGGER.info("Unfortunately due to the way that Minecraft implemented multiworld support in 1.6, Bukkit requires that you move your " + worldType + " folder to a new location in order to operate correctly.");
+ MinecraftServer.LOGGER.info("We will move this folder for you, but it will mean that you need to move it back should you wish to stop using Bukkit in the future.");
+ MinecraftServer.LOGGER.info("Attempting to move " + oldWorld + " to " + newWorld + "...");
+
+ if (newWorld.exists()) {
+ MinecraftServer.LOGGER.warn("A file or folder already exists at " + newWorld + "!");
+ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder failed ----");
+ } else if (newWorld.getParentFile().mkdirs()) {
+ if (oldWorld.renameTo(newWorld)) {
+ MinecraftServer.LOGGER.info("Success! To restore " + worldType + " in the future, simply move " + newWorld + " to " + oldWorld);
+ // Migrate world data too.
+ try {
+ com.google.common.io.Files.copy(oldLevelDat, new File(new File(name), "level.dat"));
+ org.apache.commons.io.FileUtils.copyDirectory(new File(new File(s), "data"), new File(new File(name), "data"));
+ } catch (IOException exception) {
+ MinecraftServer.LOGGER.warn("Unable to migrate world data.");
+ }
+ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder complete ----");
+ } else {
+ MinecraftServer.LOGGER.warn("Could not move folder " + oldWorld + " to " + newWorld + "!");
+ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder failed ----");
+ }
+ } else {
+ MinecraftServer.LOGGER.warn("Could not create path for " + newWorld + "!");
+ MinecraftServer.LOGGER.info("---- Migration of old " + worldType + " folder failed ----");
+ }
+ }
+
+ try {
+ worldSession = LevelStorageSource.createDefault(server.getWorldContainer().toPath()).validateAndCreateAccess(name, dimensionKey);
+ } catch (IOException | ContentValidationException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ Dynamic<?> dynamic;
+ if (worldSession.hasWorldData()) {
+ LevelSummary worldinfo;
+
+ try {
+ dynamic = worldSession.getDataTag();
+ worldinfo = worldSession.getSummary(dynamic);
+ } catch (NbtException | ReportedNbtException | IOException ioexception) {
+ LevelStorageSource.LevelDirectory convertable_b = worldSession.getLevelDirectory();
+
+ MinecraftServer.LOGGER.warn("Failed to load world data from {}", convertable_b.dataFile(), ioexception);
+ MinecraftServer.LOGGER.info("Attempting to use fallback");
+
+ try {
+ dynamic = worldSession.getDataTagFallback();
+ worldinfo = worldSession.getSummary(dynamic);
+ } catch (NbtException | ReportedNbtException | IOException ioexception1) {
+ MinecraftServer.LOGGER.error("Failed to load world data from {}", convertable_b.oldDataFile(), ioexception1);
+ MinecraftServer.LOGGER.error("Failed to load world data from {} and {}. World files may be corrupted. Shutting down.", convertable_b.dataFile(), convertable_b.oldDataFile());
+ return;
+ }
+
+ worldSession.restoreLevelDataFromOld();
+ }
+
+ if (worldinfo.requiresManualConversion()) {
+ MinecraftServer.LOGGER.info("This world must be opened in an older version (like 1.6.4) to be safely converted");
+ return;
+ }
+
+ if (!worldinfo.isCompatible()) {
+ MinecraftServer.LOGGER.info("This world was created by an incompatible version.");
+ return;
+ }
+ } else {
+ dynamic = null;
+ }
+
+ org.bukkit.generator.ChunkGenerator gen = this.server.getGenerator(name);
+ org.bukkit.generator.BiomeProvider biomeProvider = this.server.getBiomeProvider(name);
+
+ PrimaryLevelData worlddata;
+ WorldLoader.a worldloader_a = this.worldLoader;
+ Registry<LevelStem> iregistry = worldloader_a.datapackDimensions().registryOrThrow(Registries.LEVEL_STEM);
+ if (dynamic != null) {
+ LevelDataAndDimensions leveldataanddimensions = LevelStorageSource.getLevelDataAndDimensions(dynamic, worldloader_a.dataConfiguration(), iregistry, worldloader_a.datapackWorldgen());
+
+ worlddata = (PrimaryLevelData) leveldataanddimensions.worldData();
+ } else {
+ LevelSettings worldsettings;
+ WorldOptions worldoptions;
+ WorldDimensions worlddimensions;
+
+ if (this.isDemo()) {
+ worldsettings = MinecraftServer.DEMO_SETTINGS;
+ worldoptions = WorldOptions.DEMO_OPTIONS;
+ worlddimensions = WorldPresets.createNormalWorldDimensions(worldloader_a.datapackWorldgen());
+ } else {
+ DedicatedServerProperties dedicatedserverproperties = ((DedicatedServer) this).getProperties();
+
+ worldsettings = new LevelSettings(dedicatedserverproperties.levelName, dedicatedserverproperties.gamemode, dedicatedserverproperties.hardcore, dedicatedserverproperties.difficulty, false, new GameRules(), worldloader_a.dataConfiguration());
+ worldoptions = options.has("bonusChest") ? dedicatedserverproperties.worldOptions.withBonusChest(true) : dedicatedserverproperties.worldOptions;
+ worlddimensions = dedicatedserverproperties.createDimensions(worldloader_a.datapackWorldgen());
+ }
+
+ WorldDimensions.b worlddimensions_b = worlddimensions.bake(iregistry);
+ Lifecycle lifecycle = worlddimensions_b.lifecycle().add(worldloader_a.datapackWorldgen().allRegistriesLifecycle());
+
+ worlddata = new PrimaryLevelData(worldsettings, worldoptions, worlddimensions_b.specialWorldProperty(), lifecycle);
+ }
+ worlddata.checkName(name); // CraftBukkit - Migration did not rewrite the level.dat; This forces 1.8 to take the last loaded world as respawn (in this case the end)
+ if (options.has("forceUpgrade")) {
+ net.minecraft.server.Main.forceUpgrade(worldSession, DataFixers.getDataFixer(), options.has("eraseCache"), () -> {
+ return true;
+ }, dimensions);
+ }
+
+ PrimaryLevelData iworlddataserver = worlddata;
+ boolean flag = worlddata.isDebugWorld();
+ WorldOptions worldoptions = worlddata.worldGenOptions();
+ long i = worldoptions.seed();
+ long j = BiomeManager.obfuscateSeed(i);
+ List<CustomSpawner> list = ImmutableList.of(new MobSpawnerPhantom(), new PatrolSpawner(), new CatSpawner(), new VillageSiege(), new WanderingTraderSpawner(iworlddataserver));
+ LevelStem worlddimension = (LevelStem) dimensions.get(dimensionKey);
+
+ org.bukkit.generator.WorldInfo worldInfo = new org.bukkit.craftbukkit.generator.CraftWorldInfo(iworlddataserver, worldSession, org.bukkit.World.Environment.getEnvironment(dimension), worlddimension.type().value());
+ if (biomeProvider == null && gen != null) {
+ biomeProvider = gen.getDefaultBiomeProvider(worldInfo);
+ }
+
+ ResourceKey<Level> worldKey = ResourceKey.create(Registries.DIMENSION, dimensionKey.location());
+
+ if (dimensionKey == LevelStem.OVERWORLD) {
+ this.worldData = worlddata;
+ this.worldData.setGameType(((DedicatedServer) this).getProperties().gamemode); // From DedicatedServer.init
+
+ ChunkProgressListener worldloadlistener = this.progressListenerFactory.create(11);
+
+ world = new ServerLevel(this, this.executor, worldSession, iworlddataserver, worldKey, worlddimension, worldloadlistener, flag, j, list, true, (RandomSequences) null, org.bukkit.World.Environment.getEnvironment(dimension), gen, biomeProvider);
+ DimensionDataStorage worldpersistentdata = world.getDataStorage();
+ this.readScoreboard(worldpersistentdata);
+ this.server.scoreboardManager = new org.bukkit.craftbukkit.scoreboard.CraftScoreboardManager(this, world.getScoreboard());
+ this.commandStorage = new CommandStorage(worldpersistentdata);
+ } else {
+ ChunkProgressListener worldloadlistener = this.progressListenerFactory.create(11);
+ world = new ServerLevel(this, this.executor, worldSession, iworlddataserver, worldKey, worlddimension, worldloadlistener, flag, j, ImmutableList.of(), true, this.overworld().getRandomSequences(), org.bukkit.World.Environment.getEnvironment(dimension), gen, biomeProvider);
+ }
+
+ worlddata.setModdedInfo(this.getServerModName(), this.getModdedStatus().shouldReportAsModified());
+ this.initWorld(world, worlddata, worldData, worldoptions);
+
+ this.addLevel(world);
+ this.getPlayerList().addWorldborderListener(world);
+
+ if (worlddata.getCustomBossEvents() != null) {
+ this.getCustomBossEvents().load(worlddata.getCustomBossEvents());
+ }
+ }
+ this.forceDifficulty();
+ for (ServerLevel worldserver : this.getAllLevels()) {
+ this.prepareLevels(worldserver.getChunkSource().chunkMap.progressListener, worldserver);
+ worldserver.entityManager.tick(); // SPIGOT-6526: Load pending entities so they are available to the API
+ this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldLoadEvent(worldserver.getWorld()));
+ }
+
+ this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD);
+ this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
+ this.connection.acceptConnections();
+ }
+
+ public void initWorld(ServerLevel worldserver, ServerLevelData iworlddataserver, WorldData saveData, WorldOptions worldoptions) {
+ boolean flag = saveData.isDebugWorld();
+ // CraftBukkit start
+ if (worldserver.generator != null) {
+ worldserver.getWorld().getPopulators().addAll(worldserver.generator.getDefaultPopulators(worldserver.getWorld()));
+ }
+ WorldBorder worldborder = worldserver.getWorldBorder();
+ worldborder.applySettings(iworlddataserver.getWorldBorder()); // CraftBukkit - move up so that WorldBorder is set during WorldInitEvent
+ this.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldInitEvent(worldserver.getWorld())); // CraftBukkit - SPIGOT-5569: Call WorldInitEvent before any chunks are generated
+
+ if (!iworlddataserver.isInitialized()) {
try {
setInitialSpawn(serverlevel, serverleveldata, worldoptions.generateBonusChest(), flag);
serverleveldata.setInitialized(true);
@@ -421,17 +648,30 @@
worldborder.applySettings(serverleveldata.getWorldBorder());
}
+ // CraftBukkit end
private static void setInitialSpawn(ServerLevel serverlevel, ServerLevelData serverleveldata, boolean flag, boolean flag1) {
if (flag1) {
serverleveldata.setSpawn(BlockPos.ZERO.above(80), 0.0F);
} else {
- ServerChunkCache serverchunkcache = serverlevel.getChunkSource();
- ChunkPos chunkpos = new ChunkPos(serverchunkcache.randomState().sampler().findSpawnPosition());
- int i = serverchunkcache.getGenerator().getSpawnHeight(serverlevel);
+ ServerChunkCache chunkproviderserver = level.getChunkSource();
+ ChunkPos chunkcoordintpair = new ChunkPos(chunkproviderserver.randomState().sampler().findSpawnPosition());
+ // CraftBukkit start
+ if (level.generator != null) {
+ Random rand = new Random(level.getSeed());
+ org.bukkit.Location spawn = level.generator.getFixedSpawnLocation(level.getWorld(), rand);
- if (i < serverlevel.getMinBuildHeight()) {
- BlockPos blockpos = chunkpos.getWorldPosition();
+ if (spawn != null) {
+ if (spawn.getWorld() != level.getWorld()) {
+ throw new IllegalStateException("Cannot set spawn point for " + levelData.getLevelName() + " to be in another world (" + spawn.getWorld().getName() + ")");
+ } else {
+ levelData.setSpawn(new BlockPos(spawn.getBlockX(), spawn.getBlockY(), spawn.getBlockZ()), spawn.getYaw());
+ return;
+ }
+ }
+ }
+ // CraftBukkit end
+ int i = chunkproviderserver.getGenerator().getSpawnHeight(level);
i = serverlevel.getHeight(Heightmap.Types.WORLD_SURFACE, blockpos.getX() + 8, blockpos.getZ() + 8);
}
@@ -487,8 +730,11 @@
serverleveldata.setGameType(GameType.SPECTATOR);
}
- private void prepareLevels(ChunkProgressListener chunkprogresslistener) {
- ServerLevel serverlevel = this.overworld();
+ // CraftBukkit start
+ public void prepareLevels(ChunkProgressListener worldloadlistener, ServerLevel worldserver) {
+ // WorldServer worldserver = this.overworld();
+ this.forceTicks = true;
+ // CraftBukkit end
MinecraftServer.LOGGER.info("Preparing start region for dimension {}", serverlevel.dimension().location());
BlockPos blockpos = serverlevel.getSharedSpawnPos();
@@ -497,7 +743,9 @@
ServerChunkCache serverchunkcache = serverlevel.getChunkSource();
this.nextTickTimeNanos = Util.getNanos();
- serverchunkcache.addRegionTicket(TicketType.START, new ChunkPos(blockpos), 11, Unit.INSTANCE);
+ // CraftBukkit start
+ if (worldserver.getWorld().getKeepSpawnInMemory()) {
+ chunkproviderserver.addRegionTicket(TicketType.START, new ChunkPos(blockposition), 11, Unit.INSTANCE);
while (serverchunkcache.getTickingGenerated() != 441) {
this.nextTickTimeNanos = Util.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS;
@@ -508,9 +757,10 @@
this.waitUntilNextTick();
Iterator iterator = this.levels.values().iterator();
- while (iterator.hasNext()) {
- ServerLevel serverlevel1 = (ServerLevel) iterator.next();
- ForcedChunksSavedData forcedchunkssaveddata = (ForcedChunksSavedData) serverlevel1.getDataStorage().get(ForcedChunksSavedData.factory(), "chunks");
+ if (true) {
+ ServerLevel worldserver1 = worldserver;
+ // CraftBukkit end
+ ForcedChunksSavedData forcedchunk = (ForcedChunksSavedData) worldserver1.getDataStorage().get(ForcedChunksSavedData.factory(), "chunks");
if (forcedchunkssaveddata != null) {
LongIterator longiterator = forcedchunkssaveddata.getChunks().iterator();
@@ -524,10 +774,17 @@
}
}
- this.nextTickTimeNanos = Util.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS;
- this.waitUntilNextTick();
- chunkprogresslistener.stop();
- this.updateMobSpawningFlags();
+ // CraftBukkit start
+ // this.nextTickTimeNanos = SystemUtils.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS;
+ this.executeModerately();
+ // CraftBukkit end
+ worldloadlistener.stop();
+ // CraftBukkit start
+ // this.updateMobSpawningFlags();
+ worldserver.setSpawnSettings(this.isSpawningMonsters(), this.isSpawningAnimals());
+
+ this.forceTicks = false;
+ // CraftBukkit end
}
public GameType getDefaultGameType() {
@@ -557,13 +814,17 @@
serverlevel.save((ProgressListener) null, flag1, serverlevel.noSave && !flag2);
}
- ServerLevel serverlevel1 = this.overworld();
- ServerLevelData serverleveldata = this.worldData.overworldData();
+ // CraftBukkit start - moved to WorldServer.save
+ /*
+ WorldServer worldserver1 = this.overworld();
+ IWorldDataServer iworlddataserver = this.worldData.overworldData();
serverleveldata.setWorldBorder(serverlevel1.getWorldBorder().createSettings());
this.worldData.setCustomBossEvents(this.getCustomBossEvents().save());
this.storageSource.saveDataTag(this.registryAccess(), this.worldData, this.getPlayerList().getSingleplayerData());
- if (flag1) {
+ */
+ // CraftBukkit end
+ if (flush) {
Iterator iterator1 = this.getAllLevels().iterator();
while (iterator1.hasNext()) {
@@ -598,18 +858,40 @@
this.stopServer();
}
+ // CraftBukkit start
+ private boolean hasStopped = false;
+ private final Object stopLock = new Object();
+ public final boolean hasStopped() {
+ synchronized (stopLock) {
+ return hasStopped;
+ }
+ }
+ // CraftBukkit end
+
public void stopServer() {
+ // CraftBukkit start - prevent double stopping on multiple threads
+ synchronized(stopLock) {
+ if (hasStopped) return;
+ hasStopped = true;
+ }
+ // CraftBukkit end
if (this.metricsRecorder.isRecording()) {
this.cancelRecordingMetrics();
}
MinecraftServer.LOGGER.info("Stopping server");
+ // CraftBukkit start
+ if (this.server != null) {
+ this.server.disablePlugins();
+ }
+ // CraftBukkit end
this.getConnection().stop();
this.isSaving = true;
if (this.playerList != null) {
MinecraftServer.LOGGER.info("Saving players");
this.playerList.saveAll();
this.playerList.removeAll();
+ try { Thread.sleep(100); } catch (InterruptedException ex) {} // CraftBukkit - SPIGOT-625 - give server at least a chance to send packets
}
MinecraftServer.LOGGER.info("Saving worlds");
@@ -714,6 +996,7 @@
if (j > MinecraftServer.OVERLOADED_THRESHOLD_NANOS + 20L * i && this.nextTickTimeNanos - this.lastOverloadWarningNanos >= MinecraftServer.OVERLOADED_WARNING_INTERVAL_NANOS + 100L * i) {
long k = j / i;
+ if (server.getWarnOnOverload()) // CraftBukkit
MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", j / TimeUtil.NANOSECONDS_PER_MILLISECOND, k);
this.nextTickTimeNanos += k * i;
this.lastOverloadWarningNanos = this.nextTickTimeNanos;
@@ -727,6 +1010,7 @@
this.debugCommandProfiler = new MinecraftServer.TimeProfiler(Util.getNanos(), this.tickCount);
}
+ MinecraftServer.currentTick = (int) (System.currentTimeMillis() / 50); // CraftBukkit
this.nextTickTimeNanos += i;
this.startMetricsRecordingTick();
this.profiler.push("tick");
@@ -771,6 +1055,12 @@
this.services.profileCache().clearExecutor();
}
+ // CraftBukkit start - Restore terminal to original settings
+ try {
+ reader.getTerminal().restore();
+ } catch (Exception ignored) {
+ }
+ // CraftBukkit end
this.onServerExit();
}
@@ -804,9 +1094,16 @@
}
private boolean haveTime() {
- return this.runningTask() || Util.getNanos() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTimeNanos : this.nextTickTimeNanos);
+ // CraftBukkit start
+ return this.forceTicks || this.runningTask() || Util.getNanos() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTimeNanos : this.nextTickTimeNanos);
}
+ private void executeModerately() {
+ this.runAllTasks();
+ java.util.concurrent.locks.LockSupport.parkNanos("executing tasks", 1000L);
+ // CraftBukkit end
+ }
+
protected void waitUntilNextTick() {
this.runAllTasks();
this.managedBlock(() -> {
@@ -914,8 +1207,10 @@
}
--this.ticksUntilAutosave;
- if (this.ticksUntilAutosave <= 0) {
- this.ticksUntilAutosave = this.computeNextAutosaveInterval();
+ // CraftBukkit start
+ if (this.autosavePeriod > 0 && this.ticksUntilAutosave <= 0) {
+ this.ticksUntilAutosave = this.autosavePeriod;
+ // CraftBukkit end
MinecraftServer.LOGGER.debug("Autosave started");
this.profiler.push("save");
this.saveEverything(true, false, false);
@@ -996,11 +1291,26 @@
this.getPlayerList().getPlayers().forEach((serverplayer) -> {
serverplayer.connection.suspendFlushing();
});
+ this.server.getScheduler().mainThreadHeartbeat(this.tickCount); // CraftBukkit
this.profiler.push("commandFunctions");
this.getFunctions().tick();
this.profiler.popPush("levels");
Iterator iterator = this.getAllLevels().iterator();
+ // CraftBukkit start
+ // Run tasks that are waiting on processing
+ while (!processQueue.isEmpty()) {
+ processQueue.remove().run();
+ }
+
+ // Send time updates to everyone, it will get the right time from the world the player is in.
+ if (this.tickCount % 20 == 0) {
+ for (int i = 0; i < this.getPlayerList().players.size(); ++i) {
+ ServerPlayer entityplayer = (ServerPlayer) this.getPlayerList().players.get(i);
+ entityplayer.connection.send(new ClientboundSetTimePacket(entityplayer.level().getGameTime(), entityplayer.getPlayerTime(), entityplayer.level().getGameRules().getBoolean(GameRules.RULE_DAYLIGHT))); // Add support for per player time
+ }
+ }
+
while (iterator.hasNext()) {
ServerLevel serverlevel = (ServerLevel) iterator.next();
@@ -1012,6 +1323,7 @@
this.synchronizeTime(serverlevel);
this.profiler.pop();
}
+ // CraftBukkit end */
this.profiler.push("tick");
@@ -1101,6 +1413,22 @@
return (ServerLevel) this.levels.get(resourcekey);
}
+ // CraftBukkit start
+ public void addLevel(ServerLevel level) {
+ Map<ResourceKey<Level>, ServerLevel> oldLevels = this.levels;
+ Map<ResourceKey<Level>, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels);
+ newLevels.put(level.dimension(), level);
+ this.levels = Collections.unmodifiableMap(newLevels);
+ }
+
+ public void removeLevel(ServerLevel level) {
+ Map<ResourceKey<Level>, ServerLevel> oldLevels = this.levels;
+ Map<ResourceKey<Level>, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels);
+ newLevels.remove(level.dimension());
+ this.levels = Collections.unmodifiableMap(newLevels);
+ }
+ // CraftBukkit end
+
public Set<ResourceKey<Level>> levelKeys() {
return this.levels.keySet();
}
@@ -1133,7 +1458,7 @@
@DontObfuscate
public String getServerModName() {
- return "vanilla";
+ return server.getName(); // CraftBukkit - cb > vanilla!
}
public SystemReport fillSystemReport(SystemReport systemreport) {
@@ -1920,6 +2237,22 @@
}
+ // CraftBukkit start
+ @Override
+ public boolean isSameThread() {
+ return super.isSameThread() || this.isStopped(); // CraftBukkit - MC-142590
+ }
+
+ public boolean isDebugging() {
+ return false;
+ }
+
+ @Deprecated
+ public static MinecraftServer getServer() {
+ return (Bukkit.getServer() instanceof CraftServer) ? ((CraftServer) Bukkit.getServer()).getServer() : null;
+ }
+ // CraftBukkit end
+
private void startMetricsRecordingTick() {
if (this.willStartRecordingMetrics) {
this.metricsRecorder = ActiveMetricsRecorder.createStarted(new ServerMetricsSamplersProvider(Util.timeSource, this.isDedicatedServer()), Util.timeSource, Util.ioPool(), new MetricsPersister("server"), this.onMetricsRecordingStopped, (path) -> {
@@ -2046,6 +2379,11 @@
}
+ // CraftBukkit start
+ public final java.util.concurrent.ExecutorService chatExecutor = java.util.concurrent.Executors.newCachedThreadPool(
+ new com.google.common.util.concurrent.ThreadFactoryBuilder().setDaemon(true).setNameFormat("Async Chat Thread - #%d").build());
+ // CraftBukkit end
+
public ChatDecorator getChatDecorator() {
return ChatDecorator.PLAIN;
}

View file

@ -0,0 +1,20 @@
--- a/net/minecraft/server/PlayerAdvancements.java
+++ b/net/minecraft/server/PlayerAdvancements.java
@@ -196,7 +196,8 @@
AdvancementHolder advancementholder = serveradvancementmanager.get(resourcelocation);
if (advancementholder == null) {
- PlayerAdvancements.LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", resourcelocation, this.playerSavePath);
+ if (!minecraftkey.getNamespace().equals("minecraft")) return; // CraftBukkit
+ PlayerAdvancements.LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", minecraftkey, this.playerSavePath);
} else {
this.startProgress(advancementholder, advancementprogress);
this.progressChanged.add(advancementholder);
@@ -227,6 +228,7 @@
this.progressChanged.add(advancementholder);
flag = true;
if (!flag1 && advancementprogress.isDone()) {
+ this.player.level().getCraftServer().getPluginManager().callEvent(new org.bukkit.event.player.PlayerAdvancementDoneEvent(this.player.getBukkitEntity(), advancementholder.toBukkit())); // CraftBukkit
advancementholder.value().rewards().grant(this.player);
advancementholder.value().display().ifPresent((displayinfo) -> {
if (displayinfo.shouldAnnounceChat() && this.player.level().getGameRules().getBoolean(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)) {

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/server/ServerFunctionManager.java
+++ b/net/minecraft/server/ServerFunctionManager.java
@@ -37,7 +36,7 @@
}
public CommandDispatcher<CommandSourceStack> getDispatcher() {
- return this.server.getCommands().getDispatcher();
+ return this.server.vanillaCommandDispatcher.getDispatcher(); // CraftBukkit
}
public void tick() {

View file

@ -0,0 +1,176 @@
--- a/net/minecraft/server/ServerScoreboard.java
+++ b/net/minecraft/server/ServerScoreboard.java
@@ -37,11 +37,10 @@
}
@Override
- @Override
- protected void onScoreChanged(ScoreHolder scoreholder, Objective objective, Score score) {
- super.onScoreChanged(scoreholder, objective, score);
- if (this.trackedObjectives.contains(objective)) {
- this.server.getPlayerList().broadcastAll(new ClientboundSetScorePacket(scoreholder.getScoreboardName(), objective.getName(), score.value(), score.display(), score.numberFormat()));
+ protected void onScoreChanged(ScoreHolder scoreholder, Objective scoreboardobjective, Score scoreboardscore) {
+ super.onScoreChanged(scoreholder, scoreboardobjective, scoreboardscore);
+ if (this.trackedObjectives.contains(scoreboardobjective)) {
+ this.broadcastAll(new ClientboundSetScorePacket(scoreholder.getScoreboardName(), scoreboardobjective.getName(), scoreboardscore.value(), scoreboardscore.display(), scoreboardscore.numberFormat())); // CraftBukkit
}
this.setDirty();
@@ -58,16 +55,15 @@
@Override
public void onPlayerRemoved(ScoreHolder scoreholder) {
super.onPlayerRemoved(scoreholder);
- this.server.getPlayerList().broadcastAll(new ClientboundResetScorePacket(scoreholder.getScoreboardName(), (String) null));
+ this.broadcastAll(new ClientboundResetScorePacket(scoreholder.getScoreboardName(), (String) null)); // CraftBukkit
this.setDirty();
}
@Override
- @Override
- public void onPlayerScoreRemoved(ScoreHolder scoreholder, Objective objective) {
- super.onPlayerScoreRemoved(scoreholder, objective);
- if (this.trackedObjectives.contains(objective)) {
- this.server.getPlayerList().broadcastAll(new ClientboundResetScorePacket(scoreholder.getScoreboardName(), objective.getName()));
+ public void onPlayerScoreRemoved(ScoreHolder scoreholder, Objective scoreboardobjective) {
+ super.onPlayerScoreRemoved(scoreholder, scoreboardobjective);
+ if (this.trackedObjectives.contains(scoreboardobjective)) {
+ this.broadcastAll(new ClientboundResetScorePacket(scoreholder.getScoreboardName(), scoreboardobjective.getName())); // CraftBukkit
}
this.setDirty();
@@ -78,18 +73,18 @@
public void setDisplayObjective(DisplaySlot displayslot, @Nullable Objective objective) {
Objective objective1 = this.getDisplayObjective(displayslot);
- super.setDisplayObjective(displayslot, objective);
- if (objective1 != objective && objective1 != null) {
- if (this.getObjectiveDisplaySlotCount(objective1) > 0) {
- this.server.getPlayerList().broadcastAll(new ClientboundSetDisplayObjectivePacket(displayslot, objective));
+ super.setDisplayObjective(displayslot, scoreboardobjective);
+ if (scoreboardobjective1 != scoreboardobjective && scoreboardobjective1 != null) {
+ if (this.getObjectiveDisplaySlotCount(scoreboardobjective1) > 0) {
+ this.broadcastAll(new ClientboundSetDisplayObjectivePacket(displayslot, scoreboardobjective)); // CraftBukkit
} else {
this.stopTrackingObjective(objective1);
}
}
- if (objective != null) {
- if (this.trackedObjectives.contains(objective)) {
- this.server.getPlayerList().broadcastAll(new ClientboundSetDisplayObjectivePacket(displayslot, objective));
+ if (scoreboardobjective != null) {
+ if (this.trackedObjectives.contains(scoreboardobjective)) {
+ this.broadcastAll(new ClientboundSetDisplayObjectivePacket(displayslot, scoreboardobjective)); // CraftBukkit
} else {
this.startTrackingObjective(objective);
}
@@ -99,10 +94,9 @@
}
@Override
- @Override
- public boolean addPlayerToTeam(String s, PlayerTeam playerteam) {
- if (super.addPlayerToTeam(s, playerteam)) {
- this.server.getPlayerList().broadcastAll(ClientboundSetPlayerTeamPacket.createPlayerPacket(playerteam, s, ClientboundSetPlayerTeamPacket.Action.ADD));
+ public boolean addPlayerToTeam(String playerName, PlayerTeam team) {
+ if (super.addPlayerToTeam(playerName, team)) {
+ this.broadcastAll(ClientboundSetPlayerTeamPacket.createPlayerPacket(team, playerName, ClientboundSetPlayerTeamPacket.a.ADD)); // CraftBukkit
this.setDirty();
return true;
} else {
@@ -111,10 +105,9 @@
}
@Override
- @Override
- public void removePlayerFromTeam(String s, PlayerTeam playerteam) {
- super.removePlayerFromTeam(s, playerteam);
- this.server.getPlayerList().broadcastAll(ClientboundSetPlayerTeamPacket.createPlayerPacket(playerteam, s, ClientboundSetPlayerTeamPacket.Action.REMOVE));
+ public void removePlayerFromTeam(String username, PlayerTeam playerTeam) {
+ super.removePlayerFromTeam(username, playerTeam);
+ this.broadcastAll(ClientboundSetPlayerTeamPacket.createPlayerPacket(playerTeam, username, ClientboundSetPlayerTeamPacket.a.REMOVE)); // CraftBukkit
this.setDirty();
}
@@ -130,7 +121,7 @@
public void onObjectiveChanged(Objective objective) {
super.onObjectiveChanged(objective);
if (this.trackedObjectives.contains(objective)) {
- this.server.getPlayerList().broadcastAll(new ClientboundSetObjectivePacket(objective, 2));
+ this.broadcastAll(new ClientboundSetObjectivePacket(objective, 2)); // CraftBukkit
}
this.setDirty();
@@ -148,26 +138,23 @@
}
@Override
- @Override
- public void onTeamAdded(PlayerTeam playerteam) {
- super.onTeamAdded(playerteam);
- this.server.getPlayerList().broadcastAll(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(playerteam, true));
+ public void onTeamAdded(PlayerTeam playerTeam) {
+ super.onTeamAdded(playerTeam);
+ this.broadcastAll(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(playerTeam, true)); // CraftBukkit
this.setDirty();
}
@Override
- @Override
- public void onTeamChanged(PlayerTeam playerteam) {
- super.onTeamChanged(playerteam);
- this.server.getPlayerList().broadcastAll(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(playerteam, false));
+ public void onTeamChanged(PlayerTeam playerTeam) {
+ super.onTeamChanged(playerTeam);
+ this.broadcastAll(ClientboundSetPlayerTeamPacket.createAddOrModifyPacket(playerTeam, false)); // CraftBukkit
this.setDirty();
}
@Override
- @Override
- public void onTeamRemoved(PlayerTeam playerteam) {
- super.onTeamRemoved(playerteam);
- this.server.getPlayerList().broadcastAll(ClientboundSetPlayerTeamPacket.createRemovePacket(playerteam));
+ public void onTeamRemoved(PlayerTeam playerTeam) {
+ super.onTeamRemoved(playerTeam);
+ this.broadcastAll(ClientboundSetPlayerTeamPacket.createRemovePacket(playerTeam)); // CraftBukkit
this.setDirty();
}
@@ -217,7 +204,8 @@
Iterator iterator = this.server.getPlayerList().getPlayers().iterator();
while (iterator.hasNext()) {
- ServerPlayer serverplayer = (ServerPlayer) iterator.next();
+ ServerPlayer entityplayer = (ServerPlayer) iterator.next();
+ if (entityplayer.getBukkitEntity().getScoreboard().getHandle() != this) continue; // CraftBukkit - Only players on this board
Iterator iterator1 = list.iterator();
while (iterator1.hasNext()) {
@@ -253,7 +241,8 @@
Iterator iterator = this.server.getPlayerList().getPlayers().iterator();
while (iterator.hasNext()) {
- ServerPlayer serverplayer = (ServerPlayer) iterator.next();
+ ServerPlayer entityplayer = (ServerPlayer) iterator.next();
+ if (entityplayer.getBukkitEntity().getScoreboard().getHandle() != this) continue; // CraftBukkit - Only players on this board
Iterator iterator1 = list.iterator();
while (iterator1.hasNext()) {
@@ -298,7 +287,15 @@
return this.createData().load(compoundtag);
}
- public static enum Method {
+ // CraftBukkit start - Send to players
+ private void broadcastAll(Packet packet) {
+ for (ServerPlayer entityplayer : (List<ServerPlayer>) this.server.getPlayerList().players) {
+ if (entityplayer.getBukkitEntity().getScoreboard().getHandle() == this) {
+ entityplayer.connection.send(packet);
+ }
+ }
+ }
+ // CraftBukkit end
CHANGE, REMOVE;

View file

@ -0,0 +1,53 @@
--- a/net/minecraft/server/ServerTickRateManager.java
+++ b/net/minecraft/server/ServerTickRateManager.java
@@ -60,8 +59,14 @@
}
public boolean stopSprinting() {
+ // CraftBukkit start, add sendLog parameter
+ return stopSprinting(true);
+ }
+
+ public boolean stopSprinting(boolean sendLog) {
+ // CraftBukkit end
if (this.remainingSprintTicks > 0L) {
- this.finishTickSprint();
+ this.finishTickSprint(sendLog); // CraftBukkit - add sendLog parameter
return true;
} else {
return false;
@@ -79,7 +84,7 @@
return flag;
}
- private void finishTickSprint() {
+ private void finishTickSprint(boolean sendLog) { // CraftBukkit - add sendLog parameter
long i = this.scheduledCurrentSprintTicks - this.remainingSprintTicks;
double d0 = Math.max(1.0D, (double) this.sprintTimeSpend) / (double) TimeUtil.NANOSECONDS_PER_MILLISECOND;
int j = (int) ((double) (TimeUtil.MILLISECONDS_PER_SECOND * i) / d0);
@@ -87,9 +92,13 @@
this.scheduledCurrentSprintTicks = 0L;
this.sprintTimeSpend = 0L;
- this.server.createCommandSourceStack().sendSuccess(() -> {
- return Component.translatable("commands.tick.sprint.report", j, s);
- }, true);
+ // CraftBukkit start - add sendLog parameter
+ if (sendLog) {
+ this.server.createCommandSourceStack().sendSuccess(() -> {
+ return Component.translatable("commands.tick.sprint.report", j, s);
+ }, true);
+ }
+ // CraftBukkit end
this.remainingSprintTicks = 0L;
this.setFrozen(this.previousIsFrozen);
this.server.onTickRateChanged();
@@ -103,7 +112,7 @@
--this.remainingSprintTicks;
return true;
} else {
- this.finishTickSprint();
+ this.finishTickSprint(true); // CraftBukkit - add sendLog parameter
return false;
}
}

View file

@ -0,0 +1,37 @@
--- a/net/minecraft/server/bossevents/CustomBossEvent.java
+++ b/net/minecraft/server/bossevents/CustomBossEvent.java
@@ -17,6 +17,10 @@
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.BossEvent;
+// CraftBukkit start
+import org.bukkit.boss.KeyedBossBar;
+import org.bukkit.craftbukkit.boss.CraftKeyedBossbar;
+// CraftBukkit end
public class CustomBossEvent extends ServerBossEvent {
@@ -24,10 +28,20 @@
private final Set<UUID> players = Sets.newHashSet();
private int value;
private int max = 100;
+ // CraftBukkit start
+ private KeyedBossBar bossBar;
- public CustomBossEvent(ResourceLocation resourcelocation, Component component) {
- super(component, BossEvent.BossBarColor.WHITE, BossEvent.BossBarOverlay.PROGRESS);
- this.id = resourcelocation;
+ public KeyedBossBar getBukkitEntity() {
+ if (bossBar == null) {
+ bossBar = new CraftKeyedBossbar(this);
+ }
+ return bossBar;
+ }
+ // CraftBukkit end
+
+ public CustomBossEvent(ResourceLocation id, Component name) {
+ super(name, BossEvent.BossBarColor.WHITE, BossEvent.BossBarOverlay.PROGRESS);
+ this.id = id;
this.setProgress(0.0F);
}

View file

@ -0,0 +1,23 @@
--- a/net/minecraft/server/commands/DifficultyCommand.java
+++ b/net/minecraft/server/commands/DifficultyCommand.java
@@ -43,14 +42,15 @@
}));
}
- public static int setDifficulty(CommandSourceStack commandsourcestack, Difficulty difficulty) throws CommandSyntaxException {
- MinecraftServer minecraftserver = commandsourcestack.getServer();
+ public static int setDifficulty(CommandSourceStack source, Difficulty difficulty) throws CommandSyntaxException {
+ MinecraftServer minecraftserver = source.getServer();
+ net.minecraft.server.level.ServerLevel worldServer = source.getLevel(); // CraftBukkit
- if (minecraftserver.getWorldData().getDifficulty() == difficulty) {
+ if (worldServer.getDifficulty() == difficulty) { // CraftBukkit
throw DifficultyCommand.ERROR_ALREADY_DIFFICULT.create(difficulty.getKey());
} else {
- minecraftserver.setDifficulty(difficulty, true);
- commandsourcestack.sendSuccess(() -> {
+ worldServer.serverLevelData.setDifficulty(difficulty); // CraftBukkit
+ source.sendSuccess(() -> {
return Component.translatable("commands.difficulty.success", difficulty.getDisplayName());
}, true);
return 0;

View file

@ -0,0 +1,29 @@
--- a/net/minecraft/server/commands/EffectCommands.java
+++ b/net/minecraft/server/commands/EffectCommands.java
@@ -85,7 +84,7 @@
if (entity instanceof LivingEntity) {
MobEffectInstance mobeffectinstance = new MobEffectInstance(mobeffect, k, i, false, flag);
- if (((LivingEntity) entity).addEffect(mobeffectinstance, commandsourcestack.getEntity())) {
+ if (((LivingEntity) entity).addEffect(mobeffect, source.getEntity(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND)) { // CraftBukkit
++j;
}
}
@@ -115,7 +114,7 @@
while (iterator.hasNext()) {
Entity entity = (Entity) iterator.next();
- if (entity instanceof LivingEntity && ((LivingEntity) entity).removeAllEffects()) {
+ if (entity instanceof LivingEntity && ((LivingEntity) entity).removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND)) { // CraftBukkit
++i;
}
}
@@ -145,7 +144,7 @@
while (iterator.hasNext()) {
Entity entity = (Entity) iterator.next();
- if (entity instanceof LivingEntity && ((LivingEntity) entity).removeEffect(mobeffect)) {
+ if (entity instanceof LivingEntity && ((LivingEntity) entity).removeEffect(mobeffectlist, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND)) { // CraftBukkit
++i;
}
}

View file

@ -0,0 +1,26 @@
--- a/net/minecraft/server/commands/GameRuleCommand.java
+++ b/net/minecraft/server/commands/GameRuleCommand.java
@@ -31,9 +29,9 @@
commanddispatcher.register(literalargumentbuilder);
}
- static <T extends GameRules.Value<T>> int setRule(CommandContext<CommandSourceStack> commandcontext, GameRules.Key<T> gamerules_key) {
- CommandSourceStack commandsourcestack = (CommandSourceStack) commandcontext.getSource();
- T t0 = commandsourcestack.getServer().getGameRules().getRule(gamerules_key);
+ static <T extends GameRules.Value<T>> int setRule(CommandContext<CommandSourceStack> source, GameRules.Key<T> gameRule) {
+ CommandSourceStack commandlistenerwrapper = (CommandSourceStack) source.getSource();
+ T t0 = commandlistenerwrapper.getLevel().getGameRules().getRule(gameRule); // CraftBukkit
t0.setFromArgument(commandcontext, "value");
commandsourcestack.sendSuccess(() -> {
@@ -42,8 +40,8 @@
return t0.getCommandResult();
}
- static <T extends GameRules.Value<T>> int queryRule(CommandSourceStack commandsourcestack, GameRules.Key<T> gamerules_key) {
- T t0 = commandsourcestack.getServer().getGameRules().getRule(gamerules_key);
+ static <T extends GameRules.Value<T>> int queryRule(CommandSourceStack source, GameRules.Key<T> gameRule) {
+ T t0 = source.getLevel().getGameRules().getRule(gameRule); // CraftBukkit
commandsourcestack.sendSuccess(() -> {
return Component.translatable("commands.gamerule.query", gamerules_key.getId(), t0.toString());

View file

@ -0,0 +1,24 @@
--- a/net/minecraft/server/commands/ListPlayersCommand.java
+++ b/net/minecraft/server/commands/ListPlayersCommand.java
@@ -34,10 +33,17 @@
});
}
- private static int format(CommandSourceStack commandsourcestack, Function<ServerPlayer, Component> function) {
- PlayerList playerlist = commandsourcestack.getServer().getPlayerList();
- List<ServerPlayer> list = playerlist.getPlayers();
- Component component = ComponentUtils.formatList(list, function);
+ private static int format(CommandSourceStack source, Function<ServerPlayer, Component> nameExtractor) {
+ PlayerList playerlist = source.getServer().getPlayerList();
+ // CraftBukkit start
+ List<ServerPlayer> players = playerlist.getPlayers();
+ if (source.getBukkitSender() instanceof org.bukkit.entity.Player) {
+ org.bukkit.entity.Player sender = (org.bukkit.entity.Player) source.getBukkitSender();
+ players = players.stream().filter((ep) -> sender.canSee(ep.getBukkitEntity())).collect(java.util.stream.Collectors.toList());
+ }
+ List<ServerPlayer> list = players;
+ // CraftBukkit end
+ Component ichatbasecomponent = ComponentUtils.formatList(list, nameExtractor);
commandsourcestack.sendSuccess(() -> {
return Component.translatable("commands.list.players", list.size(), playerlist.getMaxPlayers(), component);

View file

@ -0,0 +1,14 @@
--- a/net/minecraft/server/commands/LootCommand.java
+++ b/net/minecraft/server/commands/LootCommand.java
@@ -248,8 +247,9 @@
private static int dropInWorld(CommandSourceStack commandsourcestack, Vec3 vec3, List<ItemStack> list, LootCommand.Callback lootcommand_callback) throws CommandSyntaxException {
ServerLevel serverlevel = commandsourcestack.getLevel();
- list.forEach((itemstack) -> {
- ItemEntity itementity = new ItemEntity(serverlevel, vec3.x, vec3.y, vec3.z, itemstack.copy());
+ items.removeIf(ItemStack::isEmpty); // CraftBukkit - SPIGOT-6959 Remove empty items for avoid throw an error in new EntityItem
+ items.forEach((itemstack) -> {
+ ItemEntity entityitem = new ItemEntity(worldserver, pos.x, pos.y, pos.z, itemstack.copy());
itementity.setDefaultPickUpDelay();
serverlevel.addFreshEntity(itementity);

View file

@ -0,0 +1,16 @@
--- a/net/minecraft/server/commands/PlaceCommand.java
+++ b/net/minecraft/server/commands/PlaceCommand.java
@@ -131,9 +130,10 @@
if (!structurestart.isValid()) {
throw PlaceCommand.ERROR_STRUCTURE_FAILED.create();
} else {
- BoundingBox boundingbox = structurestart.getBoundingBox();
- ChunkPos chunkpos = new ChunkPos(SectionPos.blockToSectionCoord(boundingbox.minX()), SectionPos.blockToSectionCoord(boundingbox.minZ()));
- ChunkPos chunkpos1 = new ChunkPos(SectionPos.blockToSectionCoord(boundingbox.maxX()), SectionPos.blockToSectionCoord(boundingbox.maxZ()));
+ structurestart.generationEventCause = org.bukkit.event.world.AsyncStructureGenerateEvent.Cause.COMMAND; // CraftBukkit - set AsyncStructureGenerateEvent.Cause.COMMAND as generation cause
+ BoundingBox structureboundingbox = structurestart.getBoundingBox();
+ ChunkPos chunkcoordintpair = new ChunkPos(SectionPos.blockToSectionCoord(structureboundingbox.minX()), SectionPos.blockToSectionCoord(structureboundingbox.minZ()));
+ ChunkPos chunkcoordintpair1 = new ChunkPos(SectionPos.blockToSectionCoord(structureboundingbox.maxX()), SectionPos.blockToSectionCoord(structureboundingbox.maxZ()));
checkLoaded(serverlevel, chunkpos, chunkpos1);
ChunkPos.rangeClosed(chunkpos, chunkpos1).forEach((chunkpos2) -> {

View file

@ -0,0 +1,25 @@
--- a/net/minecraft/server/commands/ReloadCommand.java
+++ b/net/minecraft/server/commands/ReloadCommand.java
@@ -45,9 +44,19 @@
return collection1;
}
- public static void register(CommandDispatcher<CommandSourceStack> commanddispatcher) {
- commanddispatcher.register((LiteralArgumentBuilder) ((LiteralArgumentBuilder) Commands.literal("reload").requires((commandsourcestack) -> {
- return commandsourcestack.hasPermission(2);
+ // CraftBukkit start
+ public static void reload(MinecraftServer minecraftserver) {
+ PackRepository resourcepackrepository = minecraftserver.getPackRepository();
+ WorldData savedata = minecraftserver.getWorldData();
+ Collection<String> collection = resourcepackrepository.getSelectedIds();
+ Collection<String> collection1 = discoverNewPacks(resourcepackrepository, savedata, collection);
+ minecraftserver.reloadResources(collection1);
+ }
+ // CraftBukkit end
+
+ public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
+ dispatcher.register((LiteralArgumentBuilder) ((LiteralArgumentBuilder) net.minecraft.commands.Commands.literal("reload").requires((commandlistenerwrapper) -> {
+ return commandlistenerwrapper.hasPermission(2);
})).executes((commandcontext) -> {
CommandSourceStack commandsourcestack = (CommandSourceStack) commandcontext.getSource();
MinecraftServer minecraftserver = commandsourcestack.getServer();

View file

@ -0,0 +1,15 @@
--- a/net/minecraft/server/commands/ScheduleCommand.java
+++ b/net/minecraft/server/commands/ScheduleCommand.java
@@ -55,9 +53,9 @@
if (i == 0) {
throw ScheduleCommand.ERROR_SAME_TICK.create();
} else {
- long j = commandsourcestack.getLevel().getGameTime() + (long) i;
- ResourceLocation resourcelocation = (ResourceLocation) pair.getFirst();
- TimerQueue<MinecraftServer> timerqueue = commandsourcestack.getServer().getWorldData().overworldData().getScheduledEvents();
+ long j = source.getLevel().getGameTime() + (long) time;
+ ResourceLocation minecraftkey = (ResourceLocation) function.getFirst();
+ TimerQueue<MinecraftServer> customfunctioncallbacktimerqueue = source.getLevel().serverLevelData.overworldData().getScheduledEvents(); // CraftBukkit - SPIGOT-6667: Use world specific function timer
((Either) pair.getSecond()).ifLeft((commandfunction) -> {
String s = resourcelocation.toString();

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/server/commands/SetSpawnCommand.java
+++ b/net/minecraft/server/commands/SetSpawnCommand.java
@@ -42,7 +41,7 @@
while (iterator.hasNext()) {
ServerPlayer serverplayer = (ServerPlayer) iterator.next();
- serverplayer.setRespawnPosition(resourcekey, blockpos, f, true, false);
+ entityplayer.setRespawnPosition(resourcekey, pos, angle, true, false, org.bukkit.event.player.PlayerSpawnChangeEvent.Cause.COMMAND); // CraftBukkit
}
String s = resourcekey.location().toString();

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/server/commands/SpreadPlayersCommand.java
+++ b/net/minecraft/server/commands/SpreadPlayersCommand.java
@@ -204,7 +203,7 @@
spreadplayerscommand_position = aspreadplayerscommand_position[j++];
}
- entity.teleportTo(serverlevel, (double) Mth.floor(spreadplayerscommand_position.x) + 0.5D, (double) spreadplayerscommand_position.getSpawnY(serverlevel, i), (double) Mth.floor(spreadplayerscommand_position.z) + 0.5D, Set.of(), entity.getYRot(), entity.getXRot());
+ entity.teleportTo(level, (double) Mth.floor(commandspreadplayers_a.x) + 0.5D, (double) commandspreadplayers_a.getSpawnY(level, maxHeight), (double) Mth.floor(commandspreadplayers_a.z) + 0.5D, Set.of(), entity.getYRot(), entity.getXRot(), org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.COMMAND); // CraftBukkit - handle teleport reason
d1 = Double.MAX_VALUE;
SpreadPlayersCommand.Position[] aspreadplayerscommand_position1 = aspreadplayerscommand_position;
int k = aspreadplayerscommand_position.length;

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/server/commands/SummonCommand.java
+++ b/net/minecraft/server/commands/SummonCommand.java
@@ -68,7 +67,7 @@
((Mob) entity).finalizeSpawn(commandsourcestack.getLevel(), commandsourcestack.getLevel().getCurrentDifficultyAt(entity.blockPosition()), MobSpawnType.COMMAND, (SpawnGroupData) null, (CompoundTag) null);
}
- if (!serverlevel.tryAddFreshEntityWithPassengers(entity)) {
+ if (!worldserver.tryAddFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND)) { // CraftBukkit - pass a spawn reason of "COMMAND"
throw SummonCommand.ERROR_DUPLICATE_UUID.create();
} else {
return entity;

View file

@ -0,0 +1,53 @@
--- a/net/minecraft/server/commands/TeleportCommand.java
+++ b/net/minecraft/server/commands/TeleportCommand.java
@@ -33,6 +32,12 @@
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.event.entity.EntityTeleportEvent;
+import org.bukkit.event.player.PlayerTeleportEvent;
+// CraftBukkit end
public class TeleportCommand {
@@ -156,11 +161,34 @@
float f2 = Mth.wrapDegrees(f);
float f3 = Mth.wrapDegrees(f1);
- if (entity.teleportTo(serverlevel, d0, d1, d2, set, f2, f3)) {
- if (teleportcommand_lookat != null) {
- teleportcommand_lookat.perform(commandsourcestack, entity);
+ // CraftBukkit start - Teleport event
+ boolean result;
+ if (entity instanceof ServerPlayer player) {
+ result = player.teleportTo(level, x, d1, y, set, f2, f3, PlayerTeleportEvent.TeleportCause.COMMAND);
+ } else {
+ Location to = new Location(level.getWorld(), x, d1, y, f2, f3);
+ EntityTeleportEvent event = new EntityTeleportEvent(entity.getBukkitEntity(), entity.getBukkitEntity().getLocation(), to);
+ level.getCraftServer().getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return;
}
+ x = to.getX();
+ d1 = to.getY();
+ y = to.getZ();
+ f2 = to.getYaw();
+ f3 = to.getPitch();
+ level = ((CraftWorld) to.getWorld()).getHandle();
+
+ result = entity.teleportTo(level, x, d1, y, set, f2, f3);
+ }
+
+ if (result) {
+ // CraftBukkit end
+ if (relativeList != null) {
+ relativeList.perform(source, entity);
+ }
+
label23:
{
if (entity instanceof LivingEntity) {

View file

@ -0,0 +1,59 @@
--- a/net/minecraft/server/commands/TimeCommand.java
+++ b/net/minecraft/server/commands/TimeCommand.java
@@ -9,6 +8,10 @@
import net.minecraft.commands.arguments.TimeArgument;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
+// CraftBukkit start
+import org.bukkit.Bukkit;
+import org.bukkit.event.world.TimeSkipEvent;
+// CraftBukkit end
public class TimeCommand {
@@ -49,13 +52,19 @@
return i;
}
- public static int setTime(CommandSourceStack commandsourcestack, int i) {
- Iterator iterator = commandsourcestack.getServer().getAllLevels().iterator();
+ public static int setTime(CommandSourceStack source, int time) {
+ Iterator iterator = com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in
while (iterator.hasNext()) {
ServerLevel serverlevel = (ServerLevel) iterator.next();
- serverlevel.setDayTime((long) i);
+ // CraftBukkit start
+ TimeSkipEvent event = new TimeSkipEvent(worldserver.getWorld(), TimeSkipEvent.SkipReason.COMMAND, time - worldserver.getDayTime());
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ worldserver.setDayTime((long) worldserver.getDayTime() + event.getSkipAmount());
+ }
+ // CraftBukkit end
}
commandsourcestack.sendSuccess(() -> {
@@ -64,13 +73,19 @@
return getDayTime(commandsourcestack.getLevel());
}
- public static int addTime(CommandSourceStack commandsourcestack, int i) {
- Iterator iterator = commandsourcestack.getServer().getAllLevels().iterator();
+ public static int addTime(CommandSourceStack source, int amount) {
+ Iterator iterator = com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in
while (iterator.hasNext()) {
ServerLevel serverlevel = (ServerLevel) iterator.next();
- serverlevel.setDayTime(serverlevel.getDayTime() + (long) i);
+ // CraftBukkit start
+ TimeSkipEvent event = new TimeSkipEvent(worldserver.getWorld(), TimeSkipEvent.SkipReason.COMMAND, amount);
+ Bukkit.getPluginManager().callEvent(event);
+ if (!event.isCancelled()) {
+ worldserver.setDayTime(worldserver.getDayTime() + event.getSkipAmount());
+ }
+ // CraftBukkit end
}
int j = getDayTime(commandsourcestack.getLevel());

View file

@ -0,0 +1,79 @@
--- a/net/minecraft/server/commands/WorldBorderCommand.java
+++ b/net/minecraft/server/commands/WorldBorderCommand.java
@@ -57,8 +56,8 @@
})))));
}
- private static int setDamageBuffer(CommandSourceStack commandsourcestack, float f) throws CommandSyntaxException {
- WorldBorder worldborder = commandsourcestack.getServer().overworld().getWorldBorder();
+ private static int setDamageBuffer(CommandSourceStack source, float distance) throws CommandSyntaxException {
+ WorldBorder worldborder = source.getLevel().getWorldBorder(); // CraftBukkit
if (worldborder.getDamageSafeZone() == (double) f) {
throw WorldBorderCommand.ERROR_SAME_DAMAGE_BUFFER.create();
@@ -71,8 +70,8 @@
}
}
- private static int setDamageAmount(CommandSourceStack commandsourcestack, float f) throws CommandSyntaxException {
- WorldBorder worldborder = commandsourcestack.getServer().overworld().getWorldBorder();
+ private static int setDamageAmount(CommandSourceStack source, float damagePerBlock) throws CommandSyntaxException {
+ WorldBorder worldborder = source.getLevel().getWorldBorder(); // CraftBukkit
if (worldborder.getDamagePerBlock() == (double) f) {
throw WorldBorderCommand.ERROR_SAME_DAMAGE_AMOUNT.create();
@@ -85,8 +84,8 @@
}
}
- private static int setWarningTime(CommandSourceStack commandsourcestack, int i) throws CommandSyntaxException {
- WorldBorder worldborder = commandsourcestack.getServer().overworld().getWorldBorder();
+ private static int setWarningTime(CommandSourceStack source, int time) throws CommandSyntaxException {
+ WorldBorder worldborder = source.getLevel().getWorldBorder(); // CraftBukkit
if (worldborder.getWarningTime() == i) {
throw WorldBorderCommand.ERROR_SAME_WARNING_TIME.create();
@@ -99,8 +98,8 @@
}
}
- private static int setWarningDistance(CommandSourceStack commandsourcestack, int i) throws CommandSyntaxException {
- WorldBorder worldborder = commandsourcestack.getServer().overworld().getWorldBorder();
+ private static int setWarningDistance(CommandSourceStack source, int distance) throws CommandSyntaxException {
+ WorldBorder worldborder = source.getLevel().getWorldBorder(); // CraftBukkit
if (worldborder.getWarningBlocks() == i) {
throw WorldBorderCommand.ERROR_SAME_WARNING_DISTANCE.create();
@@ -113,8 +112,8 @@
}
}
- private static int getSize(CommandSourceStack commandsourcestack) {
- double d0 = commandsourcestack.getServer().overworld().getWorldBorder().getSize();
+ private static int getSize(CommandSourceStack source) {
+ double d0 = source.getLevel().getWorldBorder().getSize(); // CraftBukkit
commandsourcestack.sendSuccess(() -> {
return Component.translatable("commands.worldborder.get", String.format(Locale.ROOT, "%.0f", d0));
@@ -122,8 +121,8 @@
return Mth.floor(d0 + 0.5D);
}
- private static int setCenter(CommandSourceStack commandsourcestack, Vec2 vec2) throws CommandSyntaxException {
- WorldBorder worldborder = commandsourcestack.getServer().overworld().getWorldBorder();
+ private static int setCenter(CommandSourceStack source, Vec2 pos) throws CommandSyntaxException {
+ WorldBorder worldborder = source.getLevel().getWorldBorder(); // CraftBukkit
if (worldborder.getCenterX() == (double) vec2.x && worldborder.getCenterZ() == (double) vec2.y) {
throw WorldBorderCommand.ERROR_SAME_CENTER.create();
@@ -138,8 +137,8 @@
}
}
- private static int setSize(CommandSourceStack commandsourcestack, double d0, long i) throws CommandSyntaxException {
- WorldBorder worldborder = commandsourcestack.getServer().overworld().getWorldBorder();
+ private static int setSize(CommandSourceStack source, double newSize, long i) throws CommandSyntaxException {
+ WorldBorder worldborder = source.getLevel().getWorldBorder(); // CraftBukkit
double d1 = worldborder.getSize();
if (d1 == d0) {

View file

@ -0,0 +1,250 @@
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -53,6 +52,16 @@
import net.minecraft.world.level.storage.LevelStorageSource;
import org.slf4j.Logger;
+// CraftBukkit start
+import net.minecraft.server.WorldLoader;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.io.IoBuilder;
+import org.bukkit.command.CommandSender;
+import org.bukkit.event.server.ServerCommandEvent;
+import org.bukkit.event.server.RemoteServerCommandEvent;
+// CraftBukkit end
+
public class DedicatedServer extends MinecraftServer implements ServerInterface {
static final Logger LOGGER = LogUtils.getLogger();
@@ -61,7 +70,7 @@
private final List<ConsoleInput> consoleInput = Collections.synchronizedList(Lists.newArrayList());
@Nullable
private QueryThreadGs4 queryThreadGs4;
- private final RconConsoleSource rconConsoleSource;
+ // private final RemoteControlCommandListener rconConsoleSource; // CraftBukkit - remove field
@Nullable
private RconThread rconThread;
private final DedicatedServerSettings settings;
@@ -70,10 +79,12 @@
@Nullable
private final TextFilterClient textFilterClient;
- public DedicatedServer(Thread thread, LevelStorageSource.LevelStorageAccess levelstoragesource_levelstorageaccess, PackRepository packrepository, WorldStem worldstem, DedicatedServerSettings dedicatedserversettings, DataFixer datafixer, Services services, ChunkProgressListenerFactory chunkprogresslistenerfactory) {
- super(thread, levelstoragesource_levelstorageaccess, packrepository, worldstem, Proxy.NO_PROXY, datafixer, services, chunkprogresslistenerfactory);
+ // CraftBukkit start - Signature changed
+ public DedicatedServer(joptsimple.OptionSet options, WorldLoader.a worldLoader, Thread thread, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PackRepository resourcepackrepository, WorldStem worldstem, DedicatedServerSettings dedicatedserversettings, DataFixer datafixer, Services services, ChunkProgressListenerFactory worldloadlistenerfactory) {
+ super(options, worldLoader, thread, convertable_conversionsession, resourcepackrepository, worldstem, Proxy.NO_PROXY, datafixer, services, worldloadlistenerfactory);
+ // CraftBukkit end
this.settings = dedicatedserversettings;
- this.rconConsoleSource = new RconConsoleSource(this);
+ // this.rconConsoleSource = new RemoteControlCommandListener(this); // CraftBukkit - remove field
this.textFilterClient = TextFilterClient.createFromConfig(dedicatedserversettings.getProperties().textFilteringConfig);
}
@@ -83,13 +92,44 @@
Thread thread = new Thread("Server console handler") {
@Override
public void run() {
- BufferedReader bufferedreader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8));
+ // CraftBukkit start
+ if (!org.bukkit.craftbukkit.Main.useConsole) {
+ return;
+ }
+ jline.console.ConsoleReader bufferedreader = reader;
+ // MC-33041, SPIGOT-5538: if System.in is not valid due to javaw, then return
+ try {
+ System.in.available();
+ } catch (IOException ex) {
+ return;
+ }
+ // CraftBukkit end
+
String s;
try {
- while (!DedicatedServer.this.isStopped() && DedicatedServer.this.isRunning() && (s = bufferedreader.readLine()) != null) {
- DedicatedServer.this.handleConsoleInput(s, DedicatedServer.this.createCommandSourceStack());
+ // CraftBukkit start - JLine disabling compatibility
+ while (!DedicatedServer.this.isStopped() && DedicatedServer.this.isRunning()) {
+ if (org.bukkit.craftbukkit.Main.useJline) {
+ s = bufferedreader.readLine(">", null);
+ } else {
+ s = bufferedreader.readLine();
+ }
+
+ // SPIGOT-5220: Throttle if EOF (ctrl^d) or stdin is /dev/null
+ if (s == null) {
+ try {
+ Thread.sleep(50L);
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
+ continue;
+ }
+ if (s.trim().length() > 0) { // Trim to filter lines which are just spaces
+ DedicatedServer.this.handleConsoleInput(s, DedicatedServer.this.createCommandSourceStack());
+ }
+ // CraftBukkit end
}
} catch (IOException ioexception) {
DedicatedServer.LOGGER.error("Exception handling console input", ioexception);
@@ -98,6 +138,27 @@
}
};
+ // CraftBukkit start - TODO: handle command-line logging arguments
+ java.util.logging.Logger global = java.util.logging.Logger.getLogger("");
+ global.setUseParentHandlers(false);
+ for (java.util.logging.Handler handler : global.getHandlers()) {
+ global.removeHandler(handler);
+ }
+ global.addHandler(new org.bukkit.craftbukkit.util.ForwardLogHandler());
+
+ final org.apache.logging.log4j.core.Logger logger = ((org.apache.logging.log4j.core.Logger) LogManager.getRootLogger());
+ for (org.apache.logging.log4j.core.Appender appender : logger.getAppenders().values()) {
+ if (appender instanceof org.apache.logging.log4j.core.appender.ConsoleAppender) {
+ logger.removeAppender(appender);
+ }
+ }
+
+ new org.bukkit.craftbukkit.util.TerminalConsoleWriterThread(System.out, this.reader).start();
+
+ System.setOut(IoBuilder.forLogger(logger).setLevel(Level.INFO).buildPrintStream());
+ System.setErr(IoBuilder.forLogger(logger).setLevel(Level.WARN).buildPrintStream());
+ // CraftBukkit end
+
thread.setDaemon(true);
thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(DedicatedServer.LOGGER));
thread.start();
@@ -122,7 +183,7 @@
this.setMotd(dedicatedserverproperties.motd);
super.setPlayerIdleTimeout((Integer) dedicatedserverproperties.playerIdleTimeout.get());
this.setEnforceWhitelist(dedicatedserverproperties.enforceWhitelist);
- this.worldData.setGameType(dedicatedserverproperties.gamemode);
+ // this.worldData.setGameType(dedicatedserverproperties.gamemode); // CraftBukkit - moved to world loading
DedicatedServer.LOGGER.info("Default game type: {}", dedicatedserverproperties.gamemode);
InetAddress inetaddress = null;
@@ -146,6 +207,12 @@
return false;
}
+ // CraftBukkit start
+ this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage));
+ server.loadPlugins();
+ server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.STARTUP);
+ // CraftBukkit end
+
if (!this.usesAuthentication()) {
DedicatedServer.LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!");
DedicatedServer.LOGGER.warn("The server will make no attempt to authenticate usernames. Beware.");
@@ -160,13 +227,13 @@
if (!OldUsersConverter.serverReadyAfterUserconversion(this)) {
return false;
} else {
- this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage));
+ // this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage)); // CraftBukkit - moved up
long i = Util.getNanos();
SkullBlockEntity.setup(this.services, this);
GameProfileCache.setUsesAuthentication(this.usesAuthentication());
DedicatedServer.LOGGER.info("Preparing level \"{}\"", this.getLevelIdName());
- this.loadLevel();
+ this.loadLevel(storageSource.getLevelId()); // CraftBukkit
long j = Util.getNanos() - i;
String s = String.format(Locale.ROOT, "%.3fs", (double) j / 1.0E9D);
@@ -307,6 +365,7 @@
this.queryThreadGs4.stop();
}
+ System.exit(0); // CraftBukkit
}
@Override
@@ -330,7 +387,15 @@
while (!this.consoleInput.isEmpty()) {
ConsoleInput consoleinput = (ConsoleInput) this.consoleInput.remove(0);
- this.getCommands().performPrefixedCommand(consoleinput.source, consoleinput.msg);
+ // CraftBukkit start - ServerCommand for preprocessing
+ ServerCommandEvent event = new ServerCommandEvent(console, servercommand.msg);
+ server.getPluginManager().callEvent(event);
+ if (event.isCancelled()) continue;
+ servercommand = new ConsoleInput(event.getCommand(), servercommand.source);
+
+ // this.getCommands().performPrefixedCommand(servercommand.source, servercommand.msg); // Called in dispatchServerCommand
+ server.dispatchServerCommand(console, servercommand);
+ // CraftBukkit end
}
}
@@ -582,17 +622,45 @@
@Override
@Override
public String getPluginNames() {
- return "";
+ // CraftBukkit start - Whole method
+ StringBuilder result = new StringBuilder();
+ org.bukkit.plugin.Plugin[] plugins = server.getPluginManager().getPlugins();
+
+ result.append(server.getName());
+ result.append(" on Bukkit ");
+ result.append(server.getBukkitVersion());
+
+ if (plugins.length > 0 && server.getQueryPlugins()) {
+ result.append(": ");
+
+ for (int i = 0; i < plugins.length; i++) {
+ if (i > 0) {
+ result.append("; ");
+ }
+
+ result.append(plugins[i].getDescription().getName());
+ result.append(" ");
+ result.append(plugins[i].getDescription().getVersion().replaceAll(";", ","));
+ }
+ }
+
+ return result.toString();
+ // CraftBukkit end
}
@Override
- @Override
- public String runCommand(String s) {
- this.rconConsoleSource.prepareForCommand();
+ public String runCommand(String command) {
+ // CraftBukkit start - fire RemoteServerCommandEvent
+ throw new UnsupportedOperationException("Not supported - remote source required.");
+ }
+
+ public String runCommand(RconConsoleSource rconConsoleSource, String s) {
+ rconConsoleSource.prepareForCommand();
this.executeBlocking(() -> {
this.getCommands().performPrefixedCommand(this.rconConsoleSource.createCommandSourceStack(), s);
});
- return this.rconConsoleSource.getCommandResponse();
+ return rconConsoleSource.getCommandResponse();
+ // CraftBukkit end
}
public void storeUsingWhiteList(boolean flag) {
@@ -651,4 +718,15 @@
public Optional<MinecraftServer.ServerResourcePackInfo> getServerResourcePack() {
return this.settings.getProperties().serverResourcePackInfo;
}
+
+ // CraftBukkit start
+ public boolean isDebugging() {
+ return this.getProperties().debug;
+ }
+
+ @Override
+ public CommandSender getBukkitSender(CommandSourceStack wrapper) {
+ return console;
+ }
+ // CraftBukkit end
}

View file

@ -0,0 +1,53 @@
--- a/net/minecraft/server/dedicated/DedicatedServerProperties.java
+++ b/net/minecraft/server/dedicated/DedicatedServerProperties.java
@@ -44,11 +44,16 @@
import net.minecraft.world.level.levelgen.presets.WorldPresets;
import org.slf4j.Logger;
+// CraftBukkit start
+import joptsimple.OptionSet;
+// CraftBukkit end
+
public class DedicatedServerProperties extends Settings<DedicatedServerProperties> {
static final Logger LOGGER = LogUtils.getLogger();
private static final Pattern SHA1 = Pattern.compile("^[a-fA-F0-9]{40}$");
private static final Splitter COMMA_SPLITTER = Splitter.on(',').trimResults();
+ public final boolean debug = this.get("debug", false); // CraftBukkit
public final boolean onlineMode = this.get("online-mode", true);
public final boolean preventProxyConnections = this.get("prevent-proxy-connections", false);
public final String serverIp = this.get("server-ip", "");
@@ -103,8 +108,10 @@
private final DedicatedServerProperties.WorldDimensionData worldDimensionData;
public final WorldOptions worldOptions;
- public DedicatedServerProperties(Properties properties) {
- super(properties);
+ // CraftBukkit start
+ public DedicatedServerProperties(Properties properties, OptionSet optionset) {
+ super(properties, optionset);
+ // CraftBukkit end
this.difficulty = (Difficulty) this.get("difficulty", dispatchNumberOrString(Difficulty::byId, Difficulty::byName), Difficulty::getKey, Difficulty.EASY);
this.gamemode = (GameType) this.get("gamemode", dispatchNumberOrString(GameType::byId, GameType::byName), GameType::getName, GameType.SURVIVAL);
this.levelName = this.get("level-name", "world");
@@ -161,14 +168,15 @@
this.initialDataPackConfiguration = getDatapackConfig(this.get("initial-enabled-packs", String.join(",", WorldDataConfiguration.DEFAULT.dataPacks().getEnabled())), this.get("initial-disabled-packs", String.join(",", WorldDataConfiguration.DEFAULT.dataPacks().getDisabled())));
}
- public static DedicatedServerProperties fromFile(Path path) {
- return new DedicatedServerProperties(loadFromFile(path));
+ // CraftBukkit start
+ public static DedicatedServerProperties fromFile(Path path, OptionSet optionset) {
+ return new DedicatedServerProperties(loadFromFile(path), optionset);
}
@Override
- @Override
- protected DedicatedServerProperties reload(RegistryAccess registryaccess, Properties properties) {
- return new DedicatedServerProperties(properties);
+ protected DedicatedServerProperties reload(RegistryAccess iregistrycustom, Properties properties, OptionSet optionset) {
+ return new DedicatedServerProperties(properties, optionset);
+ // CraftBukkit end
}
@Nullable

View file

@ -0,0 +1,27 @@
--- a/net/minecraft/server/dedicated/DedicatedServerSettings.java
+++ b/net/minecraft/server/dedicated/DedicatedServerSettings.java
@@ -3,14 +3,21 @@
import java.nio.file.Path;
import java.util.function.UnaryOperator;
+// CraftBukkit start
+import java.io.File;
+import joptsimple.OptionSet;
+// CraftBukkit end
+
public class DedicatedServerSettings {
private final Path source;
private DedicatedServerProperties properties;
- public DedicatedServerSettings(Path path) {
- this.source = path;
- this.properties = DedicatedServerProperties.fromFile(path);
+ // CraftBukkit start
+ public DedicatedServerSettings(OptionSet optionset) {
+ this.source = ((File) optionset.valueOf("config")).toPath();
+ this.properties = DedicatedServerProperties.fromFile(source, optionset);
+ // CraftBukkit end
}
public DedicatedServerProperties getProperties() {

View file

@ -0,0 +1,102 @@
--- a/net/minecraft/server/dedicated/Settings.java
+++ b/net/minecraft/server/dedicated/Settings.java
@@ -23,17 +22,36 @@
import net.minecraft.core.RegistryAccess;
import org.slf4j.Logger;
+import joptsimple.OptionSet; // CraftBukkit
+import net.minecraft.core.RegistryAccess;
+
public abstract class Settings<T extends Settings<T>> {
private static final Logger LOGGER = LogUtils.getLogger();
- protected final Properties properties;
+ public final Properties properties;
+ // CraftBukkit start
+ private OptionSet options = null;
public Settings(Properties properties) {
this.properties = properties;
}
+ private String getOverride(String name, String value) {
+ if ((this.options != null) && (this.options.has(name))) {
+ return String.valueOf(this.options.valueOf(name));
+ }
+
+ return value;
+ // CraftBukkit end
+ }
+
public static Properties loadFromFile(Path path) {
try {
+ // CraftBukkit start - SPIGOT-7465, MC-264979: Don't load if file doesn't exist
+ if (!path.toFile().exists()) {
+ return new Properties();
+ }
+ // CraftBukkit end
Properties properties;
Properties properties1;
@@ -97,6 +117,11 @@
public void store(Path path) {
try {
+ // CraftBukkit start - Don't attempt writing to file if it's read only
+ if (path.toFile().exists() && !path.toFile().canWrite()) {
+ return;
+ }
+ // CraftBukkit end
BufferedWriter bufferedwriter = Files.newBufferedWriter(path, StandardCharsets.UTF_8);
try {
@@ -143,8 +168,8 @@
}
@Nullable
- private String getStringRaw(String s) {
- return (String) this.properties.get(s);
+ private String getStringRaw(String key) {
+ return (String) getOverride(key, this.properties.getProperty(key)); // CraftBukkit
}
@Nullable
@@ -159,7 +184,17 @@
}
}
- protected <V> V get(String s, Function<String, V> function, Function<V, String> function1, V v0) {
+ protected <V> V get(String key, Function<String, V> mapper, Function<V, String> toString, V value) {
+ // CraftBukkit start
+ try {
+ return get0(key, mapper, toString, value);
+ } catch (Exception ex) {
+ throw new RuntimeException("Could not load invalidly configured property '" + key + "'", ex);
+ }
+ }
+
+ private <V> V get0(String s, Function<String, V> function, Function<V, String> function1, V v0) {
+ // CraftBukkit end
String s1 = this.getStringRaw(s);
V v1 = MoreObjects.firstNonNull(s1 != null ? function.apply(s1) : null, v0);
@@ -236,7 +271,7 @@
return properties;
}
- protected abstract T reload(RegistryAccess registryAccess, Properties properties);
+ protected abstract T reload(RegistryAccess iregistrycustom, Properties properties, OptionSet optionset); // CraftBukkit
public class MutableValue<V> implements Supplier<V> {
@@ -258,8 +292,8 @@
public T update(RegistryAccess registryaccess, V v0) {
Properties properties = Settings.this.cloneProperties();
- properties.put(this.key, this.serializer.apply(v0));
- return Settings.this.reload(registryaccess, properties);
+ properties.put(this.key, this.serializer.apply(newValue));
+ return Settings.this.reload(registryAccess, properties, Settings.this.options); // CraftBukkit
}
}
}

View file

@ -0,0 +1,21 @@
--- a/net/minecraft/server/gui/MinecraftServerGui.java
+++ b/net/minecraft/server/gui/MinecraftServerGui.java
@@ -168,7 +166,8 @@
this.finalizers.forEach(Runnable::run);
}
- public void print(JTextArea jtextarea, JScrollPane jscrollpane, String s) {
+ private static final java.util.regex.Pattern ANSI = java.util.regex.Pattern.compile("\\x1B\\[([0-9]{1,2}(;[0-9]{1,2})*)?[m|K]"); // CraftBukkit
+ public void print(JTextArea textArea, JScrollPane scrollPane, String line) {
if (!SwingUtilities.isEventDispatchThread()) {
SwingUtilities.invokeLater(() -> {
this.print(jtextarea, jscrollpane, s);
@@ -183,7 +182,7 @@
}
try {
- document.insertString(document.getLength(), s, (AttributeSet) null);
+ document.insertString(document.getLength(), ANSI.matcher(line).replaceAll(""), (AttributeSet) null); // CraftBukkit
} catch (BadLocationException badlocationexception) {
;
}

View file

@ -0,0 +1,122 @@
--- a/net/minecraft/server/level/ChunkHolder.java
+++ b/net/minecraft/server/level/ChunkHolder.java
@@ -36,6 +36,10 @@
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.lighting.LevelLightEngine;
+// CraftBukkit start
+import net.minecraft.server.MinecraftServer;
+// CraftBukkit end
+
public class ChunkHolder {
public static final Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> UNLOADED_CHUNK = Either.right(ChunkHolder.ChunkLoadingFailure.UNLOADED);
@@ -90,9 +94,23 @@
this.changedBlocksPerSection = new ShortSet[levelheightaccessor.getSectionsCount()];
}
- public CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> getFutureIfPresentUnchecked(ChunkStatus chunkstatus) {
- CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> completablefuture = (CompletableFuture) this.futures.get(chunkstatus.getIndex());
+ // CraftBukkit start
+ public LevelChunk getFullChunkNow() {
+ // Note: We use the oldTicketLevel for isLoaded checks.
+ if (!ChunkLevel.fullStatus(this.oldTicketLevel).isOrAfter(FullChunkStatus.FULL)) return null;
+ return this.getFullChunkNowUnchecked();
+ }
+ public LevelChunk getFullChunkNowUnchecked() {
+ CompletableFuture<Either<ChunkAccess, ChunkHolder.Failure>> statusFuture = this.getFutureIfPresentUnchecked(ChunkStatus.FULL);
+ Either<ChunkAccess, ChunkHolder.Failure> either = (Either<ChunkAccess, ChunkHolder.Failure>) statusFuture.getNow(null);
+ return (either == null) ? null : (LevelChunk) either.left().orElse(null);
+ }
+ // CraftBukkit end
+
+ public CompletableFuture<Either<ChunkAccess, ChunkHolder.Failure>> getFutureIfPresentUnchecked(ChunkStatus chunkStatus) {
+ CompletableFuture<Either<ChunkAccess, ChunkHolder.Failure>> completablefuture = (CompletableFuture) this.futures.get(chunkStatus.getIndex());
+
return completablefuture == null ? ChunkHolder.UNLOADED_CHUNK_FUTURE : completablefuture;
}
@@ -179,6 +197,7 @@
if (levelchunk != null) {
int i = this.levelHeightAccessor.getSectionIndex(blockpos.getY());
+ if (i < 0 || i >= this.changedBlocksPerSection.length) return; // CraftBukkit - SPIGOT-6086, SPIGOT-6296
if (this.changedBlocksPerSection[i] == null) {
this.hasChangedSections = true;
this.changedBlocksPerSection[i] = new ShortOpenHashSet();
@@ -256,9 +275,12 @@
LevelChunkSection levelchunksection = levelchunk.getSection(i);
ClientboundSectionBlocksUpdatePacket clientboundsectionblocksupdatepacket = new ClientboundSectionBlocksUpdatePacket(sectionpos, shortset, levelchunksection);
- this.broadcast(list, clientboundsectionblocksupdatepacket);
- clientboundsectionblocksupdatepacket.runUpdates((blockpos1, blockstate1) -> {
- this.broadcastBlockEntityIfNeeded(list, level, blockpos1, blockstate1);
+ this.broadcast(list, packetplayoutmultiblockchange);
+ // CraftBukkit start
+ List finalList = list;
+ packetplayoutmultiblockchange.runUpdates((blockposition1, iblockdata1) -> {
+ this.broadcastBlockEntityIfNeeded(finalList, world, blockposition1, iblockdata1);
+ // CraftBukkit end
});
}
}
@@ -411,7 +433,31 @@
boolean flag1 = ChunkLevel.isLoaded(this.ticketLevel);
FullChunkStatus fullchunkstatus = ChunkLevel.fullStatus(this.oldTicketLevel);
FullChunkStatus fullchunkstatus1 = ChunkLevel.fullStatus(this.ticketLevel);
+ // CraftBukkit start
+ // ChunkUnloadEvent: Called before the chunk is unloaded: isChunkLoaded is still true and chunk can still be modified by plugins.
+ if (fullchunkstatus.isOrAfter(FullChunkStatus.FULL) && !fullchunkstatus1.isOrAfter(FullChunkStatus.FULL)) {
+ this.getFutureIfPresentUnchecked(ChunkStatus.FULL).thenAccept((either) -> {
+ LevelChunk chunk = (LevelChunk)either.left().orElse(null);
+ if (chunk != null) {
+ chunkMap.callbackExecutor.execute(() -> {
+ // Minecraft will apply the chunks tick lists to the world once the chunk got loaded, and then store the tick
+ // lists again inside the chunk once the chunk becomes inaccessible and set the chunk's needsSaving flag.
+ // These actions may however happen deferred, so we manually set the needsSaving flag already here.
+ chunk.setUnsaved(true);
+ chunk.unloadCallback();
+ });
+ }
+ }).exceptionally((throwable) -> {
+ // ensure exceptions are printed, by default this is not the case
+ MinecraftServer.LOGGER.error("Failed to schedule unload callback for chunk " + ChunkHolder.this.pos, throwable);
+ return null;
+ });
+ // Run callback right away if the future was already done
+ chunkMap.callbackExecutor.run();
+ }
+ // CraftBukkit end
+
if (flag) {
Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> either = Either.right(new ChunkHolder.ChunkLoadingFailure() {
@Override
@@ -482,6 +527,26 @@
this.onLevelChange.onLevelChange(this.pos, this::getQueueLevel, this.ticketLevel, this::setQueueLevel);
this.oldTicketLevel = this.ticketLevel;
+ // CraftBukkit start
+ // ChunkLoadEvent: Called after the chunk is loaded: isChunkLoaded returns true and chunk is ready to be modified by plugins.
+ if (!fullchunkstatus.isOrAfter(FullChunkStatus.FULL) && fullchunkstatus1.isOrAfter(FullChunkStatus.FULL)) {
+ this.getFutureIfPresentUnchecked(ChunkStatus.FULL).thenAccept((either) -> {
+ LevelChunk chunk = (LevelChunk)either.left().orElse(null);
+ if (chunk != null) {
+ chunkMap.callbackExecutor.execute(() -> {
+ chunk.loadCallback();
+ });
+ }
+ }).exceptionally((throwable) -> {
+ // ensure exceptions are printed, by default this is not the case
+ MinecraftServer.LOGGER.error("Failed to schedule load callback for chunk " + ChunkHolder.this.pos, throwable);
+ return null;
+ });
+
+ // Run callback right away if the future was already done
+ chunkMap.callbackExecutor.run();
+ }
+ // CraftBukkit end
}
public boolean wasAccessibleSinceLastSave() {

View file

@ -0,0 +1,147 @@
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -100,6 +100,9 @@
import net.minecraft.world.phys.Vec3;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.slf4j.Logger;
+import org.bukkit.craftbukkit.generator.CustomChunkGenerator;
+import org.bukkit.entity.Player;
+// CraftBukkit end
public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider {
@@ -143,8 +146,29 @@
private final Queue<Runnable> unloadQueue;
private int serverViewDistance;
- public ChunkMap(ServerLevel serverlevel, LevelStorageSource.LevelStorageAccess levelstoragesource_levelstorageaccess, DataFixer datafixer, StructureTemplateManager structuretemplatemanager, Executor executor, BlockableEventLoop<Runnable> blockableeventloop, LightChunkGetter lightchunkgetter, ChunkGenerator chunkgenerator, ChunkProgressListener chunkprogresslistener, ChunkStatusUpdateListener chunkstatusupdatelistener, Supplier<DimensionDataStorage> supplier, int i, boolean flag) {
- super(levelstoragesource_levelstorageaccess.getDimensionPath(serverlevel.dimension()).resolve("region"), datafixer, flag);
+ // CraftBukkit start - recursion-safe executor for Chunk loadCallback() and unloadCallback()
+ public final CallbackExecutor callbackExecutor = new CallbackExecutor();
+ public static final class CallbackExecutor implements java.util.concurrent.Executor, Runnable {
+
+ private final java.util.Queue<Runnable> queue = new java.util.ArrayDeque<>();
+
+ @Override
+ public void execute(Runnable runnable) {
+ queue.add(runnable);
+ }
+
+ @Override
+ public void run() {
+ Runnable task;
+ while ((task = queue.poll()) != null) {
+ task.run();
+ }
+ }
+ };
+ // CraftBukkit end
+
+ public ChunkMap(ServerLevel level, LevelStorageSource.LevelStorageAccess levelStorageAccess, DataFixer fixerUpper, StructureTemplateManager structureManager, Executor dispatcher, BlockableEventLoop<Runnable> mainThreadExecutor, LightChunkGetter lightChunk, ChunkGenerator generator, ChunkProgressListener progressListener, ChunkStatusUpdateListener chunkStatusListener, Supplier<DimensionDataStorage> overworldDataStorage, int viewDistance, boolean sync) {
+ super(levelStorageAccess.getDimensionPath(level.dimension()).resolve("region"), fixerUpper, sync);
this.visibleChunkMap = this.updatingChunkMap.clone();
this.pendingUnloads = new Long2ObjectLinkedOpenHashMap();
this.entitiesInLevel = new LongOpenHashSet();
@@ -159,10 +183,15 @@
Path path = levelstoragesource_levelstorageaccess.getDimensionPath(serverlevel.dimension());
this.storageName = path.getFileName().toString();
- this.level = serverlevel;
- this.generator = chunkgenerator;
- RegistryAccess registryaccess = serverlevel.registryAccess();
- long j = serverlevel.getSeed();
+ this.level = level;
+ this.generator = generator;
+ // CraftBukkit start - SPIGOT-7051: It's a rigged game! Use delegate for random state creation, otherwise it is not so random.
+ if (generator instanceof CustomChunkGenerator) {
+ generator = ((CustomChunkGenerator) generator).getDelegate();
+ }
+ // CraftBukkit end
+ RegistryAccess iregistrycustom = level.registryAccess();
+ long j = level.getSeed();
if (chunkgenerator instanceof NoiseBasedChunkGenerator) {
NoiseBasedChunkGenerator noisebasedchunkgenerator = (NoiseBasedChunkGenerator) chunkgenerator;
@@ -335,8 +364,10 @@
List<ChunkAccess> list3 = Lists.newArrayList();
final int l1 = 0;
- for (Iterator iterator = list2.iterator(); iterator.hasNext(); ++l1) {
- final Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure> either = (Either) iterator.next();
+ for (Iterator iterator = list2.iterator(); iterator.hasNext(); ++cnt) {
+ final int l1 = cnt;
+ // CraftBukkit end
+ final Either<ChunkAccess, ChunkHolder.Failure> either = (Either) iterator.next();
if (either == null) {
throw this.debugFuturesAndCreateReportedException(new IllegalStateException("At least one of the chunk futures were null"), "n/a");
@@ -749,9 +778,23 @@
return chunkstatus1;
}
- private static void postLoadProtoChunk(ServerLevel serverlevel, List<CompoundTag> list) {
- if (!list.isEmpty()) {
- serverlevel.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(list, serverlevel));
+ private static void postLoadProtoChunk(ServerLevel level, List<CompoundTag> tags) {
+ if (!tags.isEmpty()) {
+ // CraftBukkit start - these are spawned serialized (DefinedStructure) and we don't call an add event below at the moment due to ordering complexities
+ level.addWorldGenChunkEntities(EntityType.loadEntitiesRecursive(tags, level).filter((entity) -> {
+ boolean needsRemoval = false;
+ net.minecraft.server.dedicated.DedicatedServer server = level.getCraftServer().getServer();
+ if (!server.areNpcsEnabled() && entity instanceof net.minecraft.world.entity.npc.NPC) {
+ entity.discard();
+ needsRemoval = true;
+ }
+ if (!server.isSpawningAnimals() && (entity instanceof net.minecraft.world.entity.animal.Animal || entity instanceof net.minecraft.world.entity.animal.WaterAnimal)) {
+ entity.discard();
+ needsRemoval = true;
+ }
+ return !needsRemoval;
+ }));
+ // CraftBukkit end
}
}
@@ -1047,14 +1091,16 @@
}
}
- private CompletableFuture<Optional<CompoundTag>> readChunk(ChunkPos chunkpos) {
- return this.read(chunkpos).thenApplyAsync((optional) -> {
- return optional.map(this::upgradeChunkTag);
+ private CompletableFuture<Optional<CompoundTag>> readChunk(ChunkPos pos) {
+ return this.read(pos).thenApplyAsync((optional) -> {
+ return optional.map((nbttagcompound) -> upgradeChunkTag(nbttagcompound, pos)); // CraftBukkit
}, Util.backgroundExecutor());
}
- private CompoundTag upgradeChunkTag(CompoundTag compoundtag) {
- return this.upgradeChunkTag(this.level.dimension(), this.overworldDataStorage, compoundtag, this.generator.getTypeNameForDataFixer());
+ // CraftBukkit start
+ private CompoundTag upgradeChunkTag(CompoundTag nbttagcompound, ChunkPos chunkcoordintpair) {
+ return this.upgradeChunkTag(this.level.getTypeKey(), this.overworldDataStorage, nbttagcompound, this.generator.getTypeNameForDataFixer(), chunkcoordintpair, level);
+ // CraftBukkit end
}
boolean anyPlayerCloseEnoughForSpawning(ChunkPos chunkpos) {
@@ -1467,7 +1509,7 @@
private final Set<ServerPlayerConnection> seenBy = Sets.newIdentityHashSet();
public TrackedEntity(Entity entity, int i, int j, boolean flag) {
- this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast);
+ this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, seenBy); // CraftBukkit
this.entity = entity;
this.range = i;
this.lastSectionPos = SectionPos.of((EntityAccess) entity);
@@ -1529,6 +1569,11 @@
double d2 = d0 * d0;
boolean flag = d1 <= d2 && this.entity.broadcastToPlayer(serverplayer) && ChunkMap.this.isChunkTracked(serverplayer, this.entity.chunkPosition().x, this.entity.chunkPosition().z);
+ // CraftBukkit start - respect vanish API
+ if (!player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) {
+ flag = false;
+ }
+ // CraftBukkit end
if (flag) {
if (this.seenBy.add(serverplayer.connection)) {
this.serverEntity.addPairing(serverplayer);

View file

@ -0,0 +1,149 @@
--- a/net/minecraft/server/level/DistanceManager.java
+++ b/net/minecraft/server/level/DistanceManager.java
@@ -122,10 +122,25 @@
}
if (!this.chunksToUpdateFutures.isEmpty()) {
- this.chunksToUpdateFutures.forEach((chunkholder) -> {
- chunkholder.updateFutures(chunkmap, this.mainThreadExecutor);
- });
- this.chunksToUpdateFutures.clear();
+ // CraftBukkit start
+ // Iterate pending chunk updates with protection against concurrent modification exceptions
+ java.util.Iterator<ChunkHolder> iter = this.chunksToUpdateFutures.iterator();
+ int expectedSize = this.chunksToUpdateFutures.size();
+ do {
+ ChunkHolder playerchunk = iter.next();
+ iter.remove();
+ expectedSize--;
+
+ playerchunk.updateFutures(chunkManager, this.mainThreadExecutor);
+
+ // Reset iterator if set was modified using add()
+ if (this.chunksToUpdateFutures.size() != expectedSize) {
+ expectedSize = this.chunksToUpdateFutures.size();
+ iter = this.chunksToUpdateFutures.iterator();
+ }
+ } while (iter.hasNext());
+ // CraftBukkit end
+
return true;
} else {
if (!this.ticketsToRelease.isEmpty()) {
@@ -161,30 +176,33 @@
}
}
- void addTicket(long i, Ticket<?> ticket) {
- SortedArraySet<Ticket<?>> sortedarrayset = this.getTickets(i);
- int j = getTicketLevelAt(sortedarrayset);
- Ticket<?> ticket1 = (Ticket) sortedarrayset.addOrGet(ticket);
+ boolean addTicket(long i, Ticket<?> ticket) { // CraftBukkit - void -> boolean
+ SortedArraySet<Ticket<?>> arraysetsorted = this.getTickets(i);
+ int j = getTicketLevelAt(arraysetsorted);
+ Ticket<?> ticket1 = (Ticket) arraysetsorted.addOrGet(ticket);
ticket1.setCreatedTick(this.ticketTickCounter);
if (ticket.getTicketLevel() < j) {
this.ticketTracker.update(i, ticket.getTicketLevel(), true);
}
+ return ticket == ticket1; // CraftBukkit
}
- void removeTicket(long i, Ticket<?> ticket) {
- SortedArraySet<Ticket<?>> sortedarrayset = this.getTickets(i);
+ boolean removeTicket(long i, Ticket<?> ticket) { // CraftBukkit - void -> boolean
+ SortedArraySet<Ticket<?>> arraysetsorted = this.getTickets(i);
- if (sortedarrayset.remove(ticket)) {
- ;
+ boolean removed = false; // CraftBukkit
+ if (arraysetsorted.remove(ticket)) {
+ removed = true; // CraftBukkit
}
if (sortedarrayset.isEmpty()) {
this.tickets.remove(i);
}
- this.ticketTracker.update(i, getTicketLevelAt(sortedarrayset), false);
+ this.ticketTracker.update(i, getTicketLevelAt(arraysetsorted), false);
+ return removed; // CraftBukkit
}
public <T> void addTicket(TicketType<T> tickettype, ChunkPos chunkpos, int i, T t0) {
@@ -197,20 +215,34 @@
this.removeTicket(chunkpos.toLong(), ticket);
}
- public <T> void addRegionTicket(TicketType<T> tickettype, ChunkPos chunkpos, int i, T t0) {
+ public <T> void addRegionTicket(TicketType<T> type, ChunkPos pos, int distance, T value) {
+ // CraftBukkit start
+ addRegionTicketAtDistance(type, pos, distance, value);
+ }
+
+ public <T> boolean addRegionTicketAtDistance(TicketType<T> tickettype, ChunkPos chunkcoordintpair, int i, T t0) {
+ // CraftBukkit end
Ticket<T> ticket = new Ticket<>(tickettype, ChunkLevel.byStatus(FullChunkStatus.FULL) - i, t0);
long j = chunkpos.toLong();
- this.addTicket(j, ticket);
+ boolean added = this.addTicket(j, ticket); // CraftBukkit
this.tickingTicketsTracker.addTicket(j, ticket);
+ return added; // CraftBukkit
}
- public <T> void removeRegionTicket(TicketType<T> tickettype, ChunkPos chunkpos, int i, T t0) {
+ public <T> void removeRegionTicket(TicketType<T> type, ChunkPos pos, int distance, T value) {
+ // CraftBukkit start
+ removeRegionTicketAtDistance(type, pos, distance, value);
+ }
+
+ public <T> boolean removeRegionTicketAtDistance(TicketType<T> tickettype, ChunkPos chunkcoordintpair, int i, T t0) {
+ // CraftBukkit end
Ticket<T> ticket = new Ticket<>(tickettype, ChunkLevel.byStatus(FullChunkStatus.FULL) - i, t0);
long j = chunkpos.toLong();
- this.removeTicket(j, ticket);
+ boolean removed = this.removeTicket(j, ticket); // CraftBukkit
this.tickingTicketsTracker.removeTicket(j, ticket);
+ return removed; // CraftBukkit
}
private SortedArraySet<Ticket<?>> getTickets(long i) {
@@ -249,6 +281,7 @@
ChunkPos chunkpos = sectionpos.chunk();
long i = chunkpos.toLong();
ObjectSet<ServerPlayer> objectset = (ObjectSet) this.playersPerChunk.get(i);
+ if (objectset == null) return; // CraftBukkit - SPIGOT-6208
objectset.remove(serverplayer);
if (objectset.isEmpty()) {
@@ -378,6 +411,26 @@
return !this.tickets.isEmpty();
}
+ // CraftBukkit start
+ public <T> void removeAllTicketsFor(TicketType<T> ticketType, int ticketLevel, T ticketIdentifier) {
+ Ticket<T> target = new Ticket<>(ticketType, ticketLevel, ticketIdentifier);
+
+ for (java.util.Iterator<Entry<SortedArraySet<Ticket<?>>>> iterator = this.tickets.long2ObjectEntrySet().fastIterator(); iterator.hasNext();) {
+ Entry<SortedArraySet<Ticket<?>>> entry = iterator.next();
+ SortedArraySet<Ticket<?>> tickets = entry.getValue();
+ if (tickets.remove(target)) {
+ // copied from removeTicket
+ this.ticketTracker.update(entry.getLongKey(), getTicketLevelAt(tickets), false);
+
+ // can't use entry after it's removed
+ if (tickets.isEmpty()) {
+ iterator.remove();
+ }
+ }
+ }
+ }
+ // CraftBukkit end
+
private class ChunkTicketTracker extends ChunkTracker {
private static final int MAX_LEVEL = ChunkLevel.MAX_LEVEL + 1;

View file

@ -0,0 +1,139 @@
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -83,6 +83,16 @@
this.clearCache();
}
+ // CraftBukkit start - properly implement isChunkLoaded
+ public boolean isChunkLoaded(int chunkX, int chunkZ) {
+ ChunkHolder chunk = this.chunkMap.getUpdatingChunkIfPresent(ChunkPos.asLong(chunkX, chunkZ));
+ if (chunk == null) {
+ return false;
+ }
+ return chunk.getFullChunkNow() != null;
+ }
+ // CraftBukkit end
+
@Override
@Override
public ThreadedLevelLightEngine getLightEngine() {
@@ -127,10 +135,10 @@
ChunkAccess chunkaccess;
for (int l = 0; l < 4; ++l) {
- if (k == this.lastChunkPos[l] && chunkstatus == this.lastChunkStatus[l]) {
- chunkaccess = this.lastChunk[l];
- if (chunkaccess != null || !flag) {
- return chunkaccess;
+ if (k == this.lastChunkPos[l] && requiredStatus == this.lastChunkStatus[l]) {
+ ichunkaccess = this.lastChunk[l];
+ if (ichunkaccess != null) { // CraftBukkit - the chunk can become accessible in the meantime TODO for non-null chunks it might also make sense to check that the chunk's state hasn't changed in the meantime
+ return ichunkaccess;
}
}
}
@@ -231,10 +238,18 @@
int l = ChunkLevel.byStatus(chunkstatus);
ChunkHolder chunkholder = this.getVisibleChunkIfPresent(k);
- if (flag) {
- this.distanceManager.addTicket(TicketType.UNKNOWN, chunkpos, l, chunkpos);
- if (this.chunkAbsent(chunkholder, l)) {
- ProfilerFiller profilerfiller = this.level.getProfiler();
+ // CraftBukkit start - don't add new ticket for currently unloading chunk
+ boolean currentlyUnloading = false;
+ if (playerchunk != null) {
+ FullChunkStatus oldChunkState = ChunkLevel.fullStatus(playerchunk.oldTicketLevel);
+ FullChunkStatus currentChunkState = ChunkLevel.fullStatus(playerchunk.getTicketLevel());
+ currentlyUnloading = (oldChunkState.isOrAfter(FullChunkStatus.FULL) && !currentChunkState.isOrAfter(FullChunkStatus.FULL));
+ }
+ if (load && !currentlyUnloading) {
+ // CraftBukkit end
+ this.distanceManager.addTicket(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair);
+ if (this.chunkAbsent(playerchunk, l)) {
+ ProfilerFiller gameprofilerfiller = this.level.getProfiler();
profilerfiller.push("chunkLoad");
this.runDistanceManagerUpdates();
@@ -249,8 +264,8 @@
return this.chunkAbsent(chunkholder, l) ? ChunkHolder.UNLOADED_CHUNK_FUTURE : chunkholder.getOrScheduleFuture(chunkstatus, this.chunkMap);
}
- private boolean chunkAbsent(@Nullable ChunkHolder chunkholder, int i) {
- return chunkholder == null || chunkholder.getTicketLevel() > i;
+ private boolean chunkAbsent(@Nullable ChunkHolder chunkHolder, int status) {
+ return chunkHolder == null || chunkHolder.oldTicketLevel > status; // CraftBukkit using oldTicketLevel for isLoaded checks
}
@Override
@@ -335,11 +346,31 @@
@Override
@Override
public void close() throws IOException {
- this.save(true);
+ // CraftBukkit start
+ close(true);
+ }
+
+ public void close(boolean save) throws IOException {
+ if (save) {
+ this.save(true);
+ }
+ // CraftBukkit end
this.lightEngine.close();
this.chunkMap.close();
}
+ // CraftBukkit start - modelled on below
+ public void purgeUnload() {
+ this.level.getProfiler().push("purge");
+ this.distanceManager.purgeStaleTickets();
+ this.runDistanceManagerUpdates();
+ this.level.getProfiler().popPush("unload");
+ this.chunkMap.tick(() -> true);
+ this.level.getProfiler().pop();
+ this.clearCache();
+ }
+ // CraftBukkit end
+
@Override
@Override
public void tick(BooleanSupplier booleansupplier, boolean flag) {
@@ -385,13 +415,13 @@
int k = this.distanceManager.getNaturalSpawnChunkCount();
NaturalSpawner.SpawnState naturalspawner_spawnstate = NaturalSpawner.createState(k, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap));
- this.lastSpawnState = naturalspawner_spawnstate;
- profilerfiller.popPush("spawnAndTick");
- boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING);
+ this.lastSpawnState = spawnercreature_d;
+ gameprofilerfiller.popPush("spawnAndTick");
+ boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
Util.shuffle(list, this.level.random);
int l = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
- boolean flag1 = this.level.getLevelData().getGameTime() % 400L == 0L;
+ boolean flag1 = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getLevelData().getGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit
Iterator iterator1 = list.iterator();
while (iterator1.hasNext()) {
@@ -604,7 +624,9 @@
}
@Override
- protected boolean pollTask() {
+ // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task
+ public boolean pollTask() {
+ try {
if (ServerChunkCache.this.runDistanceManagerUpdates()) {
return true;
} else {
@@ -612,6 +636,8 @@
return super.pollTask();
}
}
+ // CraftBukkit end
+ }
}
private static record ChunkAndHolder(LevelChunk chunk, ChunkHolder holder) {

View file

@ -0,0 +1,146 @@
--- a/net/minecraft/server/level/ServerEntity.java
+++ b/net/minecraft/server/level/ServerEntity.java
@@ -42,6 +41,13 @@
import net.minecraft.world.phys.Vec3;
import org.slf4j.Logger;
+// CraftBukkit start
+import net.minecraft.server.network.ServerPlayerConnection;
+import net.minecraft.util.Mth;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerVelocityEvent;
+// CraftBukkit end
+
public class ServerEntity {
private static final Logger LOGGER = LogUtils.getLogger();
@@ -66,8 +72,12 @@
private boolean wasOnGround;
@Nullable
private List<SynchedEntityData.DataValue<?>> trackedDataValues;
+ // CraftBukkit start
+ private final Set<ServerPlayerConnection> trackedPlayers;
- public ServerEntity(ServerLevel serverlevel, Entity entity, int i, boolean flag, Consumer<Packet<?>> consumer) {
+ public ServerEntity(ServerLevel worldserver, Entity entity, int i, boolean flag, Consumer<Packet<?>> consumer, Set<ServerPlayerConnection> trackedPlayers) {
+ this.trackedPlayers = trackedPlayers;
+ // CraftBukkit end
this.ap = Vec3.ZERO;
this.lastPassengers = Collections.emptyList();
this.level = serverlevel;
@@ -87,7 +97,7 @@
List<Entity> list = this.entity.getPassengers();
if (!list.equals(this.lastPassengers)) {
- this.broadcast.accept(new ClientboundSetPassengersPacket(this.entity));
+ this.broadcastAndSend(new ClientboundSetPassengersPacket(this.entity)); // CraftBukkit
removedPassengers(list, this.lastPassengers).forEach((entity) -> {
if (entity instanceof ServerPlayer) {
ServerPlayer serverplayer = (ServerPlayer) entity;
@@ -104,18 +114,18 @@
if (entity instanceof ItemFrame) {
ItemFrame itemframe = (ItemFrame) entity;
- if (this.tickCount % 10 == 0) {
- ItemStack itemstack = itemframe.getItem();
+ if (true || this.tickCount % 10 == 0) { // CraftBukkit - Moved below, should always enter this block
+ ItemStack itemstack = entityitemframe.getItem();
- if (itemstack.getItem() instanceof MapItem) {
+ if (this.tickCount % 10 == 0 && itemstack.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks
Integer integer = MapItem.getMapId(itemstack);
MapItemSavedData mapitemsaveddata = MapItem.getSavedData(integer, this.level);
- if (mapitemsaveddata != null) {
- Iterator iterator = this.level.players().iterator();
+ if (worldmap != null) {
+ Iterator<ServerPlayerConnection> iterator = this.trackedPlayers.iterator(); // CraftBukkit
while (iterator.hasNext()) {
- ServerPlayer serverplayer = (ServerPlayer) iterator.next();
+ ServerPlayer entityplayer = iterator.next().getPlayer(); // CraftBukkit
mapitemsaveddata.tickCarriedBy(serverplayer, itemstack);
Packet<?> packet = mapitemsaveddata.getUpdatePacket(integer, serverplayer);
@@ -228,7 +238,27 @@
++this.tickCount;
if (this.entity.hurtMarked) {
- this.broadcastAndSend(new ClientboundSetEntityMotionPacket(this.entity));
+ // CraftBukkit start - Create PlayerVelocity event
+ boolean cancelled = false;
+
+ if (this.entity instanceof ServerPlayer) {
+ Player player = (Player) this.entity.getBukkitEntity();
+ org.bukkit.util.Vector velocity = player.getVelocity();
+
+ PlayerVelocityEvent event = new PlayerVelocityEvent(player, velocity.clone());
+ this.entity.level().getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ cancelled = true;
+ } else if (!velocity.equals(event.getVelocity())) {
+ player.setVelocity(event.getVelocity());
+ }
+ }
+
+ if (!cancelled) {
+ this.broadcastAndSend(new ClientboundSetEntityMotionPacket(this.entity));
+ }
+ // CraftBukkit end
this.entity.hurtMarked = false;
}
@@ -256,7 +286,10 @@
public void sendPairingData(ServerPlayer serverplayer, Consumer<Packet<ClientGamePacketListener>> consumer) {
if (this.entity.isRemoved()) {
- ServerEntity.LOGGER.warn("Fetching packet for removed entity {}", this.entity);
+ // CraftBukkit start - Remove useless error spam, just return
+ // EntityTrackerEntry.LOGGER.warn("Fetching packet for removed entity {}", this.entity);
+ return;
+ // CraftBukkit end
}
Packet<ClientGamePacketListener> packet = this.entity.getAddEntityPacket();
@@ -272,6 +305,12 @@
if (this.entity instanceof LivingEntity) {
Collection<AttributeInstance> collection = ((LivingEntity) this.entity).getAttributes().getSyncableAttributes();
+ // CraftBukkit start - If sending own attributes send scaled health instead of current maximum health
+ if (this.entity.getId() == player.getId()) {
+ ((ServerPlayer) this.entity).getBukkitEntity().injectScaledMaxHealth(collection, false);
+ }
+ // CraftBukkit end
+
if (!collection.isEmpty()) {
consumer.accept(new ClientboundUpdateAttributesPacket(this.entity.getId(), collection));
}
@@ -303,8 +342,15 @@
if (!list.isEmpty()) {
consumer.accept(new ClientboundSetEquipmentPacket(this.entity.getId(), list));
}
+ ((LivingEntity) this.entity).detectEquipmentUpdatesPublic(); // CraftBukkit - SPIGOT-3789: sync again immediately after sending
}
+ // CraftBukkit start - MC-109346: Fix for nonsensical head yaw
+ if (this.entity instanceof ServerPlayer) {
+ consumer.accept(new ClientboundRotateHeadPacket(this.entity, (byte) Mth.floor(this.entity.getYHeadRot() * 256.0F / 360.0F)));
+ }
+ // CraftBukkit end
+
if (!this.entity.getPassengers().isEmpty()) {
consumer.accept(new ClientboundSetPassengersPacket(this.entity));
}
@@ -338,6 +384,11 @@
Set<AttributeInstance> set = ((LivingEntity) this.entity).getAttributes().getDirtyAttributes();
if (!set.isEmpty()) {
+ // CraftBukkit start - Send scaled max health
+ if (this.entity instanceof ServerPlayer) {
+ ((ServerPlayer) this.entity).getBukkitEntity().injectScaledMaxHealth(set, false);
+ }
+ // CraftBukkit end
this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), set));
}

View file

@ -0,0 +1,657 @@
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -163,6 +164,19 @@
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.ticks.LevelTicks;
import org.slf4j.Logger;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.WeatherType;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.craftbukkit.generator.CustomWorldChunkManager;
+import org.bukkit.craftbukkit.util.CraftNamespacedKey;
+import org.bukkit.craftbukkit.util.WorldUUID;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.event.server.MapInitializeEvent;
+import org.bukkit.event.weather.LightningStrikeEvent;
+import org.bukkit.event.world.GenericGameEvent;
+import org.bukkit.event.world.TimeSkipEvent;
+// CraftBukkit end
public class ServerLevel extends Level implements WorldGenLevel {
@@ -177,7 +191,7 @@
final List<ServerPlayer> players;
private final ServerChunkCache chunkSource;
private final MinecraftServer server;
- private final ServerLevelData serverLevelData;
+ public final PrimaryLevelData serverLevelData; // CraftBukkit - type
final EntityTickList entityTickList;
private final PersistentEntitySectionManager<Entity> entityManager;
private final GameEventDispatcher gameEventDispatcher;
@@ -202,12 +216,30 @@
private final boolean tickTime;
private final RandomSequences randomSequences;
- public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess levelstoragesource_levelstorageaccess, ServerLevelData serverleveldata, ResourceKey<Level> resourcekey, LevelStem levelstem, ChunkProgressListener chunkprogresslistener, boolean flag, long i, List<CustomSpawner> list, boolean flag1, @Nullable RandomSequences randomsequences) {
- RegistryAccess.Frozen registryaccess_frozen = minecraftserver.registryAccess();
- Holder holder = levelstem.type();
+ // CraftBukkit start
+ public final LevelStorageSource.LevelStorageAccess convertable;
+ public final UUID uuid;
- Objects.requireNonNull(minecraftserver);
- super(serverleveldata, resourcekey, registryaccess_frozen, holder, minecraftserver::getProfiler, false, flag, i, minecraftserver.getMaxChainedNeighborUpdates());
+ public LevelChunk getChunkIfLoaded(int x, int z) {
+ return this.chunkSource.getChunk(x, z, false);
+ }
+
+ @Override
+ public ResourceKey<LevelStem> getTypeKey() {
+ return convertable.dimensionType;
+ }
+
+ // Add env and gen to constructor, IWorldDataServer -> WorldDataServer
+ public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey<Level> resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List<CustomSpawner> list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) {
+ // IRegistryCustom.Dimension iregistrycustom_dimension = minecraftserver.registryAccess(); // CraftBukkit - decompile error
+ // Holder holder = worlddimension.type(); // CraftBukkit - decompile error
+
+ // Objects.requireNonNull(minecraftserver); // CraftBukkit - decompile error
+ super(iworlddataserver, resourcekey, minecraftserver.registryAccess(), worlddimension.type(), minecraftserver::getProfiler, false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env);
+ this.pvpMode = minecraftserver.isPvpAllowed();
+ convertable = convertable_conversionsession;
+ uuid = WorldUUID.getUUID(convertable_conversionsession.levelDirectory.path().toFile());
+ // CraftBukkit end
this.players = Lists.newArrayList();
this.entityTickList = new EntityTickList();
this.blockTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded, this.getProfilerSupplier());
@@ -219,8 +251,24 @@
this.tickTime = flag1;
this.server = minecraftserver;
this.customSpawners = list;
- this.serverLevelData = serverleveldata;
- ChunkGenerator chunkgenerator = levelstem.generator();
+ this.serverLevelData = iworlddataserver;
+ ChunkGenerator chunkgenerator = worlddimension.generator();
+ // CraftBukkit start
+ serverLevelData.setWorld(this);
+
+ if (biomeProvider != null) {
+ BiomeSource worldChunkManager = new CustomWorldChunkManager(getWorld(), biomeProvider, server.registryAccess().registryOrThrow(Registries.BIOME));
+ if (chunkgenerator instanceof NoiseBasedChunkGenerator cga) {
+ chunkgenerator = new NoiseBasedChunkGenerator(worldChunkManager, cga.settings);
+ } else if (chunkgenerator instanceof FlatLevelSource cpf) {
+ chunkgenerator = new FlatLevelSource(cpf.settings(), worldChunkManager);
+ }
+ }
+
+ if (gen != null) {
+ chunkgenerator = new org.bukkit.craftbukkit.generator.CustomChunkGenerator(this, chunkgenerator, gen);
+ }
+ // CraftBukkit end
boolean flag2 = minecraftserver.forceSynchronousWrites();
DataFixer datafixer = minecraftserver.getFixerUpper();
EntityPersistentStorage<Entity> entitypersistentstorage = new EntityStorage(this, levelstoragesource_levelstorageaccess.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, minecraftserver);
@@ -248,9 +296,9 @@
long l = minecraftserver.getWorldData().worldGenOptions().seed();
this.structureCheck = new StructureCheck(this.chunkSource.chunkScanner(), this.registryAccess(), minecraftserver.getStructureManager(), resourcekey, chunkgenerator, this.chunkSource.randomState(), this, chunkgenerator.getBiomeSource(), l, datafixer);
- this.structureManager = new StructureManager(this, minecraftserver.getWorldData().worldGenOptions(), this.structureCheck);
- if (this.dimension() == Level.END && this.dimensionTypeRegistration().is(BuiltinDimensionTypes.END)) {
- this.dragonFight = new EndDragonFight(this, l, minecraftserver.getWorldData().endDragonFightData());
+ this.structureManager = new StructureManager(this, this.serverLevelData.worldGenOptions(), structureCheck); // CraftBukkit
+ if ((this.dimension() == Level.END && this.dimensionTypeRegistration().is(BuiltinDimensionTypes.END)) || env == org.bukkit.World.Environment.THE_END) { // CraftBukkit - Allow to create EnderDragonBattle in default and custom END
+ this.dragonFight = new EndDragonFight(this, this.serverLevelData.worldGenOptions().seed(), this.serverLevelData.endDragonFightData()); // CraftBukkit
} else {
this.dragonFight = null;
}
@@ -260,6 +308,7 @@
this.randomSequences = (RandomSequences) Objects.requireNonNullElseGet(randomsequences, () -> {
return (RandomSequences) this.getDataStorage().computeIfAbsent(RandomSequences.factory(l), "random_sequences");
});
+ this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
}
/** @deprecated */
@@ -305,12 +353,18 @@
long j;
if (this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) {
+ // CraftBukkit start
+ j = this.levelData.getDayTime() + 24000L;
+ TimeSkipEvent event = new TimeSkipEvent(this.getWorld(), TimeSkipEvent.SkipReason.NIGHT_SKIP, (j - j % 24000L) - this.getDayTime());
if (this.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) {
j = this.levelData.getDayTime() + 24000L;
this.setDayTime(j - j % 24000L);
}
- this.wakeUpAllPlayers();
+ if (!event.isCancelled()) {
+ this.wakeUpAllPlayers();
+ }
+ // CraftBukkit end
if (this.getGameRules().getBoolean(GameRules.RULE_WEATHER_CYCLE) && this.isRaining()) {
this.resetWeatherCycle();
}
@@ -344,8 +400,8 @@
}
this.handlingTick = false;
- profilerfiller.pop();
- boolean flag1 = !this.players.isEmpty() || !this.getForcedChunks().isEmpty();
+ gameprofilerfiller.pop();
+ boolean flag1 = true || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players
if (flag1) {
this.resetEmptyTime();
@@ -361,7 +417,7 @@
this.entityTickList.forEach((entity) -> {
if (!entity.isRemoved()) {
- if (this.shouldDiscardEntity(entity)) {
+ if (false && this.shouldDiscardEntity(entity)) { // CraftBukkit - We prevent spawning in general, so this butchering is not needed
entity.discard();
} else if (!tickratemanager.isEntityFrozen(entity)) {
profilerfiller.push("checkDespawn");
@@ -457,20 +512,20 @@
if (flag1) {
SkeletonHorse skeletonhorse = (SkeletonHorse) EntityType.SKELETON_HORSE.create(this);
- if (skeletonhorse != null) {
- skeletonhorse.setTrap(true);
- skeletonhorse.setAge(0);
- skeletonhorse.setPos((double) blockpos.getX(), (double) blockpos.getY(), (double) blockpos.getZ());
- this.addFreshEntity(skeletonhorse);
+ if (entityhorseskeleton != null) {
+ entityhorseskeleton.setTrap(true);
+ entityhorseskeleton.setAge(0);
+ entityhorseskeleton.setPos((double) blockposition.getX(), (double) blockposition.getY(), (double) blockposition.getZ());
+ this.addFreshEntity(entityhorseskeleton, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.LIGHTNING); // CraftBukkit
}
}
LightningBolt lightningbolt = (LightningBolt) EntityType.LIGHTNING_BOLT.create(this);
- if (lightningbolt != null) {
- lightningbolt.moveTo(Vec3.atBottomCenterOf(blockpos));
- lightningbolt.setVisualOnly(flag1);
- this.addFreshEntity(lightningbolt);
+ if (entitylightning != null) {
+ entitylightning.moveTo(Vec3.atBottomCenterOf(blockposition));
+ entitylightning.setVisualOnly(flag1);
+ this.strikeLightning(entitylightning, org.bukkit.event.weather.LightningStrikeEvent.Cause.WEATHER); // CraftBukkit
}
}
}
@@ -525,8 +580,8 @@
BlockPos blockpos2 = blockpos1.below();
Biome biome = (Biome) this.getBiome(blockpos1).value();
- if (biome.shouldFreeze(this, blockpos2)) {
- this.setBlockAndUpdate(blockpos2, Blocks.ICE.defaultBlockState());
+ if (biomebase.shouldFreeze(this, blockposition2)) {
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition2, Blocks.ICE.defaultBlockState(), null); // CraftBukkit
}
if (this.isRaining()) {
@@ -541,11 +596,11 @@
if (j < Math.min(i, 8)) {
BlockState blockstate1 = (BlockState) blockstate.setValue(SnowLayerBlock.LAYERS, j + 1);
- Block.pushEntitiesUp(blockstate, blockstate1, this, blockpos1);
- this.setBlockAndUpdate(blockpos1, blockstate1);
+ Block.pushEntitiesUp(iblockdata, iblockdata1, this, blockposition1);
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition1, iblockdata1, null); // CraftBukkit
}
} else {
- this.setBlockAndUpdate(blockpos1, Blocks.SNOW.defaultBlockState());
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this, blockposition1, Blocks.SNOW.defaultBlockState(), null); // CraftBukkit
}
}
@@ -707,6 +761,7 @@
this.rainLevel = Mth.clamp(this.rainLevel, 0.0F, 1.0F);
}
+ /* CraftBukkit start
if (this.oRainLevel != this.rainLevel) {
this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, this.rainLevel), this.dimension());
}
@@ -726,14 +787,41 @@
this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, this.thunderLevel));
}
+ if (flag != this.isRaining()) {
+ // Only send weather packets to those affected
+ for (int idx = 0; idx < this.players.size(); ++idx) {
+ if (((ServerPlayer) this.players.get(idx)).level() == this) {
+ ((ServerPlayer) this.players.get(idx)).setPlayerWeather((!flag ? WeatherType.DOWNFALL : WeatherType.CLEAR), false);
+ }
+ }
+ }
+ for (int idx = 0; idx < this.players.size(); ++idx) {
+ if (((ServerPlayer) this.players.get(idx)).level() == this) {
+ ((ServerPlayer) this.players.get(idx)).updateWeather(this.oRainLevel, this.rainLevel, this.oThunderLevel, this.thunderLevel);
+ }
+ }
+ // CraftBukkit end
+
}
@VisibleForTesting
public void resetWeatherCycle() {
- this.serverLevelData.setRainTime(0);
+ // CraftBukkit start
this.serverLevelData.setRaining(false);
- this.serverLevelData.setThunderTime(0);
+ // If we stop due to everyone sleeping we should reset the weather duration to some other random value.
+ // Not that everyone ever manages to get the whole server to sleep at the same time....
+ if (!this.serverLevelData.isRaining()) {
+ this.serverLevelData.setRainTime(0);
+ }
+ // CraftBukkit end
this.serverLevelData.setThundering(false);
+ // CraftBukkit start
+ // If we stop due to everyone sleeping we should reset the weather duration to some other random value.
+ // Not that everyone ever manages to get the whole server to sleep at the same time....
+ if (!this.serverLevelData.isThundering()) {
+ this.serverLevelData.setThunderTime(0);
+ }
+ // CraftBukkit end
}
public void resetEmptyTime() {
@@ -768,6 +856,7 @@
});
profilerfiller.incrementCounter("tickNonPassenger");
entity.tick();
+ entity.postTick(); // CraftBukkit
this.getProfiler().pop();
Iterator iterator = entity.getPassengers().iterator();
@@ -789,10 +878,11 @@
profilerfiller.push(() -> {
return BuiltInRegistries.ENTITY_TYPE.getKey(entity1.getType()).toString();
});
- profilerfiller.incrementCounter("tickPassenger");
- entity1.rideTick();
- profilerfiller.pop();
- Iterator iterator = entity1.getPassengers().iterator();
+ gameprofilerfiller.incrementCounter("tickPassenger");
+ passengerEntity.rideTick();
+ passengerEntity.postTick(); // CraftBukkit
+ gameprofilerfiller.pop();
+ Iterator iterator = passengerEntity.getPassengers().iterator();
while (iterator.hasNext()) {
Entity entity2 = (Entity) iterator.next();
@@ -815,9 +904,10 @@
public void save(@Nullable ProgressListener progresslistener, boolean flag, boolean flag1) {
ServerChunkCache serverchunkcache = this.getChunkSource();
- if (!flag1) {
- if (progresslistener != null) {
- progresslistener.progressStartNoAbort(Component.translatable("menu.savingLevel"));
+ if (!skipSave) {
+ org.bukkit.Bukkit.getPluginManager().callEvent(new org.bukkit.event.world.WorldSaveEvent(getWorld())); // CraftBukkit
+ if (progress != null) {
+ progress.progressStartNoAbort(Component.translatable("menu.savingLevel"));
}
this.saveLevelData();
@@ -833,11 +923,19 @@
}
}
+
+ // CraftBukkit start - moved from MinecraftServer.saveChunks
+ ServerLevel worldserver1 = this;
+
+ serverLevelData.setWorldBorder(worldserver1.getWorldBorder().createSettings());
+ serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save());
+ convertable.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData());
+ // CraftBukkit end
}
private void saveLevelData() {
if (this.dragonFight != null) {
- this.server.getWorldData().setEndDragonFightData(this.dragonFight.saveData());
+ this.serverLevelData.setEndDragonFightData(this.dragonFight.saveData()); // CraftBukkit
}
this.getChunkSource().getDataStorage().save();
@@ -903,19 +1000,37 @@
@Override
@Override
public boolean addFreshEntity(Entity entity) {
- return this.addEntity(entity);
+ // CraftBukkit start
+ return this.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.DEFAULT);
}
+ @Override
+ public boolean addFreshEntity(Entity entity, CreatureSpawnEvent.SpawnReason reason) {
+ return this.addEntity(entity, reason);
+ // CraftBukkit end
+ }
+
public boolean addWithUUID(Entity entity) {
- return this.addEntity(entity);
+ // CraftBukkit start
+ return this.addWithUUID(entity, CreatureSpawnEvent.SpawnReason.DEFAULT);
}
+ public boolean addWithUUID(Entity entity, CreatureSpawnEvent.SpawnReason reason) {
+ return this.addEntity(entity, reason);
+ // CraftBukkit end
+ }
+
public void addDuringTeleport(Entity entity) {
- this.addEntity(entity);
+ // CraftBukkit start
+ // SPIGOT-6415: Don't call spawn event for entities which travel trough worlds,
+ // since it is only an implementation detail, that a new entity is created when
+ // they are traveling between worlds.
+ this.addDuringTeleport(entity, null);
}
- public void addDuringCommandTeleport(ServerPlayer serverplayer) {
- this.addPlayer(serverplayer);
+ public void addDuringTeleport(Entity entity, CreatureSpawnEvent.SpawnReason reason) {
+ this.addEntity(entity, reason);
+ // CraftBukkit end
}
public void addDuringPortalTeleport(ServerPlayer serverplayer) {
@@ -942,24 +1061,37 @@
this.entityManager.addNewEntity(serverplayer);
}
- private boolean addEntity(Entity entity) {
+ // CraftBukkit start
+ private boolean addEntity(Entity entity, CreatureSpawnEvent.SpawnReason spawnReason) {
if (entity.isRemoved()) {
- ServerLevel.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityType.getKey(entity.getType()));
+ // WorldServer.LOGGER.warn("Tried to add entity {} but it was marked as removed already", EntityTypes.getKey(entity.getType())); // CraftBukkit
return false;
} else {
+ // SPIGOT-6415: Don't call spawn event when reason is null. For example when an entity teleports to a new world.
+ if (spawnReason != null && !CraftEventFactory.doEntityAddEventCalling(this, entity, spawnReason)) {
+ return false;
+ }
+ // CraftBukkit end
+
return this.entityManager.addNewEntity(entity);
}
}
public boolean tryAddFreshEntityWithPassengers(Entity entity) {
- Stream stream = entity.getSelfAndPassengers().map(Entity::getUUID);
+ // CraftBukkit start
+ return this.tryAddFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT);
+ }
+
+ public boolean tryAddFreshEntityWithPassengers(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) {
+ // CraftBukkit end
+ Stream<UUID> stream = entity.getSelfAndPassengers().map(Entity::getUUID); // CraftBukkit - decompile error
PersistentEntitySectionManager persistententitysectionmanager = this.entityManager;
Objects.requireNonNull(this.entityManager);
if (stream.anyMatch(persistententitysectionmanager::isLoaded)) {
return false;
} else {
- this.addFreshEntityWithPassengers(entity);
+ this.addFreshEntityWithPassengers(entity, reason); // CraftBukkit
return true;
}
}
@@ -973,11 +1105,33 @@
serverplayer.remove(entity_removalreason);
}
+ // CraftBukkit start
+ public boolean strikeLightning(Entity entitylightning) {
+ return this.strikeLightning(entitylightning, LightningStrikeEvent.Cause.UNKNOWN);
+ }
+
+ public boolean strikeLightning(Entity entitylightning, LightningStrikeEvent.Cause cause) {
+ LightningStrikeEvent lightning = CraftEventFactory.callLightningStrikeEvent((org.bukkit.entity.LightningStrike) entitylightning.getBukkitEntity(), cause);
+
+ if (lightning.isCancelled()) {
+ return false;
+ }
+
+ return this.addFreshEntity(entitylightning);
+ }
+ // CraftBukkit end
+
@Override
@Override
public void destroyBlockProgress(int i, BlockPos blockpos, int j) {
Iterator iterator = this.server.getPlayerList().getPlayers().iterator();
+ // CraftBukkit start
+ Player entityhuman = null;
+ Entity entity = this.getEntity(breakerId);
+ if (entity instanceof Player) entityhuman = (Player) entity;
+ // CraftBukkit end
+
while (iterator.hasNext()) {
ServerPlayer serverplayer = (ServerPlayer) iterator.next();
@@ -986,6 +1139,12 @@
double d1 = (double) blockpos.getY() - serverplayer.getY();
double d2 = (double) blockpos.getZ() - serverplayer.getZ();
+ // CraftBukkit start
+ if (entityhuman != null && !entityplayer.getBukkitEntity().canSee(entityhuman.getBukkitEntity())) {
+ continue;
+ }
+ // CraftBukkit end
+
if (d0 * d0 + d1 * d1 + d2 * d2 < 1024.0D) {
serverplayer.connection.send(new ClientboundBlockDestructionPacket(i, blockpos, j));
}
@@ -1051,8 +1204,19 @@
Iterator iterator = this.navigatingMobs.iterator();
while (iterator.hasNext()) {
- Mob mob = (Mob) iterator.next();
- PathNavigation pathnavigation = mob.getNavigation();
+ // CraftBukkit start - fix SPIGOT-6362
+ Mob entityinsentient;
+ try {
+ entityinsentient = (Mob) iterator.next();
+ } catch (java.util.ConcurrentModificationException ex) {
+ // This can happen because the pathfinder update below may trigger a chunk load, which in turn may cause more navigators to register
+ // In this case we just run the update again across all the iterators as the chunk will then be loaded
+ // As this is a relative edge case it is much faster than copying navigators (on either read or write)
+ sendBlockUpdated(pos, oldState, newState, flags);
+ return;
+ }
+ // CraftBukkit end
+ PathNavigation navigationabstract = entityinsentient.getNavigation();
if (pathnavigation.shouldRecomputePath(blockpos)) {
list.add(pathnavigation);
@@ -1118,9 +1275,13 @@
}
@Override
- @Override
- public Explosion explode(@Nullable Entity entity, @Nullable DamageSource damagesource, @Nullable ExplosionDamageCalculator explosiondamagecalculator, double d0, double d1, double d2, float f, boolean flag, Level.ExplosionInteraction level_explosioninteraction, ParticleOptions particleoptions, ParticleOptions particleoptions1, SoundEvent soundevent) {
- Explosion explosion = this.explode(entity, damagesource, explosiondamagecalculator, d0, d1, d2, f, flag, level_explosioninteraction, false, particleoptions, particleoptions1, soundevent);
+ public Explosion explode(@Nullable Entity entity, @Nullable DamageSource damagesource, @Nullable ExplosionDamageCalculator explosiondamagecalculator, double d0, double d1, double d2, float f, boolean flag, Level.a world_a, ParticleOptions particleparam, ParticleOptions particleparam1, SoundEvent soundeffect) {
+ Explosion explosion = this.explode(entity, damagesource, explosiondamagecalculator, d0, d1, d2, f, flag, world_a, false, particleparam, particleparam1, soundeffect);
+ // CraftBukkit start
+ if (explosion.wasCanceled) {
+ return explosion;
+ }
+ // CraftBukkit end
if (!explosion.interactsWithBlocks()) {
explosion.clearToBlow();
@@ -1196,14 +1353,21 @@
return this.server.getStructureManager();
}
- public <T extends ParticleOptions> int sendParticles(T t0, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6) {
- ClientboundLevelParticlesPacket clientboundlevelparticlespacket = new ClientboundLevelParticlesPacket(t0, false, d0, d1, d2, (float) d3, (float) d4, (float) d5, (float) d6, i);
+ public <T extends ParticleOptions> int sendParticles(T type, double posX, double d1, double posY, int i, double posZ, double d4, double particleCount, double xOffset) {
+ // CraftBukkit - visibility api support
+ return sendParticles(null, type, posX, d1, posY, i, posZ, d4, particleCount, xOffset, false);
+ }
+
+ public <T extends ParticleOptions> int sendParticles(ServerPlayer sender, T t0, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6, boolean force) {
+ ClientboundLevelParticlesPacket packetplayoutworldparticles = new ClientboundLevelParticlesPacket(t0, force, d0, d1, d2, (float) d3, (float) d4, (float) d5, (float) d6, i);
+ // CraftBukkit end
int j = 0;
for (int k = 0; k < this.players.size(); ++k) {
- ServerPlayer serverplayer = (ServerPlayer) this.players.get(k);
+ ServerPlayer entityplayer = (ServerPlayer) this.players.get(k);
+ if (sender != null && !entityplayer.getBukkitEntity().canSee(sender.getBukkitEntity())) continue; // CraftBukkit
- if (this.sendParticles(serverplayer, false, d0, d1, d2, clientboundlevelparticlespacket)) {
+ if (this.sendParticles(entityplayer, force, d0, d1, d2, packetplayoutworldparticles)) { // CraftBukkit
++j;
}
}
@@ -1254,8 +1417,8 @@
}
@Nullable
- public BlockPos findNearestMapStructure(TagKey<Structure> tagkey, BlockPos blockpos, int i, boolean flag) {
- if (!this.server.getWorldData().worldGenOptions().generateStructures()) {
+ public BlockPos findNearestMapStructure(TagKey<Structure> structureTag, BlockPos pos, int radius, boolean skipExistingChunks) {
+ if (!this.serverLevelData.worldGenOptions().generateStructures()) { // CraftBukkit
return null;
} else {
Optional<HolderSet.Named<Structure>> optional = this.registryAccess().registryOrThrow(Registries.STRUCTURE).getTag(tagkey);
@@ -1299,15 +1459,24 @@
@Nullable
@Override
- @Override
- public MapItemSavedData getMapData(String s) {
- return (MapItemSavedData) this.getServer().overworld().getDataStorage().get(MapItemSavedData.factory(), s);
+ public MapItemSavedData getMapData(String mapName) {
+ // CraftBukkit start
+ MapItemSavedData worldmap = (MapItemSavedData) this.getServer().overworld().getDataStorage().get(MapItemSavedData.factory(), mapName);
+ if (worldmap != null) {
+ worldmap.id = mapName;
+ }
+ return worldmap;
+ // CraftBukkit end
}
@Override
- @Override
- public void setMapData(String s, MapItemSavedData mapitemsaveddata) {
- this.getServer().overworld().getDataStorage().set(s, mapitemsaveddata);
+ public void setMapData(String mapName, MapItemSavedData data) {
+ // CraftBukkit start
+ data.id = mapName;
+ MapInitializeEvent event = new MapInitializeEvent(data.mapView);
+ Bukkit.getServer().getPluginManager().callEvent(event);
+ // CraftBukkit end
+ this.getServer().overworld().getDataStorage().set(mapName, data);
}
@Override
@@ -1608,7 +1773,12 @@
@Override
public void blockUpdated(BlockPos blockpos, Block block) {
if (!this.isDebug()) {
- this.updateNeighborsAt(blockpos, block);
+ // CraftBukkit start
+ if (populating) {
+ return;
+ }
+ // CraftBukkit end
+ this.updateNeighborsAt(pos, block);
}
}
@@ -1629,13 +1797,13 @@
}
public boolean isFlat() {
- return this.server.getWorldData().isFlatWorld();
+ return this.serverLevelData.isFlatWorld(); // CraftBukkit
}
@Override
@Override
public long getSeed() {
- return this.server.getWorldData().worldGenOptions().seed();
+ return this.serverLevelData.worldGenOptions().seed(); // CraftBukkit
}
@Nullable
@@ -1678,18 +1844,34 @@
}
}
- public static void makeObsidianPlatform(ServerLevel serverlevel) {
- BlockPos blockpos = ServerLevel.END_SPAWN_POINT;
- int i = blockpos.getX();
- int j = blockpos.getY() - 2;
- int k = blockpos.getZ();
+ public static void makeObsidianPlatform(ServerLevel serverLevel) {
+ // CraftBukkit start
+ ServerLevel.makeObsidianPlatform(serverLevel, null);
+ }
- BlockPos.betweenClosed(i - 2, j + 1, k - 2, i + 2, j + 3, k + 2).forEach((blockpos1) -> {
- serverlevel.setBlockAndUpdate(blockpos1, Blocks.AIR.defaultBlockState());
+ public static void makeObsidianPlatform(ServerLevel worldserver, Entity entity) {
+ // CraftBukkit end
+ BlockPos blockposition = ServerLevel.END_SPAWN_POINT;
+ int i = blockposition.getX();
+ int j = blockposition.getY() - 2;
+ int k = blockposition.getZ();
+
+ // CraftBukkit start
+ org.bukkit.craftbukkit.util.BlockStateListPopulator blockList = new org.bukkit.craftbukkit.util.BlockStateListPopulator(worldserver);
+ BlockPos.betweenClosed(i - 2, j + 1, k - 2, i + 2, j + 3, k + 2).forEach((blockposition1) -> {
+ blockList.setBlock(blockposition1, Blocks.AIR.defaultBlockState(), 3);
});
BlockPos.betweenClosed(i - 2, j, k - 2, i + 2, j, k + 2).forEach((blockpos1) -> {
serverlevel.setBlockAndUpdate(blockpos1, Blocks.OBSIDIAN.defaultBlockState());
});
+ org.bukkit.World bworld = worldserver.getWorld();
+ org.bukkit.event.world.PortalCreateEvent portalEvent = new org.bukkit.event.world.PortalCreateEvent((List<org.bukkit.block.BlockState>) (List) blockList.getList(), bworld, (entity == null) ? null : entity.getBukkitEntity(), org.bukkit.event.world.PortalCreateEvent.CreateReason.END_PLATFORM);
+
+ worldserver.getCraftServer().getPluginManager().callEvent(portalEvent);
+ if (!portalEvent.isCancelled()) {
+ blockList.updateList();
+ }
+ // CraftBukkit end
}
@Override
@@ -1833,6 +2005,8 @@
}
entity.updateDynamicGameEventListener(DynamicGameEventListener::add);
+ entity.inWorld = true; // CraftBukkit - Mark entity as in world
+ entity.valid = true; // CraftBukkit
}
@Override
@@ -1870,6 +2043,14 @@
}
entity.updateDynamicGameEventListener(DynamicGameEventListener::remove);
+ // CraftBukkit start
+ entity.valid = false;
+ if (!(entity instanceof ServerPlayer)) {
+ for (ServerPlayer player : players) {
+ player.getBukkitEntity().onEntityRemove(entity);
+ }
+ }
+ // CraftBukkit end
}
@Override

View file

@ -0,0 +1,334 @@
--- a/net/minecraft/server/level/ServerPlayerGameMode.java
+++ b/net/minecraft/server/level/ServerPlayerGameMode.java
@@ -21,10 +23,28 @@
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.GameMasterBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
-import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.block.state.IBlockData;
+import org.slf4j.Logger;
+
+// CraftBukkit start
+import java.util.ArrayList;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.network.ServerGamePacketListenerImpl;
+import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.block.CakeBlock;
+import net.minecraft.world.level.block.DoorBlock;
+import net.minecraft.world.level.block.state.properties.BlockPropertyDoubleBlockHalf;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
-import org.slf4j.Logger;
+import org.bukkit.GameMode;
+import org.bukkit.craftbukkit.block.CraftBlock;
+import org.bukkit.event.block.BlockBreakEvent;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.Event;
+import org.bukkit.event.block.Action;
+import org.bukkit.event.player.PlayerGameModeChangeEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+// CraftBukkit end
public class ServerPlayerGameMode {
@@ -56,9 +76,16 @@
if (gametype == this.gameModeForPlayer) {
return false;
} else {
- this.setGameModeForPlayer(gametype, this.previousGameModeForPlayer);
+ // CraftBukkit start
+ PlayerGameModeChangeEvent event = new PlayerGameModeChangeEvent(player.getBukkitEntity(), GameMode.getByValue(gameModeForPlayer.getId()));
+ level.getCraftServer().getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return false;
+ }
+ // CraftBukkit end
+ this.setGameModeForPlayer(gameModeForPlayer, this.previousGameModeForPlayer);
this.player.onUpdateAbilities();
- this.player.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player));
+ this.player.server.getPlayerList().broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player), this.player); // CraftBukkit
this.level.updateSleepingPlayerList();
return true;
}
@@ -88,8 +115,8 @@
}
public void tick() {
- ++this.gameTicks;
- BlockState blockstate;
+ this.gameTicks = MinecraftServer.currentTick; // CraftBukkit;
+ IBlockData iblockdata;
if (this.hasDelayedDestroy) {
blockstate = this.level.getBlockState(this.delayedDestroyPos);
@@ -140,13 +167,35 @@
} else {
BlockState blockstate;
- if (serverboundplayeractionpacket_action == ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK) {
- if (!this.level.mayInteract(this.player, blockpos)) {
- this.player.connection.send(new ClientboundBlockUpdatePacket(blockpos, this.level.getBlockState(blockpos)));
- this.debugLogging(blockpos, false, j, "may not interact");
+ if (action == ServerboundPlayerActionPacket.EnumPlayerDigType.START_DESTROY_BLOCK) {
+ if (!this.level.mayInteract(this.player, pos)) {
+ // CraftBukkit start - fire PlayerInteractEvent
+ CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, pos, face, this.player.getInventory().getSelected(), EnumHand.MAIN_HAND);
+ this.player.connection.send(new ClientboundBlockUpdatePacket(pos, this.level.getBlockState(pos)));
+ this.debugLogging(pos, false, sequence, "may not interact");
+ // Update any tile entity data for this block
+ BlockEntity tileentity = level.getBlockEntity(pos);
+ if (tileentity != null) {
+ this.player.connection.send(tileentity.getUpdatePacket());
+ }
+ // CraftBukkit end
return;
}
+ // CraftBukkit start
+ PlayerInteractEvent event = CraftEventFactory.callPlayerInteractEvent(this.player, Action.LEFT_CLICK_BLOCK, pos, face, this.player.getInventory().getSelected(), EnumHand.MAIN_HAND);
+ if (event.isCancelled()) {
+ // Let the client know the block still exists
+ this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos));
+ // Update any tile entity data for this block
+ BlockEntity tileentity = this.level.getBlockEntity(pos);
+ if (tileentity != null) {
+ this.player.connection.send(tileentity.getUpdatePacket());
+ }
+ return;
+ }
+ // CraftBukkit end
+
if (this.isCreative()) {
this.destroyAndAck(blockpos, j, "creative destroy");
return;
@@ -161,14 +210,46 @@
this.destroyProgressStart = this.gameTicks;
float f = 1.0F;
- blockstate = this.level.getBlockState(blockpos);
- if (!blockstate.isAir()) {
- blockstate.attack(this.level, blockpos, this.player);
- f = blockstate.getDestroyProgress(this.player, this.player.level(), blockpos);
+ iblockdata = this.level.getBlockState(pos);
+ // CraftBukkit start - Swings at air do *NOT* exist.
+ if (event.useInteractedBlock() == Event.Result.DENY) {
+ // If we denied a door from opening, we need to send a correcting update to the client, as it already opened the door.
+ IBlockData data = this.level.getBlockState(pos);
+ if (data.getBlock() instanceof DoorBlock) {
+ // For some reason *BOTH* the bottom/top part have to be marked updated.
+ boolean bottom = data.getValue(DoorBlock.HALF) == BlockPropertyDoubleBlockHalf.LOWER;
+ this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos));
+ this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, bottom ? pos.above() : pos.below()));
+ } else if (data.getBlock() instanceof TrapDoorBlock) {
+ this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos));
+ }
+ } else if (!iblockdata.isAir()) {
+ iblockdata.attack(this.level, pos, this.player);
+ f = iblockdata.getDestroyProgress(this.player, this.player.level(), pos);
}
- if (!blockstate.isAir() && f >= 1.0F) {
- this.destroyAndAck(blockpos, j, "insta mine");
+ if (event.useItemInHand() == Event.Result.DENY) {
+ // If we 'insta destroyed' then the client needs to be informed.
+ if (f > 1.0f) {
+ this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos));
+ }
+ return;
+ }
+ org.bukkit.event.block.BlockDamageEvent blockEvent = CraftEventFactory.callBlockDamageEvent(this.player, pos, this.player.getInventory().getSelected(), f >= 1.0f);
+
+ if (blockEvent.isCancelled()) {
+ // Let the client know the block still exists
+ this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos));
+ return;
+ }
+
+ if (blockEvent.getInstaBreak()) {
+ f = 2.0f;
+ }
+ // CraftBukkit end
+
+ if (!iblockdata.isAir() && f >= 1.0F) {
+ this.destroyAndAck(pos, sequence, "insta mine");
} else {
if (this.isDestroyingBlock) {
this.player.connection.send(new ClientboundBlockUpdatePacket(this.destroyPos, this.level.getBlockState(this.destroyPos)));
@@ -210,14 +291,16 @@
this.debugLogging(blockpos, true, j, "stopped destroying");
} else if (serverboundplayeractionpacket_action == ServerboundPlayerActionPacket.Action.ABORT_DESTROY_BLOCK) {
this.isDestroyingBlock = false;
- if (!Objects.equals(this.destroyPos, blockpos)) {
- ServerPlayerGameMode.LOGGER.warn("Mismatch in destroy block pos: {} {}", this.destroyPos, blockpos);
+ if (!Objects.equals(this.destroyPos, pos)) {
+ ServerPlayerGameMode.LOGGER.debug("Mismatch in destroy block pos: {} {}", this.destroyPos, pos); // CraftBukkit - SPIGOT-5457 sent by client when interact event cancelled
this.level.destroyBlockProgress(this.player.getId(), this.destroyPos, -1);
this.debugLogging(blockpos, true, j, "aborted mismatched destroying");
}
- this.level.destroyBlockProgress(this.player.getId(), blockpos, -1);
- this.debugLogging(blockpos, true, j, "aborted destroying");
+ this.level.destroyBlockProgress(this.player.getId(), pos, -1);
+ this.debugLogging(pos, true, sequence, "aborted destroying");
+
+ CraftEventFactory.callBlockDamageAbortEvent(this.player, pos, this.player.getInventory().getSelected()); // CraftBukkit
}
}
@@ -233,14 +316,69 @@
}
- public boolean destroyBlock(BlockPos blockpos) {
- BlockState blockstate = this.level.getBlockState(blockpos);
+ public boolean destroyBlock(BlockPos pos) {
+ IBlockData iblockdata = this.level.getBlockState(pos);
+ // CraftBukkit start - fire BlockBreakEvent
+ org.bukkit.block.Block bblock = CraftBlock.at(level, pos);
+ BlockBreakEvent event = null;
- if (!this.player.getMainHandItem().getItem().canAttackBlock(blockstate, this.level, blockpos, this.player)) {
+ if (this.player instanceof ServerPlayer) {
+ // Sword + Creative mode pre-cancel
+ boolean isSwordNoBreak = !this.player.getMainHandItem().getItem().canAttackBlock(iblockdata, this.level, pos, this.player);
+
+ // Tell client the block is gone immediately then process events
+ // Don't tell the client if its a creative sword break because its not broken!
+ if (level.getBlockEntity(pos) == null && !isSwordNoBreak) {
+ ClientboundBlockUpdatePacket packet = new ClientboundBlockUpdatePacket(pos, Blocks.AIR.defaultBlockState());
+ this.player.connection.send(packet);
+ }
+
+ event = new BlockBreakEvent(bblock, this.player.getBukkitEntity());
+
+ // Sword + Creative mode pre-cancel
+ event.setCancelled(isSwordNoBreak);
+
+ // Calculate default block experience
+ IBlockData nmsData = this.level.getBlockState(pos);
+ Block nmsBlock = nmsData.getBlock();
+
+ ItemStack itemstack = this.player.getItemBySlot(EquipmentSlot.MAINHAND);
+
+ if (nmsBlock != null && !event.isCancelled() && !this.isCreative() && this.player.hasCorrectToolForDrops(nmsBlock.defaultBlockState())) {
+ event.setExpToDrop(nmsBlock.getExpDrop(nmsData, this.level, pos, itemstack, true));
+ }
+
+ this.level.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ if (isSwordNoBreak) {
+ return false;
+ }
+ // Let the client know the block still exists
+ this.player.connection.send(new ClientboundBlockUpdatePacket(this.level, pos));
+
+ // Brute force all possible updates
+ for (Direction dir : Direction.values()) {
+ this.player.connection.send(new ClientboundBlockUpdatePacket(level, pos.relative(dir)));
+ }
+
+ // Update any tile entity data for this block
+ BlockEntity tileentity = this.level.getBlockEntity(pos);
+ if (tileentity != null) {
+ this.player.connection.send(tileentity.getUpdatePacket());
+ }
+ return false;
+ }
+ }
+ // CraftBukkit end
+
+ if (false && !this.player.getMainHandItem().getItem().canAttackBlock(iblockdata, this.level, pos, this.player)) { // CraftBukkit - false
return false;
} else {
- BlockEntity blockentity = this.level.getBlockEntity(blockpos);
- Block block = blockstate.getBlock();
+ iblockdata = this.level.getBlockState(pos); // CraftBukkit - update state from plugins
+ if (iblockdata.isAir()) return false; // CraftBukkit - A plugin set block to air without cancelling
+ BlockEntity tileentity = this.level.getBlockEntity(pos);
+ Block block = iblockdata.getBlock();
if (block instanceof GameMasterBlock && !this.player.canUseGameMasterBlocks()) {
this.level.sendBlockUpdated(blockpos, blockstate, blockstate, 3);
@@ -248,27 +386,44 @@
} else if (this.player.blockActionRestricted(this.level, blockpos, this.gameModeForPlayer)) {
return false;
} else {
- BlockState blockstate1 = block.playerWillDestroy(this.level, blockpos, blockstate, this.player);
- boolean flag = this.level.removeBlock(blockpos, false);
+ // CraftBukkit start
+ org.bukkit.block.BlockState state = bblock.getState();
+ level.captureDrops = new ArrayList<>();
+ // CraftBukkit end
+ IBlockData iblockdata1 = block.playerWillDestroy(this.level, pos, iblockdata, this.player);
+ boolean flag = this.level.removeBlock(pos, false);
if (flag) {
block.destroy(this.level, blockpos, blockstate1);
}
if (this.isCreative()) {
- return true;
+ // return true; // CraftBukkit
} else {
ItemStack itemstack = this.player.getMainHandItem();
ItemStack itemstack1 = itemstack.copy();
boolean flag1 = this.player.hasCorrectToolForDrops(blockstate1);
- itemstack.mineBlock(this.level, blockstate1, blockpos, this.player);
- if (flag && flag1) {
- block.playerDestroy(this.level, this.player, blockpos, blockstate1, blockentity, itemstack1);
+ itemstack.mineBlock(this.level, iblockdata1, pos, this.player);
+ if (flag && flag1 && event.isDropItems()) { // CraftBukkit - Check if block should drop items
+ block.playerDestroy(this.level, this.player, pos, iblockdata1, tileentity, itemstack1);
}
- return true;
+ // return true; // CraftBukkit
}
+ // CraftBukkit start
+ if (event.isDropItems()) {
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, state, this.player, level.captureDrops);
+ }
+ level.captureDrops = null;
+
+ // Drop event experience
+ if (flag && event != null) {
+ iblockdata.getBlock().popExperience(this.level, pos, event.getExpToDrop());
+ }
+
+ return true;
+ // CraftBukkit end
}
}
}
@@ -313,9 +468,17 @@
}
}
- public InteractionResult useItemOn(ServerPlayer serverplayer, Level level, ItemStack itemstack, InteractionHand interactionhand, BlockHitResult blockhitresult) {
- BlockPos blockpos = blockhitresult.getBlockPos();
- BlockState blockstate = level.getBlockState(blockpos);
+ // CraftBukkit start - whole method
+ public boolean interactResult = false;
+ public boolean firedInteract = false;
+ public BlockPos interactPosition;
+ public EnumHand interactHand;
+ public ItemStack interactItemStack;
+ public InteractionResult useItemOn(ServerPlayer player, Level level, ItemStack stack, EnumHand hand, BlockHitResult hitResult) {
+ BlockPos blockposition = hitResult.getBlockPos();
+ IBlockData iblockdata = level.getBlockState(blockposition);
+ InteractionResult enuminteractionresult = InteractionResult.PASS;
+ boolean cancelledBlock = false;
if (!blockstate.getBlock().isEnabled(level.enabledFeatures())) {
return InteractionResult.FAIL;
@@ -364,6 +557,8 @@
return InteractionResult.PASS;
}
}
+ return enuminteractionresult;
+ // CraftBukkit end
}
public void setLevel(ServerLevel serverlevel) {

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/server/level/TicketType.java
+++ b/net/minecraft/server/level/TicketType.java
@@ -23,6 +23,8 @@
public static final TicketType<BlockPos> PORTAL = create("portal", Vec3i::compareTo, 300);
public static final TicketType<Integer> POST_TELEPORT = create("post_teleport", Integer::compareTo, 5);
public static final TicketType<ChunkPos> UNKNOWN = create("unknown", Comparator.comparingLong(ChunkPos::toLong), 1);
+ public static final TicketType<Unit> PLUGIN = create("plugin", (a, b) -> 0); // CraftBukkit
+ public static final TicketType<org.bukkit.plugin.Plugin> PLUGIN_TICKET = create("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // CraftBukkit
public static <T> TicketType<T> create(String s, Comparator<T> comparator) {
return new TicketType<>(s, comparator, 0L);

View file

@ -0,0 +1,27 @@
--- a/net/minecraft/server/level/WorldGenRegion.java
+++ b/net/minecraft/server/level/WorldGenRegion.java
@@ -221,8 +208,8 @@
if (blockstate.isAir()) {
return false;
} else {
- if (flag) {
- BlockEntity blockentity = blockstate.hasBlockEntity() ? this.getBlockEntity(blockpos) : null;
+ if (false) { // CraftBukkit - SPIGOT-6833: Do not drop during world generation
+ BlockEntity tileentity = iblockdata.hasBlockEntity() ? this.getBlockEntity(pos) : null;
Block.dropResources(blockstate, this.level, blockpos, blockentity, entity, ItemStack.EMPTY);
}
@@ -344,6 +327,13 @@
@Override
@Override
public boolean addFreshEntity(Entity entity) {
+ // CraftBukkit start
+ return addFreshEntity(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT);
+ }
+
+ @Override
+ public boolean addFreshEntity(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) {
+ // CraftBukkit end
int i = SectionPos.blockToSectionCoord(entity.getBlockX());
int j = SectionPos.blockToSectionCoord(entity.getBlockZ());

View file

@ -0,0 +1,45 @@
--- a/net/minecraft/server/network/LegacyQueryHandler.java
+++ b/net/minecraft/server/network/LegacyQueryHandler.java
@@ -36,10 +35,11 @@
SocketAddress socketaddress = channelhandlercontext.channel().remoteAddress();
int i = bytebuf.readableBytes();
String s;
+ org.bukkit.event.server.ServerListPingEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callServerListPingEvent(socketaddress, server.getMotd(), server.getPlayerCount(), server.getMaxPlayers()); // CraftBukkit
if (i == 0) {
LegacyQueryHandler.LOGGER.debug("Ping: (<1.3.x) from {}", socketaddress);
- s = createVersion0Response(this.server);
+ s = createVersion0Response(this.server, event); // CraftBukkit
sendFlushAndClose(channelhandlercontext, createLegacyDisconnectPacket(channelhandlercontext.alloc(), s));
} else {
if (bytebuf.readUnsignedByte() != 1) {
@@ -56,7 +56,7 @@
LegacyQueryHandler.LOGGER.debug("Ping: (1.4-1.5.x) from {}", socketaddress);
}
- s = createVersion1Response(this.server);
+ s = createVersion1Response(this.server, event); // CraftBukkit
sendFlushAndClose(channelhandlercontext, createLegacyDisconnectPacket(channelhandlercontext.alloc(), s));
}
@@ -107,12 +107,16 @@
}
}
- private static String createVersion0Response(ServerInfo serverinfo) {
- return String.format(Locale.ROOT, "%s\u00a7%d\u00a7%d", serverinfo.getMotd(), serverinfo.getPlayerCount(), serverinfo.getMaxPlayers());
+ // CraftBukkit start
+ private static String createVersion0Response(ServerInfo serverinfo, org.bukkit.event.server.ServerListPingEvent event) {
+ return String.format(Locale.ROOT, "%s\u00a7%d\u00a7%d", event.getMotd(), event.getNumPlayers(), event.getMaxPlayers());
+ // CraftBukkit end
}
- private static String createVersion1Response(ServerInfo serverinfo) {
- return String.format(Locale.ROOT, "\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", 127, serverinfo.getServerVersion(), serverinfo.getMotd(), serverinfo.getPlayerCount(), serverinfo.getMaxPlayers());
+ // CraftBukkit start
+ private static String createVersion1Response(ServerInfo serverinfo, org.bukkit.event.server.ServerListPingEvent event) {
+ return String.format(Locale.ROOT, "\u00a71\u0000%d\u0000%s\u0000%s\u0000%d\u0000%d", 127, serverinfo.getServerVersion(), event.getMotd(), event.getNumPlayers(), event.getMaxPlayers());
+ // CraftBukkit end
}
private static void sendFlushAndClose(ChannelHandlerContext channelhandlercontext, ByteBuf bytebuf) {

View file

@ -0,0 +1,208 @@
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
@@ -26,6 +30,17 @@
import net.minecraft.util.thread.BlockableEventLoop;
import org.slf4j.Logger;
+// CraftBukkit start
+import io.netty.buffer.ByteBuf;
+import java.util.concurrent.ExecutionException;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.craftbukkit.util.CraftChatMessage;
+import org.bukkit.craftbukkit.util.CraftLocation;
+import org.bukkit.craftbukkit.util.Waitable;
+import org.bukkit.event.player.PlayerKickEvent;
+import org.bukkit.event.player.PlayerResourcePackStatusEvent;
+// CraftBukkit end
+
public abstract class ServerCommonPacketListenerImpl implements ServerCommonPacketListener {
private static final Logger LOGGER = LogUtils.getLogger();
@@ -39,13 +54,21 @@
private int latency;
private volatile boolean suspendFlushingOnServerThread = false;
- public ServerCommonPacketListenerImpl(MinecraftServer minecraftserver, Connection connection, CommonListenerCookie commonlistenercookie) {
+ public ServerCommonPacketListenerImpl(MinecraftServer minecraftserver, Connection networkmanager, CommonListenerCookie commonlistenercookie, ServerPlayer player) { // CraftBukkit
this.server = minecraftserver;
this.connection = connection;
this.keepAliveTime = Util.getMillis();
this.latency = commonlistenercookie.latency();
+ // CraftBukkit start - add fields and methods
+ this.player = player;
+ this.cserver = minecraftserver.server;
}
+ public CraftPlayer getCraftPlayer() {
+ return (this.player == null) ? null : (CraftPlayer) this.player.getBukkitEntity();
+ // CraftBukkit end
+ }
+
@Override
@Override
public void onDisconnect(Component component) {
@@ -59,6 +83,7 @@
@Override
@Override
public void handleKeepAlive(ServerboundKeepAlivePacket serverboundkeepalivepacket) {
+ PacketUtils.ensureRunningOnSameThread(serverboundkeepalivepacket, this, this.player.serverLevel()); // CraftBukkit
if (this.keepAlivePending && serverboundkeepalivepacket.getId() == this.keepAliveChallenge) {
int i = (int) (Util.getMillis() - this.keepAliveTime);
@@ -74,10 +98,52 @@
@Override
public void handlePong(ServerboundPongPacket serverboundpongpacket) {}
+ // CraftBukkit start
+ private static final ResourceLocation CUSTOM_REGISTER = new ResourceLocation("register");
+ private static final ResourceLocation CUSTOM_UNREGISTER = new ResourceLocation("unregister");
+
@Override
@Override
public void handleCustomPayload(ServerboundCustomPayloadPacket serverboundcustompayloadpacket) {}
+ if (identifier.equals(CUSTOM_REGISTER)) {
+ try {
+ String channels = payload.toString(com.google.common.base.Charsets.UTF_8);
+ for (String channel : channels.split("\0")) {
+ getCraftPlayer().addChannel(channel);
+ }
+ } catch (Exception ex) {
+ ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t register custom payload", ex);
+ this.disconnect("Invalid payload REGISTER!");
+ }
+ } else if (identifier.equals(CUSTOM_UNREGISTER)) {
+ try {
+ String channels = payload.toString(com.google.common.base.Charsets.UTF_8);
+ for (String channel : channels.split("\0")) {
+ getCraftPlayer().removeChannel(channel);
+ }
+ } catch (Exception ex) {
+ ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t unregister custom payload", ex);
+ this.disconnect("Invalid payload UNREGISTER!");
+ }
+ } else {
+ try {
+ byte[] data = new byte[payload.readableBytes()];
+ payload.readBytes(data);
+ cserver.getMessenger().dispatchIncomingMessage(player.getBukkitEntity(), identifier.toString(), data);
+ } catch (Exception ex) {
+ ServerGamePacketListenerImpl.LOGGER.error("Couldn\'t dispatch custom payload", ex);
+ this.disconnect("Invalid custom payload!");
+ }
+ }
+
+ }
+
+ public final boolean isDisconnected() {
+ return !this.player.joining && !this.connection.isConnected();
+ }
+ // CraftBukkit end
+
@Override
@Override
public void handleResourcePackResponse(ServerboundResourcePackPacket serverboundresourcepackpacket) {
@@ -86,6 +156,7 @@
ServerCommonPacketListenerImpl.LOGGER.info("Disconnecting {} due to resource pack {} rejection", this.playerProfile().getName(), serverboundresourcepackpacket.id());
this.disconnect(Component.translatable("multiplayer.requiredTexturePrompt.disconnect"));
}
+ this.cserver.getPluginManager().callEvent(new PlayerResourcePackStatusEvent(getCraftPlayer(), serverboundresourcepackpacket.id(), PlayerResourcePackStatusEvent.Status.values()[serverboundresourcepackpacket.action().ordinal()])); // CraftBukkit
}
@@ -93,7 +164,7 @@
this.server.getProfiler().push("keepAlive");
long i = Util.getMillis();
- if (i - this.keepAliveTime >= 15000L) {
+ if (i - this.keepAliveTime >= 25000L) { // CraftBukkit
if (this.keepAlivePending) {
this.disconnect(ServerCommonPacketListenerImpl.TIMEOUT_DISCONNECTION_MESSAGE);
} else {
@@ -121,6 +192,14 @@
}
public void send(Packet<?> packet, @Nullable PacketSendListener packetsendlistener) {
+ // CraftBukkit start
+ if (packet == null) {
+ return;
+ } else if (packet instanceof ClientboundSetDefaultSpawnPositionPacket) {
+ ClientboundSetDefaultSpawnPositionPacket packet6 = (ClientboundSetDefaultSpawnPositionPacket) packet;
+ this.player.compassTarget = CraftLocation.toBukkit(packet6.pos, this.getCraftPlayer().getWorld());
+ }
+ // CraftBukkit end
boolean flag = !this.suspendFlushingOnServerThread || !this.server.isSameThread();
try {
@@ -136,16 +215,67 @@
}
}
- public void disconnect(Component component) {
- this.connection.send(new ClientboundDisconnectPacket(component), PacketSendListener.thenRun(() -> {
- this.connection.disconnect(component);
+ // CraftBukkit start
+ @Deprecated
+ public void disconnect(Component ichatbasecomponent) {
+ disconnect(CraftChatMessage.fromComponent(ichatbasecomponent));
+ }
+ // CraftBukkit end
+
+ public void disconnect(String s) {
+ // CraftBukkit start - fire PlayerKickEvent
+ if (this.processedDisconnect) {
+ return;
+ }
+ if (!this.cserver.isPrimaryThread()) {
+ Waitable waitable = new Waitable() {
+ @Override
+ protected Object evaluate() {
+ ServerCommonPacketListenerImpl.this.disconnect(s);
+ return null;
+ }
+ };
+
+ this.server.processQueue.add(waitable);
+
+ try {
+ waitable.get();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ } catch (ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ return;
+ }
+
+ String leaveMessage = ChatFormatting.YELLOW + this.player.getScoreboardName() + " left the game.";
+
+ PlayerKickEvent event = new PlayerKickEvent(this.player.getBukkitEntity(), s, leaveMessage);
+
+ if (this.cserver.getServer().isRunning()) {
+ this.cserver.getPluginManager().callEvent(event);
+ }
+
+ if (event.isCancelled()) {
+ // Do not kick the player
+ return;
+ }
+ this.player.kickLeaveMessage = event.getLeaveMessage(); // CraftBukkit - SPIGOT-3034: Forward leave message to PlayerQuitEvent
+ // Send the possibly modified leave message
+ final Component ichatbasecomponent = CraftChatMessage.fromString(event.getReason(), true)[0];
+ // CraftBukkit end
+
+ this.connection.send(new ClientboundDisconnectPacket(ichatbasecomponent), PacketSendListener.thenRun(() -> {
+ this.connection.disconnect(ichatbasecomponent);
}));
+ this.onDisconnect(ichatbasecomponent); // CraftBukkit - fire quit instantly
this.connection.setReadOnly();
MinecraftServer minecraftserver = this.server;
Connection connection = this.connection;
Objects.requireNonNull(this.connection);
- minecraftserver.executeBlocking(connection::handleDisconnection);
+ // CraftBukkit - Don't wait
+ minecraftserver.wrapRunnable(networkmanager::handleDisconnection);
}
protected boolean isSingleplayerOwner() {

View file

@ -0,0 +1,30 @@
--- a/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java
@@ -44,8 +44,8 @@
private ConfigurationTask currentTask;
private ClientInformation clientInformation;
- public ServerConfigurationPacketListenerImpl(MinecraftServer minecraftserver, Connection connection, CommonListenerCookie commonlistenercookie) {
- super(minecraftserver, connection, commonlistenercookie);
+ public ServerConfigurationPacketListenerImpl(MinecraftServer minecraftserver, Connection networkmanager, CommonListenerCookie commonlistenercookie, ServerPlayer player) { // CraftBukkit
+ super(minecraftserver, networkmanager, commonlistenercookie, player); // CraftBukkit
this.gameProfile = commonlistenercookie.gameProfile();
this.clientInformation = commonlistenercookie.clientInformation();
}
@@ -123,14 +117,14 @@
return;
}
- Component component = playerlist.canPlayerLogin(this.connection.getRemoteAddress(), this.gameProfile);
+ Component ichatbasecomponent = null; // CraftBukkit - login checks already completed
if (component != null) {
this.disconnect(component);
return;
}
- ServerPlayer serverplayer = playerlist.getPlayerForLogin(this.gameProfile, this.clientInformation);
+ ServerPlayer entityplayer = playerlist.getPlayerForLogin(this.gameProfile, this.clientInformation, this.player); // CraftBukkit
playerlist.placeNewPlayer(this.connection, serverplayer, this.createCookie(this.clientInformation));
this.connection.resumeInboundAfterProtocolChange();

View file

@ -0,0 +1,24 @@
--- a/net/minecraft/server/network/ServerConnectionListener.java
+++ b/net/minecraft/server/network/ServerConnectionListener.java
@@ -105,10 +104,20 @@
((Connection) object).configurePacketHandler(channelpipeline);
((Connection) object).setListenerForServerboundHandshake(new ServerHandshakePacketListenerImpl(ServerConnectionListener.this.server, (Connection) object));
}
- }).group(eventloopgroup).localAddress(inetaddress, i)).bind().syncUninterruptibly());
+ }).group(eventloopgroup).localAddress(address, port)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit
}
}
+ // CraftBukkit start
+ public void acceptConnections() {
+ synchronized (this.channels) {
+ for (ChannelFuture future : this.channels) {
+ future.channel().config().setAutoRead(true);
+ }
+ }
+ }
+ // CraftBukkit end
+
public SocketAddress startMemoryChannel() {
List list = this.channels;
ChannelFuture channelfuture;

View file

@ -0,0 +1,78 @@
--- a/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerHandshakePacketListenerImpl.java
@@ -11,8 +11,17 @@
import net.minecraft.network.protocol.status.ServerStatus;
import net.minecraft.server.MinecraftServer;
+// CraftBukkit start
+import java.net.InetAddress;
+import java.util.HashMap;
+// CraftBukkit end
+
public class ServerHandshakePacketListenerImpl implements ServerHandshakePacketListener {
+ // CraftBukkit start - add fields
+ private static final HashMap<InetAddress, Long> throttleTracker = new HashMap<InetAddress, Long>();
+ private static int throttleCounter = 0;
+ // CraftBukkit end
private static final Component IGNORE_STATUS_REASON = Component.translatable("disconnect.ignoring_status_request");
private final MinecraftServer server;
private final Connection connection;
@@ -23,16 +32,50 @@
}
@Override
- @Override
- public void handleIntention(ClientIntentionPacket clientintentionpacket) {
- switch (clientintentionpacket.intention()) {
+ public void handleIntention(ClientIntentionPacket packet) {
+ this.connection.hostname = packet.hostName() + ":" + packet.port(); // CraftBukkit - set hostname
+ switch (packet.intention()) {
case LOGIN:
this.connection.setClientboundProtocolAfterHandshake(ClientIntent.LOGIN);
- if (clientintentionpacket.protocolVersion() != SharedConstants.getCurrentVersion().getProtocolVersion()) {
- MutableComponent mutablecomponent;
+ // CraftBukkit start - Connection throttle
+ try {
+ long currentTime = System.currentTimeMillis();
+ long connectionThrottle = this.server.server.getConnectionThrottle();
+ InetAddress address = ((java.net.InetSocketAddress) this.connection.getRemoteAddress()).getAddress();
- if (clientintentionpacket.protocolVersion() < 754) {
- mutablecomponent = Component.translatable("multiplayer.disconnect.outdated_client", SharedConstants.getCurrentVersion().getName());
+ synchronized (throttleTracker) {
+ if (throttleTracker.containsKey(address) && !"127.0.0.1".equals(address.getHostAddress()) && currentTime - throttleTracker.get(address) < connectionThrottle) {
+ throttleTracker.put(address, currentTime);
+ MutableComponent chatmessage = Component.literal("Connection throttled! Please wait before reconnecting.");
+ this.connection.send(new ClientboundLoginDisconnectPacket(chatmessage));
+ this.connection.disconnect(chatmessage);
+ return;
+ }
+
+ throttleTracker.put(address, currentTime);
+ throttleCounter++;
+ if (throttleCounter > 200) {
+ throttleCounter = 0;
+
+ // Cleanup stale entries
+ java.util.Iterator iter = throttleTracker.entrySet().iterator();
+ while (iter.hasNext()) {
+ java.util.Map.Entry<InetAddress, Long> entry = (java.util.Map.Entry) iter.next();
+ if (entry.getValue() > connectionThrottle) {
+ iter.remove();
+ }
+ }
+ }
+ }
+ } catch (Throwable t) {
+ org.apache.logging.log4j.LogManager.getLogger().debug("Failed to check connection throttle", t);
+ }
+ // CraftBukkit end
+ if (packet.protocolVersion() != SharedConstants.getCurrentVersion().getProtocolVersion()) {
+ MutableComponent ichatmutablecomponent;
+
+ if (packet.protocolVersion() < 754) {
+ ichatmutablecomponent = Component.translatable("multiplayer.disconnect.outdated_client", SharedConstants.getCurrentVersion().getName());
} else {
mutablecomponent = Component.translatable("multiplayer.disconnect.incompatible", SharedConstants.getCurrentVersion().getName());
}

View file

@ -0,0 +1,125 @@
--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -39,6 +40,10 @@
import net.minecraft.world.entity.player.Player;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
+import org.bukkit.craftbukkit.util.Waitable;
+import org.bukkit.event.player.AsyncPlayerPreLoginEvent;
+import org.bukkit.event.player.PlayerPreLoginEvent;
+// CraftBukkit end
public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, TickablePacketListener {
@@ -56,6 +61,7 @@
@Nullable
private GameProfile authenticatedProfile;
private final String serverId;
+ private ServerPlayer player; // CraftBukkit
public ServerLoginPacketListenerImpl(MinecraftServer minecraftserver, Connection connection) {
this.state = ServerLoginPacketListenerImpl.State.HELLO;
@@ -82,6 +87,13 @@
}
+ // CraftBukkit start
+ @Deprecated
+ public void disconnect(String s) {
+ disconnect(Component.literal(s));
+ }
+ // CraftBukkit end
+
@Override
@Override
public boolean isAcceptingMessages() {
@@ -143,10 +152,12 @@
private void verifyLoginAndFinishConnectionSetup(GameProfile gameprofile) {
PlayerList playerlist = this.server.getPlayerList();
- Component component = playerlist.canPlayerLogin(this.connection.getRemoteAddress(), gameprofile);
+ // CraftBukkit start - fire PlayerLoginEvent
+ this.player = playerlist.canPlayerLogin(this, gameprofile); // CraftBukkit
- if (component != null) {
- this.disconnect(component);
+ if (this.player == null) {
+ // this.disconnect(ichatbasecomponent);
+ // CraftBukkit end
} else {
if (this.server.getCompressionThreshold() >= 0 && !this.connection.isMemoryConnection()) {
this.connection.send(new ClientboundLoginCompressionPacket(this.server.getCompressionThreshold()), PacketSendListener.thenRun(() -> {
@@ -154,7 +165,7 @@
}));
}
- boolean flag = playerlist.disconnectAllPlayersWithProfile(gameprofile);
+ boolean flag = playerlist.disconnectAllPlayersWithProfile(gameprofile, this.player); // CraftBukkit - add player reference
if (flag) {
this.state = ServerLoginPacketListenerImpl.State.WAITING_FOR_DUPE_DISCONNECT;
@@ -206,6 +215,43 @@
if (profileresult != null) {
GameProfile gameprofile = profileresult.profile();
+ // CraftBukkit start - fire PlayerPreLoginEvent
+ if (!connection.isConnected()) {
+ return;
+ }
+
+ String playerName = gameprofile.getName();
+ java.net.InetAddress address = ((java.net.InetSocketAddress) connection.getRemoteAddress()).getAddress();
+ java.util.UUID uniqueId = gameprofile.getId();
+ final org.bukkit.craftbukkit.CraftServer server = ServerLoginPacketListenerImpl.this.server.server;
+
+ AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, uniqueId);
+ server.getPluginManager().callEvent(asyncEvent);
+
+ if (PlayerPreLoginEvent.getHandlerList().getRegisteredListeners().length != 0) {
+ final PlayerPreLoginEvent event = new PlayerPreLoginEvent(playerName, address, uniqueId);
+ if (asyncEvent.getResult() != PlayerPreLoginEvent.Result.ALLOWED) {
+ event.disallow(asyncEvent.getResult(), asyncEvent.getKickMessage());
+ }
+ Waitable<PlayerPreLoginEvent.Result> waitable = new Waitable<PlayerPreLoginEvent.Result>() {
+ @Override
+ protected PlayerPreLoginEvent.Result evaluate() {
+ server.getPluginManager().callEvent(event);
+ return event.getResult();
+ }};
+
+ ServerLoginPacketListenerImpl.this.server.processQueue.add(waitable);
+ if (waitable.get() != PlayerPreLoginEvent.Result.ALLOWED) {
+ disconnect(event.getKickMessage());
+ return;
+ }
+ } else {
+ if (asyncEvent.getLoginResult() != AsyncPlayerPreLoginEvent.Result.ALLOWED) {
+ disconnect(asyncEvent.getKickMessage());
+ return;
+ }
+ }
+ // CraftBukkit end
ServerLoginPacketListenerImpl.LOGGER.info("UUID of player {} is {}", gameprofile.getName(), gameprofile.getId());
ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile);
} else if (ServerLoginPacketListenerImpl.this.server.isSingleplayer()) {
@@ -223,6 +269,11 @@
ServerLoginPacketListenerImpl.this.disconnect(Component.translatable("multiplayer.disconnect.authservers_down"));
ServerLoginPacketListenerImpl.LOGGER.error("Couldn't verify username because servers are unavailable");
}
+ // CraftBukkit start - catch all exceptions
+ } catch (Exception exception) {
+ disconnect("Failed to verify username!");
+ server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + s1, exception);
+ // CraftBukkit end
}
}
@@ -250,7 +299,7 @@
public void handleLoginAcknowledgement(ServerboundLoginAcknowledgedPacket serverboundloginacknowledgedpacket) {
Validate.validState(this.state == ServerLoginPacketListenerImpl.State.PROTOCOL_SWITCHING, "Unexpected login acknowledgement packet", new Object[0]);
CommonListenerCookie commonlistenercookie = CommonListenerCookie.createInitial((GameProfile) Objects.requireNonNull(this.authenticatedProfile));
- ServerConfigurationPacketListenerImpl serverconfigurationpacketlistenerimpl = new ServerConfigurationPacketListenerImpl(this.server, this.connection, commonlistenercookie);
+ ServerConfigurationPacketListenerImpl serverconfigurationpacketlistenerimpl = new ServerConfigurationPacketListenerImpl(this.server, this.connection, commonlistenercookie, this.player); // CraftBukkit
this.connection.setListener(serverconfigurationpacketlistenerimpl);
serverconfigurationpacketlistenerimpl.startConfiguration();

View file

@ -0,0 +1,131 @@
--- a/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerStatusPacketListenerImpl.java
@@ -1,5 +1,12 @@
package net.minecraft.server.network;
+// CraftBukkit start
+import com.mojang.authlib.GameProfile;
+import java.net.InetSocketAddress;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Optional;
+import net.minecraft.SharedConstants;
import net.minecraft.network.Connection;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.status.ClientboundPongResponsePacket;
@@ -8,6 +15,12 @@
import net.minecraft.network.protocol.status.ServerStatusPacketListener;
import net.minecraft.network.protocol.status.ServerboundPingRequestPacket;
import net.minecraft.network.protocol.status.ServerboundStatusRequestPacket;
+import net.minecraft.server.MinecraftServer;
+import net.minecraft.server.level.ServerPlayer;
+import org.bukkit.craftbukkit.util.CraftChatMessage;
+import org.bukkit.craftbukkit.util.CraftIconCache;
+import org.bukkit.entity.Player;
+// CraftBukkit end
public class ServerStatusPacketListenerImpl implements ServerStatusPacketListener {
@@ -38,7 +48,101 @@
this.connection.disconnect(ServerStatusPacketListenerImpl.DISCONNECT_REASON);
} else {
this.hasRequestedStatus = true;
- this.connection.send(new ClientboundStatusResponsePacket(this.status));
+ // CraftBukkit start
+ // this.connection.send(new PacketStatusOutServerInfo(this.status));
+ MinecraftServer server = MinecraftServer.getServer();
+ final Object[] players = server.getPlayerList().players.toArray();
+ class ServerListPingEvent extends org.bukkit.event.server.ServerListPingEvent {
+
+ CraftIconCache icon = server.server.getServerIcon();
+
+ ServerListPingEvent() {
+ super(connection.hostname, ((InetSocketAddress) connection.getRemoteAddress()).getAddress(), server.getMotd(), server.getPlayerList().getMaxPlayers());
+ }
+
+ @Override
+ public void setServerIcon(org.bukkit.util.CachedServerIcon icon) {
+ if (!(icon instanceof CraftIconCache)) {
+ throw new IllegalArgumentException(icon + " was not created by " + org.bukkit.craftbukkit.CraftServer.class);
+ }
+ this.icon = (CraftIconCache) icon;
+ }
+
+ @Override
+ public Iterator<Player> iterator() throws UnsupportedOperationException {
+ return new Iterator<Player>() {
+ int i;
+ int ret = Integer.MIN_VALUE;
+ ServerPlayer player;
+
+ @Override
+ public boolean hasNext() {
+ if (player != null) {
+ return true;
+ }
+ final Object[] currentPlayers = players;
+ for (int length = currentPlayers.length, i = this.i; i < length; i++) {
+ final ServerPlayer player = (ServerPlayer) currentPlayers[i];
+ if (player != null) {
+ this.i = i + 1;
+ this.player = player;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public Player next() {
+ if (!hasNext()) {
+ throw new java.util.NoSuchElementException();
+ }
+ final ServerPlayer player = this.player;
+ this.player = null;
+ this.ret = this.i - 1;
+ return player.getBukkitEntity();
+ }
+
+ @Override
+ public void remove() {
+ final Object[] currentPlayers = players;
+ final int i = this.ret;
+ if (i < 0 || currentPlayers[i] == null) {
+ throw new IllegalStateException();
+ }
+ currentPlayers[i] = null;
+ }
+ };
+ }
+ }
+
+ ServerListPingEvent event = new ServerListPingEvent();
+ server.server.getPluginManager().callEvent(event);
+
+ java.util.List<GameProfile> profiles = new java.util.ArrayList<GameProfile>(players.length);
+ for (Object player : players) {
+ if (player != null) {
+ ServerPlayer entityPlayer = ((ServerPlayer) player);
+ if (entityPlayer.allowsListing()) {
+ profiles.add(entityPlayer.getGameProfile());
+ } else {
+ profiles.add(MinecraftServer.ANONYMOUS_PLAYER_PROFILE);
+ }
+ }
+ }
+
+ ServerStatus.ServerPingPlayerSample playerSample = new ServerStatus.ServerPingPlayerSample(event.getMaxPlayers(), profiles.size(), (server.hidesOnlinePlayers()) ? Collections.emptyList() : profiles);
+
+ ServerStatus ping = new ServerStatus(
+ CraftChatMessage.fromString(event.getMotd(), true)[0],
+ Optional.of(playerSample),
+ Optional.of(new ServerStatus.Version(server.getServerModName() + " " + server.getServerVersion(), SharedConstants.getCurrentVersion().getProtocolVersion())),
+ (event.icon.value != null) ? Optional.of(new ServerStatus.a(event.icon.value)) : Optional.empty(),
+ server.enforceSecureProfile()
+ );
+
+ this.connection.send(new ClientboundStatusResponsePacket(ping));
+ // CraftBukkit end
}
}

View file

@ -0,0 +1,36 @@
--- a/net/minecraft/server/players/BanListEntry.java
+++ b/net/minecraft/server/players/BanListEntry.java
@@ -26,8 +26,8 @@
this.reason = s1 == null ? "Banned by an operator." : s1;
}
- protected BanListEntry(@Nullable T t0, JsonObject jsonobject) {
- super(t0);
+ protected BanListEntry(@Nullable T user, JsonObject entryData) {
+ super(checkExpiry(user, entryData)); // CraftBukkit
Date date;
@@ -85,4 +83,22 @@
jsonobject.addProperty("expires", this.expires == null ? "forever" : BanListEntry.DATE_FORMAT.format(this.expires));
jsonobject.addProperty("reason", this.reason);
}
+
+ // CraftBukkit start
+ private static <T> T checkExpiry(T object, JsonObject jsonobject) {
+ Date expires = null;
+
+ try {
+ expires = jsonobject.has("expires") ? DATE_FORMAT.parse(jsonobject.get("expires").getAsString()) : null;
+ } catch (ParseException ex) {
+ // Guess we don't have a date
+ }
+
+ if (expires == null || expires.after(new Date())) {
+ return object;
+ } else {
+ return null;
+ }
+ }
+ // CraftBukkit end
}

View file

@ -0,0 +1,71 @@
--- a/net/minecraft/server/players/OldUsersConverter.java
+++ b/net/minecraft/server/players/OldUsersConverter.java
@@ -85,7 +88,7 @@
try {
userbanlist.load();
} catch (IOException ioexception) {
- OldUsersConverter.LOGGER.warn("Could not load existing file {}", userbanlist.getFile().getName(), ioexception);
+ OldUsersConverter.LOGGER.warn("Could not load existing file {}", gameprofilebanlist.getFile().getName()); // CraftBukkit - don't print stacktrace
}
}
@@ -145,7 +146,7 @@
try {
ipbanlist.load();
} catch (IOException ioexception) {
- OldUsersConverter.LOGGER.warn("Could not load existing file {}", ipbanlist.getFile().getName(), ioexception);
+ OldUsersConverter.LOGGER.warn("Could not load existing file {}", ipbanlist.getFile().getName()); // CraftBukkit - don't print stacktrace
}
}
@@ -186,7 +187,7 @@
try {
serveroplist.load();
} catch (IOException ioexception) {
- OldUsersConverter.LOGGER.warn("Could not load existing file {}", serveroplist.getFile().getName(), ioexception);
+ OldUsersConverter.LOGGER.warn("Could not load existing file {}", oplist.getFile().getName()); // CraftBukkit - don't print stacktrace
}
}
@@ -232,7 +231,7 @@
try {
userwhitelist.load();
} catch (IOException ioexception) {
- OldUsersConverter.LOGGER.warn("Could not load existing file {}", userwhitelist.getFile().getName(), ioexception);
+ OldUsersConverter.LOGGER.warn("Could not load existing file {}", whitelist.getFile().getName()); // CraftBukkit - don't print stacktrace
}
}
@@ -357,7 +350,31 @@
File file5 = new File(file, s2 + ".dat");
File file6 = new File(file4, s3 + ".dat");
- OldUsersConverter.ensureDirectoryExists(file4);
+ // CraftBukkit start - Use old file name to seed lastKnownName
+ CompoundTag root = null;
+
+ try {
+ root = NbtIo.readCompressed(new java.io.FileInputStream(file5), NbtAccounter.unlimitedHeap());
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ }
+
+ if (root != null) {
+ if (!root.contains("bukkit")) {
+ root.put("bukkit", new CompoundTag());
+ }
+ CompoundTag data = root.getCompound("bukkit");
+ data.putString("lastKnownName", oldFileName);
+
+ try {
+ NbtIo.writeCompressed(root, new java.io.FileOutputStream(file2));
+ } catch (Exception exception) {
+ exception.printStackTrace();
+ }
+ }
+ // CraftBukkit end
+
+ OldUsersConverter.ensureDirectoryExists(file);
if (!file5.renameTo(file6)) {
throw new OldUsersConverter.ConversionError("Could not convert file for " + s2);
}

View file

@ -0,0 +1,856 @@
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -101,6 +101,25 @@
import net.minecraft.world.scores.PlayerTeam;
import org.slf4j.Logger;
+// CraftBukkit start
+import java.util.stream.Collectors;
+import net.minecraft.server.dedicated.DedicatedServer;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.CraftServer;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.craftbukkit.util.CraftChatMessage;
+import org.bukkit.craftbukkit.util.CraftLocation;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerChangedWorldEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerLoginEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.event.player.PlayerRespawnEvent;
+import org.bukkit.event.player.PlayerRespawnEvent.RespawnReason;
+import org.bukkit.event.player.PlayerSpawnChangeEvent;
+// CraftBukkit end
+
public abstract class PlayerList {
public static final File USERBANLIST_FILE = new File("banned-players.json");
@@ -113,15 +132,17 @@
private static final int SEND_PLAYER_INFO_INTERVAL = 600;
private static final SimpleDateFormat BAN_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z");
private final MinecraftServer server;
- private final List<ServerPlayer> players = Lists.newArrayList();
+ public final List<ServerPlayer> players = new java.util.concurrent.CopyOnWriteArrayList(); // CraftBukkit - ArrayList -> CopyOnWriteArrayList: Iterator safety
private final Map<UUID, ServerPlayer> playersByUUID = Maps.newHashMap();
private final UserBanList bans;
private final IpBanList ipBans;
private final ServerOpList ops;
private final UserWhiteList whitelist;
- private final Map<UUID, ServerStatsCounter> stats;
- private final Map<UUID, PlayerAdvancements> advancements;
- private final PlayerDataStorage playerIo;
+ // CraftBukkit start
+ // private final Map<UUID, ServerStatisticManager> stats;
+ // private final Map<UUID, AdvancementDataPlayer> advancements;
+ // CraftBukkit end
+ public final PlayerDataStorage playerIo;
private boolean doWhiteList;
private final LayeredRegistryAccess<RegistryLayer> registries;
protected final int maxPlayers;
@@ -131,17 +152,27 @@
private static final boolean ALLOW_LOGOUTIVATOR = false;
private int sendAllPlayerInfoIn;
- public PlayerList(MinecraftServer minecraftserver, LayeredRegistryAccess<RegistryLayer> layeredregistryaccess, PlayerDataStorage playerdatastorage, int i) {
+ // CraftBukkit start
+ private CraftServer cserver;
+
+ public PlayerList(MinecraftServer server, LayeredRegistryAccess<RegistryLayer> registries, PlayerDataStorage playerIo, int maxPlayers) {
+ this.cserver = server.server = new CraftServer((DedicatedServer) server, this);
+ server.console = org.bukkit.craftbukkit.command.ColouredConsoleSender.getInstance();
+ server.reader.addCompleter(new org.bukkit.craftbukkit.command.ConsoleCommandCompleter(server.server));
+ // CraftBukkit end
+
this.bans = new UserBanList(PlayerList.USERBANLIST_FILE);
this.ipBans = new IpBanList(PlayerList.IPBANLIST_FILE);
this.ops = new ServerOpList(PlayerList.OPLIST_FILE);
this.whitelist = new UserWhiteList(PlayerList.WHITELIST_FILE);
- this.stats = Maps.newHashMap();
- this.advancements = Maps.newHashMap();
- this.server = minecraftserver;
- this.registries = layeredregistryaccess;
- this.maxPlayers = i;
- this.playerIo = playerdatastorage;
+ // CraftBukkit start
+ // this.stats = Maps.newHashMap();
+ // this.advancements = Maps.newHashMap();
+ // CraftBukkit end
+ this.server = server;
+ this.registries = registries;
+ this.maxPlayers = maxPlayers;
+ this.playerIo = playerIo;
}
public void placeNewPlayer(Connection connection, ServerPlayer serverplayer, CommonListenerCookie commonlistenercookie) {
@@ -160,15 +191,21 @@
CompoundTag compoundtag = this.load(serverplayer);
ResourceKey resourcekey;
+ // CraftBukkit start - Better rename detection
+ if (nbttagcompound != null && nbttagcompound.contains("bukkit")) {
+ CompoundTag bukkit = nbttagcompound.getCompound("bukkit");
+ s = bukkit.contains("lastKnownName", 8) ? bukkit.getString("lastKnownName") : s;
+ }
+ // CraftBukkit end
if (compoundtag != null) {
DataResult dataresult = DimensionType.parseLegacy(new Dynamic(NbtOps.INSTANCE, compoundtag.get("Dimension")));
Logger logger = PlayerList.LOGGER;
Objects.requireNonNull(logger);
- resourcekey = (ResourceKey) dataresult.resultOrPartial(logger::error).orElse(Level.OVERWORLD);
+ resourcekey = (ResourceKey) dataresult.resultOrPartial(logger::error).orElse(entityplayer.serverLevel().dimension()); // CraftBukkit - SPIGOT-7507: If no dimension, fall back to existing dimension loaded from "WorldUUID", which in turn defaults to World.OVERWORLD
} else {
- resourcekey = Level.OVERWORLD;
+ resourcekey = entityplayer.serverLevel().dimension(); // CraftBukkit - SPIGOT-7507: If no dimension, fall back to existing dimension loaded from "WorldUUID", which in turn defaults to World.OVERWORLD
}
ResourceKey<Level> resourcekey1 = resourcekey;
@@ -185,8 +222,9 @@
serverplayer.setServerLevel(serverlevel1);
String s1 = connection.getLoggableAddress(this.server.logIPs());
- PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ({}, {}, {})", new Object[]{serverplayer.getName().getString(), s1, serverplayer.getId(), serverplayer.getX(), serverplayer.getY(), serverplayer.getZ()});
- LevelData leveldata = serverlevel1.getLevelData();
+ // CraftBukkit - Moved message to after join
+ // PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ({}, {}, {})", new Object[]{entityplayer.getName().getString(), s1, entityplayer.getId(), entityplayer.getX(), entityplayer.getY(), entityplayer.getZ()});
+ LevelData worlddata = worldserver1.getLevelData();
serverplayer.loadGameTypes(compoundtag);
ServerGamePacketListenerImpl servergamepacketlistenerimpl = new ServerGamePacketListenerImpl(this.server, connection, serverplayer, commonlistenercookie);
@@ -195,15 +233,16 @@
boolean flag1 = gamerules.getBoolean(GameRules.RULE_REDUCEDDEBUGINFO);
boolean flag2 = gamerules.getBoolean(GameRules.RULE_LIMITED_CRAFTING);
- servergamepacketlistenerimpl.send(new ClientboundLoginPacket(serverplayer.getId(), leveldata.isHardcore(), this.server.levelKeys(), this.getMaxPlayers(), this.viewDistance, this.simulationDistance, flag1, !flag, flag2, serverplayer.createCommonSpawnInfo(serverlevel1)));
- servergamepacketlistenerimpl.send(new ClientboundChangeDifficultyPacket(leveldata.getDifficulty(), leveldata.isDifficultyLocked()));
- servergamepacketlistenerimpl.send(new ClientboundPlayerAbilitiesPacket(serverplayer.getAbilities()));
- servergamepacketlistenerimpl.send(new ClientboundSetCarriedItemPacket(serverplayer.getInventory().selected));
- servergamepacketlistenerimpl.send(new ClientboundUpdateRecipesPacket(this.server.getRecipeManager().getRecipes()));
- this.sendPlayerPermissionLevel(serverplayer);
- serverplayer.getStats().markAllDirty();
- serverplayer.getRecipeBook().sendInitialRecipeBook(serverplayer);
- this.updateEntireScoreboard(serverlevel1.getScoreboard(), serverplayer);
+ playerconnection.send(new ClientboundLoginPacket(entityplayer.getId(), worlddata.isHardcore(), this.server.levelKeys(), this.getMaxPlayers(), this.viewDistance, this.simulationDistance, flag1, !flag, flag2, entityplayer.createCommonSpawnInfo(worldserver1)));
+ entityplayer.getBukkitEntity().sendSupportedChannels(); // CraftBukkit
+ playerconnection.send(new ClientboundChangeDifficultyPacket(worlddata.getDifficulty(), worlddata.isDifficultyLocked()));
+ playerconnection.send(new ClientboundPlayerAbilitiesPacket(entityplayer.getAbilities()));
+ playerconnection.send(new ClientboundSetCarriedItemPacket(entityplayer.getInventory().selected));
+ playerconnection.send(new ClientboundUpdateRecipesPacket(this.server.getRecipeManager().getRecipes()));
+ this.sendPlayerPermissionLevel(entityplayer);
+ entityplayer.getStats().markAllDirty();
+ entityplayer.getRecipeBook().sendInitialRecipeBook(entityplayer);
+ this.updateEntireScoreboard(worldserver1.getScoreboard(), entityplayer);
this.server.invalidateStatus();
MutableComponent mutablecomponent;
@@ -212,6 +251,9 @@
} else {
mutablecomponent = Component.translatable("multiplayer.player.joined.renamed", serverplayer.getDisplayName(), s);
}
+ // CraftBukkit start
+ ichatmutablecomponent.withStyle(ChatFormatting.YELLOW);
+ String joinMessage = CraftChatMessage.fromComponent(ichatmutablecomponent);
this.broadcastSystemMessage(mutablecomponent.withStyle(ChatFormatting.YELLOW), false);
servergamepacketlistenerimpl.teleport(serverplayer.getX(), serverplayer.getY(), serverplayer.getZ(), serverplayer.getYRot(), serverplayer.getXRot());
@@ -221,25 +262,79 @@
serverplayer.sendServerStatus(serverstatus);
}
- serverplayer.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(this.players));
- this.players.add(serverplayer);
- this.playersByUUID.put(serverplayer.getUUID(), serverplayer);
- this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(serverplayer)));
- this.sendLevelInfo(serverplayer, serverlevel1);
- serverlevel1.addNewPlayer(serverplayer);
- this.server.getCustomBossEvents().onPlayerConnect(serverplayer);
- Iterator iterator = serverplayer.getActiveEffects().iterator();
+ // entityplayer.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(this.players)); // CraftBukkit - replaced with loop below
+ this.players.add(entityplayer);
+ this.playersByUUID.put(entityplayer.getUUID(), entityplayer);
+ // this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer))); // CraftBukkit - replaced with loop below
+ // CraftBukkit start
+ CraftPlayer bukkitPlayer = entityplayer.getBukkitEntity();
+
+ // Ensure that player inventory is populated with its viewer
+ entityplayer.containerMenu.transferTo(entityplayer.containerMenu, bukkitPlayer);
+
+ PlayerJoinEvent playerJoinEvent = new PlayerJoinEvent(bukkitPlayer, joinMessage);
+ cserver.getPluginManager().callEvent(playerJoinEvent);
+
+ if (!entityplayer.connection.isAcceptingMessages()) {
+ return;
+ }
+
+ joinMessage = playerJoinEvent.getJoinMessage();
+
+ if (joinMessage != null && joinMessage.length() > 0) {
+ for (Component line : org.bukkit.craftbukkit.util.CraftChatMessage.fromString(joinMessage)) {
+ server.getPlayerList().broadcastSystemMessage(line, false);
+ }
+ }
+ // CraftBukkit end
+
+ // CraftBukkit start - sendAll above replaced with this loop
+ ClientboundPlayerInfoUpdatePacket packet = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer));
+
+ for (int i = 0; i < this.players.size(); ++i) {
+ ServerPlayer entityplayer1 = (ServerPlayer) this.players.get(i);
+
+ if (entityplayer1.getBukkitEntity().canSee(bukkitPlayer)) {
+ entityplayer1.connection.send(packet);
+ }
+
+ if (!bukkitPlayer.canSee(entityplayer1.getBukkitEntity())) {
+ continue;
+ }
+
+ entityplayer.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(entityplayer1)));
+ }
+ entityplayer.sentListPacket = true;
+ // CraftBukkit end
+
+ entityplayer.getEntityData().refresh(entityplayer); // CraftBukkit - BungeeCord#2321, send complete data to self on spawn
+
+ this.sendLevelInfo(entityplayer, worldserver1);
+
+ // CraftBukkit start - Only add if the player wasn't moved in the event
+ if (entityplayer.level() == worldserver1 && !worldserver1.players().contains(entityplayer)) {
+ worldserver1.addNewPlayer(entityplayer);
+ this.server.getCustomBossEvents().onPlayerConnect(entityplayer);
+ }
+
+ worldserver1 = entityplayer.serverLevel(); // CraftBukkit - Update in case join event changed it
+ // CraftBukkit end
+ Iterator iterator = entityplayer.getActiveEffects().iterator();
+
while (iterator.hasNext()) {
MobEffectInstance mobeffectinstance = (MobEffectInstance) iterator.next();
servergamepacketlistenerimpl.send(new ClientboundUpdateMobEffectPacket(serverplayer.getId(), mobeffectinstance));
}
- if (compoundtag != null && compoundtag.contains("RootVehicle", 10)) {
- CompoundTag compoundtag1 = compoundtag.getCompound("RootVehicle");
- Entity entity = EntityType.loadEntityRecursive(compoundtag1.getCompound("Entity"), serverlevel1, (entity1) -> {
- return !serverlevel1.addWithUUID(entity1) ? null : entity1;
+ if (nbttagcompound != null && nbttagcompound.contains("RootVehicle", 10)) {
+ CompoundTag nbttagcompound1 = nbttagcompound.getCompound("RootVehicle");
+ // CraftBukkit start
+ ServerLevel finalWorldServer = worldserver1;
+ Entity entity = EntityType.loadEntityRecursive(nbttagcompound1.getCompound("Entity"), finalWorldServer, (entity1) -> {
+ return !finalWorldServer.addWithUUID(entity1) ? null : entity1;
+ // CraftBukkit end
});
if (entity != null) {
@@ -281,7 +376,9 @@
}
}
- serverplayer.initInventoryMenu();
+ entityplayer.initInventoryMenu();
+ // CraftBukkit - Moved from above, added world
+ PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", entityplayer.getName().getString(), s1, entityplayer.getId(), worldserver1.serverLevelData.getLevelName(), entityplayer.getX(), entityplayer.getY(), entityplayer.getZ());
}
protected void updateEntireScoreboard(ServerScoreboard serverscoreboard, ServerPlayer serverplayer) {
@@ -317,36 +414,32 @@
}
- public void addWorldborderListener(ServerLevel serverlevel) {
- serverlevel.getWorldBorder().addListener(new BorderChangeListener() {
+ public void addWorldborderListener(ServerLevel level) {
+ if (playerIo != null) return; // CraftBukkit
+ level.getWorldBorder().addListener(new BorderChangeListener() {
@Override
- @Override
- public void onBorderSizeSet(WorldBorder worldborder, double d0) {
- PlayerList.this.broadcastAll(new ClientboundSetBorderSizePacket(worldborder));
+ public void onBorderSizeSet(WorldBorder border, double size) {
+ PlayerList.this.broadcastAll(new ClientboundSetBorderSizePacket(border), border.world); // CraftBukkit
}
@Override
- @Override
- public void onBorderSizeLerping(WorldBorder worldborder, double d0, double d1, long i) {
- PlayerList.this.broadcastAll(new ClientboundSetBorderLerpSizePacket(worldborder));
+ public void onBorderSizeLerping(WorldBorder border, double oldSize, double d1, long newSize) {
+ PlayerList.this.broadcastAll(new ClientboundSetBorderLerpSizePacket(border), border.world); // CraftBukkit
}
@Override
- @Override
- public void onBorderCenterSet(WorldBorder worldborder, double d0, double d1) {
- PlayerList.this.broadcastAll(new ClientboundSetBorderCenterPacket(worldborder));
+ public void onBorderCenterSet(WorldBorder border, double x, double d1) {
+ PlayerList.this.broadcastAll(new ClientboundSetBorderCenterPacket(border), border.world); // CraftBukkit
}
@Override
- @Override
- public void onBorderSetWarningTime(WorldBorder worldborder, int i) {
- PlayerList.this.broadcastAll(new ClientboundSetBorderWarningDelayPacket(worldborder));
+ public void onBorderSetWarningTime(WorldBorder border, int warningTime) {
+ PlayerList.this.broadcastAll(new ClientboundSetBorderWarningDelayPacket(border), border.world); // CraftBukkit
}
@Override
- @Override
- public void onBorderSetWarningBlocks(WorldBorder worldborder, int i) {
- PlayerList.this.broadcastAll(new ClientboundSetBorderWarningDistancePacket(worldborder));
+ public void onBorderSetWarningBlocks(WorldBorder border, int warningBlocks) {
+ PlayerList.this.broadcastAll(new ClientboundSetBorderWarningDistancePacket(border), border.world); // CraftBukkit
}
@Override
@@ -375,15 +466,16 @@
return compoundtag1;
}
- protected void save(ServerPlayer serverplayer) {
- this.playerIo.save(serverplayer);
- ServerStatsCounter serverstatscounter = (ServerStatsCounter) this.stats.get(serverplayer.getUUID());
+ protected void save(ServerPlayer player) {
+ if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit
+ this.playerIo.save(player);
+ ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit
if (serverstatscounter != null) {
serverstatscounter.save();
}
- PlayerAdvancements playeradvancements = (PlayerAdvancements) this.advancements.get(serverplayer.getUUID());
+ PlayerAdvancements advancementdataplayer = (PlayerAdvancements) player.getAdvancements(); // CraftBukkit
if (playeradvancements != null) {
playeradvancements.save();
@@ -391,14 +483,31 @@
}
- public void remove(ServerPlayer serverplayer) {
- ServerLevel serverlevel = serverplayer.serverLevel();
+ public String remove(ServerPlayer entityplayer) { // CraftBukkit - return string
+ ServerLevel worldserver = entityplayer.serverLevel();
serverplayer.awardStat(Stats.LEAVE_GAME);
this.save(serverplayer);
if (serverplayer.isPassenger()) {
Entity entity = serverplayer.getRootVehicle();
+ // CraftBukkit start - Quitting must be before we do final save of data, in case plugins need to modify it
+ // See SPIGOT-5799, SPIGOT-6145
+ if (entityplayer.containerMenu != entityplayer.inventoryMenu) {
+ entityplayer.closeContainer();
+ }
+
+ PlayerQuitEvent playerQuitEvent = new PlayerQuitEvent(entityplayer.getBukkitEntity(), entityplayer.kickLeaveMessage != null ? entityplayer.kickLeaveMessage : "\u00A7e" + entityplayer.getScoreboardName() + " left the game");
+ cserver.getPluginManager().callEvent(playerQuitEvent);
+ entityplayer.getBukkitEntity().disconnect(playerQuitEvent.getQuitMessage());
+
+ entityplayer.doTick(); // SPIGOT-924
+ // CraftBukkit end
+
+ this.save(entityplayer);
+ if (entityplayer.isPassenger()) {
+ Entity entity = entityplayer.getRootVehicle();
+
if (entity.hasExactlyOnePlayerPassenger()) {
PlayerList.LOGGER.debug("Removing player mount");
serverplayer.stopRiding();
@@ -418,16 +524,34 @@
if (serverplayer1 == serverplayer) {
this.playersByUUID.remove(uuid);
- this.stats.remove(uuid);
- this.advancements.remove(uuid);
+ // CraftBukkit start
+ // this.stats.remove(uuid);
+ // this.advancements.remove(uuid);
+ // CraftBukkit end
}
- this.broadcastAll(new ClientboundPlayerInfoRemovePacket(List.of(serverplayer.getUUID())));
+ // CraftBukkit start
+ // this.broadcastAll(new ClientboundPlayerInfoRemovePacket(List.of(entityplayer.getUUID())));
+ ClientboundPlayerInfoRemovePacket packet = new ClientboundPlayerInfoRemovePacket(List.of(entityplayer.getUUID()));
+ for (int i = 0; i < players.size(); i++) {
+ ServerPlayer entityplayer2 = (ServerPlayer) this.players.get(i);
+
+ if (entityplayer2.getBukkitEntity().canSee(entityplayer.getBukkitEntity())) {
+ entityplayer2.connection.send(packet);
+ } else {
+ entityplayer2.getBukkitEntity().onEntityRemove(entityplayer);
+ }
+ }
+ // This removes the scoreboard (and player reference) for the specific player in the manager
+ cserver.getScoreboardManager().removePlayer(entityplayer.getBukkitEntity());
+ // CraftBukkit end
+
+ return playerQuitEvent.getQuitMessage(); // CraftBukkit
}
- @Nullable
- public Component canPlayerLogin(SocketAddress socketaddress, GameProfile gameprofile) {
- MutableComponent mutablecomponent;
+ // CraftBukkit start - Whole method, SocketAddress to LoginListener, added hostname to signature, return EntityPlayer
+ public ServerPlayer canPlayerLogin(ServerLoginPacketListenerImpl loginlistener, GameProfile gameprofile) {
+ MutableComponent ichatmutablecomponent;
if (this.bans.isBanned(gameprofile)) {
UserBanListEntry userbanlistentry = (UserBanListEntry) this.bans.get(gameprofile);
@@ -437,7 +566,33 @@
mutablecomponent.append((Component) Component.translatable("multiplayer.disconnect.banned.expiration", PlayerList.BAN_DATE_FORMAT.format(userbanlistentry.getExpires())));
}
- return mutablecomponent;
+ Iterator iterator = list.iterator();
+
+ while (iterator.hasNext()) {
+ entityplayer = (ServerPlayer) iterator.next();
+ save(entityplayer); // CraftBukkit - Force the player's inventory to be saved
+ entityplayer.connection.disconnect(Component.translatable("multiplayer.disconnect.duplicate_login"));
+ }
+
+ // Instead of kicking then returning, we need to store the kick reason
+ // in the event, check with plugins to see if it's ok, and THEN kick
+ // depending on the outcome.
+ SocketAddress socketaddress = loginlistener.connection.getRemoteAddress();
+
+ ServerPlayer entity = new ServerPlayer(this.server, this.server.getLevel(Level.OVERWORLD), gameprofile, ClientInformation.createDefault());
+ Player player = entity.getBukkitEntity();
+ PlayerLoginEvent event = new PlayerLoginEvent(player, loginlistener.connection.hostname, ((java.net.InetSocketAddress) socketaddress).getAddress());
+
+ if (getBans().isBanned(gameprofile) && !getBans().get(gameprofile).hasExpired()) {
+ UserBanListEntry gameprofilebanentry = (UserBanListEntry) this.bans.get(gameprofile);
+
+ ichatmutablecomponent = Component.translatable("multiplayer.disconnect.banned.reason", gameprofilebanentry.getReason());
+ if (gameprofilebanentry.getExpires() != null) {
+ ichatmutablecomponent.append((Component) Component.translatable("multiplayer.disconnect.banned.expiration", PlayerList.BAN_DATE_FORMAT.format(gameprofilebanentry.getExpires())));
+ }
+
+ // return chatmessage;
+ event.disallow(PlayerLoginEvent.Result.KICK_BANNED, CraftChatMessage.fromComponent(ichatmutablecomponent));
} else if (!this.isWhiteListed(gameprofile)) {
return Component.translatable("multiplayer.disconnect.not_whitelisted");
} else if (this.ipBans.isBanned(socketaddress)) {
@@ -454,11 +621,15 @@
}
}
- public ServerPlayer getPlayerForLogin(GameProfile gameprofile, ClientInformation clientinformation) {
- return new ServerPlayer(this.server, this.server.overworld(), gameprofile, clientinformation);
+ // CraftBukkit start - added EntityPlayer
+ public ServerPlayer getPlayerForLogin(GameProfile gameprofile, ClientInformation clientinformation, ServerPlayer player) {
+ player.updateOptions(clientinformation);
+ return player;
+ // CraftBukkit end
}
- public boolean disconnectAllPlayersWithProfile(GameProfile gameprofile) {
+ public boolean disconnectAllPlayersWithProfile(GameProfile gameprofile, ServerPlayer player) { // CraftBukkit - added EntityPlayer
+ /* CraftBukkit startMoved up
UUID uuid = gameprofile.getId();
Set<ServerPlayer> set = Sets.newIdentityHashSet();
Iterator iterator = this.players.iterator();
@@ -486,15 +657,25 @@
}
return !set.isEmpty();
+ */
+ return player == null;
+ // CraftBukkit end
}
- public ServerPlayer respawn(ServerPlayer serverplayer, boolean flag) {
- this.players.remove(serverplayer);
- serverplayer.serverLevel().removePlayerImmediately(serverplayer, Entity.RemovalReason.DISCARDED);
- BlockPos blockpos = serverplayer.getRespawnPosition();
- float f = serverplayer.getRespawnAngle();
- boolean flag1 = serverplayer.isRespawnForced();
- ServerLevel serverlevel = this.server.getLevel(serverplayer.getRespawnDimension());
+ // CraftBukkit start
+ public ServerPlayer respawn(ServerPlayer entityplayer, boolean flag, RespawnReason reason) {
+ return this.respawn(entityplayer, this.server.getLevel(entityplayer.getRespawnDimension()), flag, null, true, reason);
+ }
+
+ public ServerPlayer respawn(ServerPlayer entityplayer, ServerLevel worldserver, boolean flag, Location location, boolean avoidSuffocation, RespawnReason reason) {
+ entityplayer.stopRiding(); // CraftBukkit
+ this.players.remove(entityplayer);
+ entityplayer.serverLevel().removePlayerImmediately(entityplayer, Entity.RemovalReason.DISCARDED);
+ BlockPos blockposition = entityplayer.getRespawnPosition();
+ float f = entityplayer.getRespawnAngle();
+ boolean flag1 = entityplayer.isRespawnForced();
+ /* CraftBukkit start
+ WorldServer worldserver = this.server.getLevel(entityplayer.getRespawnDimension());
Optional optional;
if (serverlevel != null && blockpos != null) {
@@ -503,8 +684,13 @@
optional = Optional.empty();
}
- ServerLevel serverlevel1 = serverlevel != null && optional.isPresent() ? serverlevel : this.server.overworld();
- ServerPlayer serverplayer1 = new ServerPlayer(this.server, serverlevel1, serverplayer.getGameProfile(), serverplayer.clientInformation());
+ WorldServer worldserver1 = worldserver != null && optional.isPresent() ? worldserver : this.server.overworld();
+ EntityPlayer entityplayer1 = new EntityPlayer(this.server, worldserver1, entityplayer.getGameProfile(), entityplayer.clientInformation());
+ // */
+ ServerPlayer entityplayer1 = entityplayer;
+ org.bukkit.World fromWorld = entityplayer.getBukkitEntity().getWorld();
+ entityplayer.wonGame = false;
+ // CraftBukkit end
serverplayer1.connection = serverplayer.connection;
serverplayer1.restoreFrom(serverplayer, flag);
@@ -520,18 +706,40 @@
boolean flag2 = false;
- if (optional.isPresent()) {
- BlockState blockstate = serverlevel1.getBlockState(blockpos);
- boolean flag3 = blockstate.is(Blocks.RESPAWN_ANCHOR);
- Vec3 vec3 = (Vec3) optional.get();
- float f1;
+ // CraftBukkit start - fire PlayerRespawnEvent
+ if (location == null) {
+ boolean isBedSpawn = false;
+ ServerLevel worldserver1 = this.server.getLevel(entityplayer.getRespawnDimension());
+ if (worldserver1 != null) {
+ Optional optional;
if (!blockstate.is(BlockTags.BEDS) && !flag3) {
f1 = f;
} else {
Vec3 vec31 = Vec3.atBottomCenterOf(blockpos).subtract(vec3).normalize();
- f1 = (float) Mth.wrapDegrees(Mth.atan2(vec31.z, vec31.x) * 57.2957763671875D - 90.0D);
+ if (optional.isPresent()) {
+ IBlockData iblockdata = worldserver1.getBlockState(blockposition);
+ boolean flag3 = iblockdata.is(Blocks.RESPAWN_ANCHOR);
+ Vec3 vec3d = (Vec3) optional.get();
+ float f1;
+
+ if (!iblockdata.is(BlockTags.BEDS) && !flag3) {
+ f1 = f;
+ } else {
+ Vec3 vec3d1 = Vec3.atBottomCenterOf(blockposition).subtract(vec3d).normalize();
+
+ f1 = (float) Mth.wrapDegrees(Mth.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D - 90.0D);
+ }
+
+ // entityplayer1.setRespawnPosition(worldserver1.dimension(), blockposition, f, flag1, false); // CraftBukkit - not required, just copies old location into reused entity
+ flag2 = !flag && flag3;
+ isBedSpawn = true;
+ location = CraftLocation.toBukkit(vec3d, worldserver1.getWorld(), f1, 0.0F);
+ } else if (blockposition != null) {
+ entityplayer1.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.NO_RESPAWN_BLOCK_AVAILABLE, 0.0F));
+ entityplayer1.setRespawnPosition(null, null, 0f, false, false, PlayerSpawnChangeEvent.Cause.RESET); // CraftBukkit - SPIGOT-5988: Clear respawn location when obstructed
+ }
}
serverplayer1.moveTo(vec3.x, vec3.y, vec3.z, f1, 0.0F);
@@ -541,31 +764,48 @@
serverplayer1.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.NO_RESPAWN_BLOCK_AVAILABLE, 0.0F));
}
- while (!serverlevel1.noCollision((Entity) serverplayer1) && serverplayer1.getY() < (double) serverlevel1.getMaxBuildHeight()) {
- serverplayer1.setPos(serverplayer1.getX(), serverplayer1.getY() + 1.0D, serverplayer1.getZ());
+ while (avoidSuffocation && !worldserver1.noCollision((Entity) entityplayer1) && entityplayer1.getY() < (double) worldserver1.getMaxBuildHeight()) {
+ // CraftBukkit end
+ entityplayer1.setPos(entityplayer1.getX(), entityplayer1.getY() + 1.0D, entityplayer1.getZ());
}
int i = flag ? 1 : 0;
ServerLevel serverlevel2 = serverplayer1.serverLevel();
LevelData leveldata = serverlevel2.getLevelData();
- serverplayer1.connection.send(new ClientboundRespawnPacket(serverplayer1.createCommonSpawnInfo(serverlevel2), (byte) i));
- serverplayer1.connection.teleport(serverplayer1.getX(), serverplayer1.getY(), serverplayer1.getZ(), serverplayer1.getYRot(), serverplayer1.getXRot());
- serverplayer1.connection.send(new ClientboundSetDefaultSpawnPositionPacket(serverlevel1.getSharedSpawnPos(), serverlevel1.getSharedSpawnAngle()));
- serverplayer1.connection.send(new ClientboundChangeDifficultyPacket(leveldata.getDifficulty(), leveldata.isDifficultyLocked()));
- serverplayer1.connection.send(new ClientboundSetExperiencePacket(serverplayer1.experienceProgress, serverplayer1.totalExperience, serverplayer1.experienceLevel));
- this.sendLevelInfo(serverplayer1, serverlevel1);
- this.sendPlayerPermissionLevel(serverplayer1);
- serverlevel1.addRespawnedPlayer(serverplayer1);
- this.players.add(serverplayer1);
- this.playersByUUID.put(serverplayer1.getUUID(), serverplayer1);
- serverplayer1.initInventoryMenu();
- serverplayer1.setHealth(serverplayer1.getHealth());
+ entityplayer1.connection.send(new ClientboundRespawnPacket(entityplayer1.createCommonSpawnInfo(worldserver2), (byte) i));
+ entityplayer1.connection.teleport(CraftLocation.toBukkit(entityplayer1.position(), worldserver2.getWorld(), entityplayer1.getYRot(), entityplayer1.getXRot())); // CraftBukkit
+ entityplayer1.connection.send(new ClientboundSetDefaultSpawnPositionPacket(worldserver1.getSharedSpawnPos(), worldserver1.getSharedSpawnAngle()));
+ entityplayer1.connection.send(new ClientboundChangeDifficultyPacket(worlddata.getDifficulty(), worlddata.isDifficultyLocked()));
+ entityplayer1.connection.send(new ClientboundSetExperiencePacket(entityplayer1.experienceProgress, entityplayer1.totalExperience, entityplayer1.experienceLevel));
+ this.sendLevelInfo(entityplayer1, worldserver1);
+ this.sendPlayerPermissionLevel(entityplayer1);
+ if (!entityplayer.connection.isDisconnected()) {
+ worldserver1.addRespawnedPlayer(entityplayer1);
+ this.players.add(entityplayer1);
+ this.playersByUUID.put(entityplayer1.getUUID(), entityplayer1);
+ }
+ // entityplayer1.initInventoryMenu();
+ entityplayer1.setHealth(entityplayer1.getHealth());
if (flag2) {
serverplayer1.connection.send(new ClientboundSoundPacket(SoundEvents.RESPAWN_ANCHOR_DEPLETE, SoundSource.BLOCKS, (double) blockpos.getX(), (double) blockpos.getY(), (double) blockpos.getZ(), 1.0F, 1.0F, serverlevel1.getRandom().nextLong()));
}
- return serverplayer1;
+ // Fire advancement trigger
+ entityplayer.triggerDimensionChangeTriggers(((CraftWorld) fromWorld).getHandle());
+
+ // Don't fire on respawn
+ if (fromWorld != location.getWorld()) {
+ PlayerChangedWorldEvent event = new PlayerChangedWorldEvent(entityplayer.getBukkitEntity(), fromWorld);
+ server.server.getPluginManager().callEvent(event);
+ }
+
+ // Save player file again if they were disconnected
+ if (entityplayer.connection.isDisconnected()) {
+ this.save(entityplayer);
+ }
+ // CraftBukkit end
+ return entityplayer1;
}
public void sendPlayerPermissionLevel(ServerPlayer serverplayer) {
@@ -577,7 +823,18 @@
public void tick() {
if (++this.sendAllPlayerInfoIn > 600) {
- this.broadcastAll(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY), this.players));
+ // CraftBukkit start
+ for (int i = 0; i < this.players.size(); ++i) {
+ final ServerPlayer target = (ServerPlayer) this.players.get(i);
+
+ target.connection.send(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY), this.players.stream().filter(new Predicate<ServerPlayer>() {
+ @Override
+ public boolean test(ServerPlayer input) {
+ return target.getBukkitEntity().canSee(input.getBukkitEntity());
+ }
+ }).collect(Collectors.toList())));
+ }
+ // CraftBukkit end
this.sendAllPlayerInfoIn = 0;
}
@@ -594,7 +851,26 @@
}
- public void broadcastAll(Packet<?> packet, ResourceKey<Level> resourcekey) {
+ // CraftBukkit start - add a world/entity limited version
+ public void broadcastAll(Packet packet, net.minecraft.world.entity.player.Player entityhuman) {
+ for (int i = 0; i < this.players.size(); ++i) {
+ ServerPlayer entityplayer = this.players.get(i);
+ if (entityhuman != null && !entityplayer.getBukkitEntity().canSee(entityhuman.getBukkitEntity())) {
+ continue;
+ }
+ ((ServerPlayer) this.players.get(i)).connection.send(packet);
+ }
+ }
+
+ public void broadcastAll(Packet packet, Level world) {
+ for (int i = 0; i < world.players().size(); ++i) {
+ ((ServerPlayer) world.players().get(i)).connection.send(packet);
+ }
+
+ }
+ // CraftBukkit end
+
+ public void broadcastAll(Packet<?> packet, ResourceKey<Level> dimension) {
Iterator iterator = this.players.iterator();
while (iterator.hasNext()) {
@@ -696,7 +972,8 @@
serverplayer.connection.send(new ClientboundEntityEventPacket(serverplayer, b0));
}
- this.server.getCommands().sendCommands(serverplayer);
+ player.getBukkitEntity().recalculatePermissions(); // CraftBukkit
+ this.server.getCommands().sendCommands(player);
}
public boolean isWhiteListed(GameProfile gameprofile) {
@@ -726,10 +1003,11 @@
for (int i = 0; i < this.players.size(); ++i) {
ServerPlayer serverplayer = (ServerPlayer) this.players.get(i);
- if (serverplayer != player && serverplayer.level().dimension() == resourcekey) {
- double d4 = d0 - serverplayer.getX();
- double d5 = d1 - serverplayer.getY();
- double d6 = d2 - serverplayer.getZ();
+ // CraftBukkit start - Test if player receiving packet can see the source of the packet
+ if (except != null && !entityplayer.getBukkitEntity().canSee(except.getBukkitEntity())) {
+ continue;
+ }
+ // CraftBukkit end
if (d4 * d4 + d5 * d5 + d6 * d6 < d3 * d3) {
serverplayer.connection.send(packet);
@@ -764,26 +1047,38 @@
public void reloadWhiteList() {}
- public void sendLevelInfo(ServerPlayer serverplayer, ServerLevel serverlevel) {
- WorldBorder worldborder = this.server.overworld().getWorldBorder();
+ public void sendLevelInfo(ServerPlayer player, ServerLevel level) {
+ WorldBorder worldborder = player.level().getWorldBorder(); // CraftBukkit
- serverplayer.connection.send(new ClientboundInitializeBorderPacket(worldborder));
- serverplayer.connection.send(new ClientboundSetTimePacket(serverlevel.getGameTime(), serverlevel.getDayTime(), serverlevel.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)));
- serverplayer.connection.send(new ClientboundSetDefaultSpawnPositionPacket(serverlevel.getSharedSpawnPos(), serverlevel.getSharedSpawnAngle()));
- if (serverlevel.isRaining()) {
- serverplayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.START_RAINING, 0.0F));
- serverplayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.RAIN_LEVEL_CHANGE, serverlevel.getRainLevel(1.0F)));
- serverplayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, serverlevel.getThunderLevel(1.0F)));
+ player.connection.send(new ClientboundInitializeBorderPacket(worldborder));
+ player.connection.send(new ClientboundSetTimePacket(level.getGameTime(), level.getDayTime(), level.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)));
+ player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getSharedSpawnPos(), level.getSharedSpawnAngle()));
+ if (level.isRaining()) {
+ // CraftBukkit start - handle player weather
+ // entityplayer.connection.send(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.START_RAINING, 0.0F));
+ // entityplayer.connection.send(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.RAIN_LEVEL_CHANGE, worldserver.getRainLevel(1.0F)));
+ // entityplayer.connection.send(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.THUNDER_LEVEL_CHANGE, worldserver.getThunderLevel(1.0F)));
+ player.setPlayerWeather(org.bukkit.WeatherType.DOWNFALL, false);
+ player.updateWeather(-level.rainLevel, level.rainLevel, -level.thunderLevel, level.thunderLevel);
+ // CraftBukkit end
}
serverplayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.LEVEL_CHUNKS_LOAD_START, 0.0F));
this.server.tickRateManager().updateJoiningPlayer(serverplayer);
}
- public void sendAllPlayerInfo(ServerPlayer serverplayer) {
- serverplayer.inventoryMenu.sendAllDataToRemote();
- serverplayer.resetSentInfo();
- serverplayer.connection.send(new ClientboundSetCarriedItemPacket(serverplayer.getInventory().selected));
+ public void sendAllPlayerInfo(ServerPlayer player) {
+ player.inventoryMenu.sendAllDataToRemote();
+ // entityplayer.resetSentInfo();
+ player.getBukkitEntity().updateScaledHealth(); // CraftBukkit - Update scaled health on respawn and worldchange
+ player.getEntityData().refresh(player); // CraftBukkkit - SPIGOT-7218: sync metadata
+ player.connection.send(new ClientboundSetCarriedItemPacket(player.getInventory().selected));
+ // CraftBukkit start - from GameRules
+ int i = player.level().getGameRules().getBoolean(GameRules.RULE_REDUCEDDEBUGINFO) ? 22 : 23;
+ player.connection.send(new ClientboundEntityEventPacket(player, (byte) i));
+ float immediateRespawn = player.level().getGameRules().getBoolean(GameRules.RULE_DO_IMMEDIATE_RESPAWN) ? 1.0F: 0.0F;
+ player.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.IMMEDIATE_RESPAWN, immediateRespawn));
+ // CraftBukkit end
}
public int getPlayerCount() {
@@ -839,17 +1134,21 @@
}
public void removeAll() {
- for (int i = 0; i < this.players.size(); ++i) {
- ((ServerPlayer) this.players.get(i)).connection.disconnect(Component.translatable("multiplayer.disconnect.server_shutdown"));
+ // CraftBukkit start - disconnect safely
+ for (ServerPlayer player : this.players) {
+ player.connection.disconnect(this.server.server.getShutdownMessage()); // CraftBukkit - add custom shutdown message
}
+ // CraftBukkit end
}
- public void broadcastSystemMessage(Component component, boolean flag) {
- this.broadcastSystemMessage(component, (serverplayer) -> {
- return component;
- }, flag);
+ // CraftBukkit start
+ public void broadcastMessage(Component[] iChatBaseComponents) {
+ for (Component component : iChatBaseComponents) {
+ broadcastSystemMessage(component, false);
+ }
}
+ // CraftBukkit end
public void broadcastSystemMessage(Component component, Function<ServerPlayer, Component> function, boolean flag) {
this.server.sendSystemMessage(component);
@@ -902,16 +1207,23 @@
return playerchatmessage.hasSignature() && !playerchatmessage.hasExpiredServer(Instant.now());
}
- public ServerStatsCounter getPlayerStats(Player player) {
- UUID uuid = player.getUUID();
- ServerStatsCounter serverstatscounter = (ServerStatsCounter) this.stats.get(uuid);
+ // CraftBukkit start
+ public ServerStatsCounter getPlayerStats(ServerPlayer entityhuman) {
+ ServerStatsCounter serverstatisticmanager = entityhuman.getStats();
+ return serverstatisticmanager == null ? getPlayerStats(entityhuman.getUUID(), entityhuman.getDisplayName().getString()) : serverstatisticmanager;
+ }
- if (serverstatscounter == null) {
+ public ServerStatsCounter getPlayerStats(UUID uuid, String displayName) {
+ ServerPlayer entityhuman = this.getPlayer(uuid);
+ ServerStatsCounter serverstatisticmanager = entityhuman == null ? null : (ServerStatsCounter) entityhuman.getStats();
+ // CraftBukkit end
+
+ if (serverstatisticmanager == null) {
File file = this.server.getWorldPath(LevelResource.PLAYER_STATS_DIR).toFile();
File file1 = new File(file, uuid + ".json");
if (!file1.exists()) {
- File file2 = new File(file, player.getName().getString() + ".json");
+ File file2 = new File(file, displayName + ".json"); // CraftBukkit
Path path = file2.toPath();
if (FileUtil.isPathNormalized(path) && FileUtil.isPathPortable(path) && path.startsWith(file.getPath()) && file2.isFile()) {
@@ -919,22 +1231,22 @@
}
}
- serverstatscounter = new ServerStatsCounter(this.server, file1);
- this.stats.put(uuid, serverstatscounter);
+ serverstatisticmanager = new ServerStatsCounter(this.server, file1);
+ // this.stats.put(uuid, serverstatisticmanager); // CraftBukkit
}
return serverstatscounter;
}
- public PlayerAdvancements getPlayerAdvancements(ServerPlayer serverplayer) {
- UUID uuid = serverplayer.getUUID();
- PlayerAdvancements playeradvancements = (PlayerAdvancements) this.advancements.get(uuid);
+ public PlayerAdvancements getPlayerAdvancements(ServerPlayer player) {
+ UUID uuid = player.getUUID();
+ PlayerAdvancements advancementdataplayer = (PlayerAdvancements) player.getAdvancements(); // CraftBukkit
if (playeradvancements == null) {
Path path = this.server.getWorldPath(LevelResource.PLAYER_ADVANCEMENTS_DIR).resolve(uuid + ".json");
- playeradvancements = new PlayerAdvancements(this.server.getFixerUpper(), this, this.server.getAdvancements(), path, serverplayer);
- this.advancements.put(uuid, playeradvancements);
+ advancementdataplayer = new PlayerAdvancements(this.server.getFixerUpper(), this, this.server.getAdvancements(), path, player);
+ // this.advancements.put(uuid, advancementdataplayer); // CraftBukkit
}
playeradvancements.setPlayer(serverplayer);
@@ -985,13 +1297,20 @@
}
public void reloadResources() {
- Iterator iterator = this.advancements.values().iterator();
+ // CraftBukkit start
+ /*Iterator iterator = this.advancements.values().iterator();
while (iterator.hasNext()) {
PlayerAdvancements playeradvancements = (PlayerAdvancements) iterator.next();
- playeradvancements.reload(this.server.getAdvancements());
+ advancementdataplayer.reload(this.server.getAdvancements());
+ }*/
+
+ for (ServerPlayer player : players) {
+ player.getAdvancements().reload(this.server.getAdvancements());
+ player.getAdvancements().flushDirty(player); // CraftBukkit - trigger immediate flush of advancements
}
+ // CraftBukkit end
this.broadcastAll(new ClientboundUpdateTagsPacket(TagNetworkSerialization.serializeTagsToNetwork(this.registries)));
ClientboundUpdateRecipesPacket clientboundupdaterecipespacket = new ClientboundUpdateRecipesPacket(this.server.getRecipeManager().getRecipes());

View file

@ -0,0 +1,48 @@
--- a/net/minecraft/server/players/SleepStatus.java
+++ b/net/minecraft/server/players/SleepStatus.java
@@ -17,10 +17,13 @@
return this.sleepingPlayers >= this.sleepersNeeded(i);
}
- public boolean areEnoughDeepSleeping(int i, List<ServerPlayer> list) {
- int j = (int) list.stream().filter(Player::isSleepingLongEnough).count();
+ public boolean areEnoughDeepSleeping(int requiredSleepPercentage, List<ServerPlayer> sleepingPlayers) {
+ // CraftBukkit start
+ int j = (int) sleepingPlayers.stream().filter((eh) -> { return eh.isSleepingLongEnough() || eh.fauxSleeping; }).count();
+ boolean anyDeepSleep = sleepingPlayers.stream().anyMatch(Player::isSleepingLongEnough);
- return j >= this.sleepersNeeded(i);
+ return anyDeepSleep && j >= this.sleepersNeeded(requiredSleepPercentage);
+ // CraftBukkit end
}
public int sleepersNeeded(int i) {
@@ -41,19 +44,25 @@
this.activePlayers = 0;
this.sleepingPlayers = 0;
- Iterator iterator = list.iterator();
+ Iterator iterator = players.iterator();
+ boolean anySleep = false; // CraftBukkit
while (iterator.hasNext()) {
ServerPlayer serverplayer = (ServerPlayer) iterator.next();
if (!serverplayer.isSpectator()) {
++this.activePlayers;
- if (serverplayer.isSleeping()) {
+ if (entityplayer.isSleeping() || entityplayer.fauxSleeping) { // CraftBukkit
++this.sleepingPlayers;
}
+ // CraftBukkit start
+ if (entityplayer.isSleeping()) {
+ anySleep = true;
+ }
+ // CraftBukkit end
}
}
- return (j > 0 || this.sleepingPlayers > 0) && (i != this.activePlayers || j != this.sleepingPlayers);
+ return anySleep && (j > 0 || this.sleepingPlayers > 0) && (i != this.activePlayers || j != this.sleepingPlayers); // CraftBukkit
}
}

View file

@ -0,0 +1,46 @@
--- a/net/minecraft/server/rcon/RconConsoleSource.java
+++ b/net/minecraft/server/rcon/RconConsoleSource.java
@@ -8,15 +8,23 @@
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
-
+// CraftBukkit start
+import java.net.SocketAddress;
+import org.bukkit.craftbukkit.command.CraftRemoteConsoleCommandSender;
+// CraftBukkit end
public class RconConsoleSource implements CommandSource {
private static final String RCON = "Rcon";
private static final Component RCON_COMPONENT = Component.literal("Rcon");
private final StringBuffer buffer = new StringBuffer();
private final MinecraftServer server;
+ // CraftBukkit start
+ public final SocketAddress socketAddress;
+ private final CraftRemoteConsoleCommandSender remoteConsole = new CraftRemoteConsoleCommandSender(this);
- public RconConsoleSource(MinecraftServer minecraftserver) {
+ public RconConsoleSource(MinecraftServer minecraftserver, SocketAddress socketAddress) {
+ this.socketAddress = socketAddress;
+ // CraftBukkit end
this.server = minecraftserver;
}
@@ -34,7 +42,17 @@
return new CommandSourceStack(this, Vec3.atLowerCornerOf(serverlevel.getSharedSpawnPos()), Vec2.ZERO, serverlevel, 4, "Rcon", RconConsoleSource.RCON_COMPONENT, this.server, (Entity) null);
}
+ // CraftBukkit start - Send a String
+ public void sendMessage(String message) {
+ this.buffer.append(message);
+ }
+
@Override
+ public org.bukkit.command.CommandSender getBukkitSender(CommandSourceStack wrapper) {
+ return this.remoteConsole;
+ }
+ // CraftBukkit end
+
@Override
public void sendSystemMessage(Component component) {
this.buffer.append(component.getString());

View file

@ -0,0 +1,74 @@
--- a/net/minecraft/server/rcon/thread/RconClient.java
+++ b/net/minecraft/server/rcon/thread/RconClient.java
@@ -9,6 +10,8 @@
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import net.minecraft.server.ServerInterface;
+// CraftBukkit start
+import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.rcon.PktUtils;
import org.slf4j.Logger;
@@ -24,12 +27,15 @@
private final Socket client;
private final byte[] buf = new byte[1460];
private final String rconPassword;
- private final ServerInterface serverInterface;
+ // CraftBukkit start
+ private final DedicatedServer serverInterface;
+ private final RconConsoleSource rconConsoleSource;
+ // CraftBukkit end
- RconClient(ServerInterface serverinterface, String s, Socket socket) {
- super("RCON Client " + socket.getInetAddress());
- this.serverInterface = serverinterface;
- this.client = socket;
+ RconClient(ServerInterface serverInterface, String rconPassword, Socket client) {
+ super("RCON Client " + client.getInetAddress());
+ this.serverInterface = (DedicatedServer) serverInterface; // CraftBukkit
+ this.client = client;
try {
this.client.setSoTimeout(0);
@@ -37,13 +43,16 @@
this.running = false;
}
- this.rconPassword = s;
+ this.rconPassword = rconPassword;
+ this.rconConsoleSource = new net.minecraft.server.rcon.RconConsoleSource(this.serverInterface, client.getRemoteSocketAddress()); // CraftBukkit
}
@Override
public void run() {
- while (true) {
- try {
+ // CraftBukkit start - decompile error: switch try / while statement
+ try {
+ while (true) {
+ // CraftBukkit end
if (!this.running) {
return;
}
@@ -72,7 +80,7 @@
String s = PktUtils.stringFromByteArray(this.buf, k, i);
try {
- this.sendCmdResponse(l, this.serverInterface.runCommand(s));
+ this.sendCmdResponse(l, this.serverInterface.runCommand(this.rconConsoleSource, s)); // CraftBukkit
} catch (Exception exception) {
this.sendCmdResponse(l, "Error executing: " + s + " (" + exception.getMessage() + ")");
}
@@ -110,8 +119,10 @@
this.running = false;
}
- return;
- }
+ // CraftBukkit start - decompile error: switch try / while statement
+ // return;
+ // }
+ // CraftBukkit end
}
private void send(int i, int j, String s) throws IOException {

View file

@ -0,0 +1,28 @@
--- a/net/minecraft/stats/ServerRecipeBook.java
+++ b/net/minecraft/stats/ServerRecipeBook.java
@@ -20,6 +20,8 @@
import net.minecraft.world.item.crafting.RecipeManager;
import org.slf4j.Logger;
+import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit
+
public class ServerRecipeBook extends RecipeBook {
public static final String RECIPE_BOOK_TAG = "recipeBook";
@@ -36,11 +38,11 @@
RecipeHolder<?> recipeholder = (RecipeHolder) iterator.next();
ResourceLocation resourcelocation = recipeholder.id();
- if (!this.known.contains(resourcelocation) && !recipeholder.value().isSpecial()) {
- this.add(resourcelocation);
- this.addHighlight(resourcelocation);
- list.add(resourcelocation);
- CriteriaTriggers.RECIPE_UNLOCKED.trigger(serverplayer, recipeholder);
+ if (!this.known.contains(minecraftkey) && !recipeholder.value().isSpecial() && CraftEventFactory.handlePlayerRecipeListUpdateEvent(player, minecraftkey)) { // CraftBukkit
+ this.add(minecraftkey);
+ this.addHighlight(minecraftkey);
+ list.add(minecraftkey);
+ CriteriaTriggers.RECIPE_UNLOCKED.trigger(player, recipeholder);
++i;
}
}

View file

@ -0,0 +1,15 @@
--- a/net/minecraft/stats/StatsCounter.java
+++ b/net/minecraft/stats/StatsCounter.java
@@ -16,6 +16,12 @@
public void increment(Player player, Stat<?> stat, int i) {
int j = (int) Math.min((long) this.getValue(stat) + (long) i, 2147483647L);
+ // CraftBukkit start - fire Statistic events
+ org.bukkit.event.Cancellable cancellable = org.bukkit.craftbukkit.event.CraftEventFactory.handleStatisticsIncrease(player, stat, this.getValue(stat), j);
+ if (cancellable != null && cancellable.isCancelled()) {
+ return;
+ }
+ // CraftBukkit end
this.setValue(player, stat, j);
}

View file

@ -0,0 +1,31 @@
--- a/net/minecraft/util/SpawnUtil.java
+++ b/net/minecraft/util/SpawnUtil.java
@@ -20,9 +20,15 @@
public SpawnUtil() {}
- public static <T extends Mob> Optional<T> trySpawnMob(EntityType<T> entitytype, MobSpawnType mobspawntype, ServerLevel serverlevel, BlockPos blockpos, int i, int j, int k, SpawnUtil.Strategy spawnutil_strategy) {
- BlockPos.MutableBlockPos blockpos_mutableblockpos = blockpos.mutable();
+ public static <T extends Mob> Optional<T> trySpawnMob(EntityType<T> entityType, EnumMobSpawn spawnType, ServerLevel level, BlockPos pos, int attempts, int j, int yOffset, SpawnUtil.Strategy strategy) {
+ // CraftBukkit start
+ return trySpawnMob(entityType, spawnType, level, pos, attempts, j, yOffset, strategy, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT);
+ }
+ public static <T extends Mob> Optional<T> trySpawnMob(EntityType<T> entitytypes, EnumMobSpawn enummobspawn, ServerLevel worldserver, BlockPos blockposition, int i, int j, int k, SpawnUtil.Strategy spawnutil_a, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) {
+ // CraftBukkit end
+ BlockPos.MutableBlockPos blockposition_mutableblockposition = blockposition.mutable();
+
for (int l = 0; l < i; ++l) {
int i1 = Mth.randomBetweenInclusive(serverlevel.random, -j, j);
int j1 = Mth.randomBetweenInclusive(serverlevel.random, -j, j);
@@ -32,8 +38,8 @@
T t0 = (Mob) entitytype.create(serverlevel, (CompoundTag) null, (Consumer) null, blockpos_mutableblockpos, mobspawntype, false, false);
if (t0 != null) {
- if (t0.checkSpawnRules(serverlevel, mobspawntype) && t0.checkSpawnObstruction(serverlevel)) {
- serverlevel.addFreshEntityWithPassengers(t0);
+ if (t0.checkSpawnRules(worldserver, enummobspawn) && t0.checkSpawnObstruction(worldserver)) {
+ worldserver.addFreshEntityWithPassengers(t0, reason); // CraftBukkit
return Optional.of(t0);
}

View file

@ -0,0 +1,29 @@
--- a/net/minecraft/util/datafix/DataFixers.java
+++ b/net/minecraft/util/datafix/DataFixers.java
@@ -455,10 +279,22 @@
datafixerbuilder.addFixer(new EntityItemFrameDirectionFix(schema44, false));
Schema schema45 = datafixerbuilder.addSchema(1458, DataFixers.SAME_NAMESPACED);
- datafixerbuilder.addFixer(new EntityCustomNameToComponentFix(schema45, false));
- datafixerbuilder.addFixer(new ItemCustomNameToComponentFix(schema45, false));
- datafixerbuilder.addFixer(new BlockEntityCustomNameToComponentFix(schema45, false));
- Schema schema46 = datafixerbuilder.addSchema(1460, V1460::new);
+ // CraftBukkit start
+ builder.addFixer(new com.mojang.datafixers.DataFix(schema45, false) {
+ @Override
+ protected com.mojang.datafixers.TypeRewriteRule makeRule() {
+ return this.fixTypeEverywhereTyped("Player CustomName", this.getInputSchema().getType(DataConverterTypes.PLAYER), (typed) -> {
+ return typed.update(DSL.remainderFinder(), (dynamic) -> {
+ return EntityCustomNameToComponentFix.fixTagCustomName(dynamic);
+ });
+ });
+ }
+ });
+ // CraftBukkit end
+ builder.addFixer(new EntityCustomNameToComponentFix(schema45, false));
+ builder.addFixer(new ItemCustomNameToComponentFix(schema45, false));
+ builder.addFixer(new BlockEntityCustomNameToComponentFix(schema45, false));
+ Schema schema46 = builder.addSchema(1460, V1460::new);
datafixerbuilder.addFixer(new EntityPaintingMotiveFix(schema46, false));
Schema schema47 = datafixerbuilder.addSchema(1466, V1466::new);

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/util/datafix/fixes/ItemStackMapIdFix.java
+++ b/net/minecraft/util/datafix/fixes/ItemStackMapIdFix.java
@@ -33,7 +32,7 @@
Typed<?> typed1 = typed.getOrCreateTyped(opticfinder1);
Dynamic<?> dynamic1 = (Dynamic) typed1.get(DSL.remainderFinder());
- dynamic1 = dynamic1.set("map", dynamic1.createInt(dynamic.get("Damage").asInt(0)));
+ if (!dynamic1.getElement("map").result().isPresent()) dynamic1 = dynamic1.set("map", dynamic1.createInt(dynamic.get("Damage").asInt(0))); // CraftBukkit
return typed.set(opticfinder1, typed1.set(DSL.remainderFinder(), dynamic1));
} else {
return typed;

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/util/datafix/fixes/ItemStackTheFlatteningFix.java
+++ b/net/minecraft/util/datafix/fixes/ItemStackTheFlatteningFix.java
@@ -377,7 +376,7 @@
Typed<?> typed2 = typed.getOrCreateTyped(opticfinder1);
Dynamic<?> dynamic1 = (Dynamic) typed2.get(DSL.remainderFinder());
- dynamic1 = dynamic1.set("Damage", dynamic1.createInt(i));
+ if (i != 0) dynamic1 = dynamic1.set("Damage", dynamic1.createInt(i)); // CraftBukkit
typed1 = typed1.set(opticfinder1, typed2.set(DSL.remainderFinder(), dynamic1));
}

View file

@ -0,0 +1,37 @@
--- a/net/minecraft/util/worldupdate/WorldUpgrader.java
+++ b/net/minecraft/util/worldupdate/WorldUpgrader.java
@@ -64,13 +64,13 @@
private static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$");
private final DimensionDataStorage overworldDataStorage;
- public WorldUpgrader(LevelStorageSource.LevelStorageAccess levelstoragesource_levelstorageaccess, DataFixer datafixer, Registry<LevelStem> registry, boolean flag) {
- this.dimensions = registry;
- this.levels = (Set) registry.registryKeySet().stream().map(Registries::levelStemToLevel).collect(Collectors.toUnmodifiableSet());
- this.eraseCache = flag;
- this.dataFixer = datafixer;
- this.levelStorage = levelstoragesource_levelstorageaccess;
- this.overworldDataStorage = new DimensionDataStorage(this.levelStorage.getDimensionPath(Level.OVERWORLD).resolve("data").toFile(), datafixer);
+ public WorldUpgrader(LevelStorageSource.LevelStorageAccess levelStoarge, DataFixer dataFixer, Registry<LevelStem> dimensions, boolean eraseCache) {
+ this.dimensions = dimensions;
+ this.levels = (Set) java.util.stream.Stream.of(levelStoarge.dimensionType).map(Registries::levelStemToLevel).collect(Collectors.toUnmodifiableSet()); // CraftBukkit
+ this.eraseCache = eraseCache;
+ this.dataFixer = dataFixer;
+ this.levelStorage = levelStoarge;
+ this.overworldDataStorage = new DimensionDataStorage(this.levelStorage.getDimensionPath(Level.OVERWORLD).resolve("data").toFile(), dataFixer);
this.thread = WorldUpgrader.THREAD_FACTORY.newThread(this::work);
this.thread.setUncaughtExceptionHandler((thread, throwable) -> {
WorldUpgrader.LOGGER.error("Error upgrading world", throwable);
@@ -145,10 +145,10 @@
if (compoundtag != null) {
int j = ChunkStorage.getVersion(compoundtag);
ChunkGenerator chunkgenerator = ((LevelStem) this.dimensions.getOrThrow(Registries.levelToLevelStem(resourcekey2))).generator();
- CompoundTag compoundtag1 = chunkstorage.upgradeChunkTag(resourcekey2, () -> {
+ CompoundTag nbttagcompound1 = ichunkloader.upgradeChunkTag(Registries.levelToLevelStem(resourcekey2), () -> { // CraftBukkit
return this.overworldDataStorage;
- }, compoundtag, chunkgenerator.getTypeNameForDataFixer());
- ChunkPos chunkpos1 = new ChunkPos(compoundtag1.getInt("xPos"), compoundtag1.getInt("zPos"));
+ }, nbttagcompound, chunkgenerator.getTypeNameForDataFixer(), chunkcoordintpair, null); // CraftBukkit
+ ChunkPos chunkcoordintpair1 = new ChunkPos(nbttagcompound1.getInt("xPos"), nbttagcompound1.getInt("zPos"));
if (!chunkpos1.equals(chunkpos)) {
WorldUpgrader.LOGGER.warn("Chunk {} has invalid position {}", chunkpos, chunkpos1);

View file

@ -0,0 +1,57 @@
--- a/net/minecraft/world/CompoundContainer.java
+++ b/net/minecraft/world/CompoundContainer.java
@@ -3,17 +3,42 @@
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
+// CraftBukkit start
+import java.util.ArrayList;
+import java.util.List;
+import org.bukkit.Location;
+
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
+import org.bukkit.entity.HumanEntity;
+// CraftBukkit end
+
public class CompoundContainer implements Container {
private final Container container1;
private final Container container2;
- public CompoundContainer(Container container, Container container1) {
- this.container1 = container;
- this.container2 = container1;
+ // CraftBukkit start - add fields and methods
+ public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
+
+ public List<ItemStack> getContents() {
+ List<ItemStack> result = new ArrayList<ItemStack>(this.getContainerSize());
+ for (int i = 0; i < this.getContainerSize(); i++) {
+ result.add(this.getItem(i));
+ }
+ return result;
}
@Override
+ public Location getLocation() {
+ return container1.getLocation(); // TODO: right?
+ }
+ // CraftBukkit end
+
+ public CompoundContainer(Container container1, Container container2) {
+ this.container1 = container1;
+ this.container2 = container2;
+ }
+
@Override
public int getContainerSize() {
return this.container1.getContainerSize() + this.container2.getContainerSize();
@@ -61,7 +105,7 @@
@Override
@Override
public int getMaxStackSize() {
- return this.container1.getMaxStackSize();
+ return Math.min(this.container1.getMaxStackSize(), this.container2.getMaxStackSize()); // CraftBukkit - check both sides
}
@Override

View file

@ -0,0 +1,56 @@
--- a/net/minecraft/world/Container.java
+++ b/net/minecraft/world/Container.java
@@ -6,8 +6,12 @@
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
+// CraftBukkit start
+import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
+// CraftBukkit end
public interface Container extends Clearable {
@@ -26,9 +30,7 @@
void setItem(int slot, ItemStack stack);
- default int getMaxStackSize() {
- return 64;
- }
+ int getMaxStackSize(); // CraftBukkit
void setChanged();
@@ -88,4 +90,29 @@
return level == null ? false : (level.getBlockEntity(blockpos) != blockentity ? false : player.distanceToSqr((double) blockpos.getX() + 0.5D, (double) blockpos.getY() + 0.5D, (double) blockpos.getZ() + 0.5D) <= (double) (i * i));
}
+
+ // CraftBukkit start
+ java.util.List<ItemStack> getContents();
+
+ void onOpen(CraftHumanEntity who);
+
+ void onClose(CraftHumanEntity who);
+
+ java.util.List<org.bukkit.entity.HumanEntity> getViewers();
+
+ org.bukkit.inventory.InventoryHolder getOwner();
+
+ void setMaxStackSize(int size);
+
+ org.bukkit.Location getLocation();
+
+ default RecipeHolder<?> getCurrentRecipe() {
+ return null;
+ }
+
+ default void setCurrentRecipe(RecipeHolder<?> recipe) {
+ }
+
+ int MAX_STACK = 64;
+ // CraftBukkit end
}

Some files were not shown because too many files have changed in this diff Show more