This commit is contained in:
@@ -1,10 +1,21 @@
|
||||
package io.papermc.paper;
|
||||
|
||||
import io.papermc.paper.world.damagesource.CombatEntry;
|
||||
import io.papermc.paper.world.damagesource.FallLocationType;
|
||||
import io.papermc.paper.world.damagesource.PaperCombatEntryWrapper;
|
||||
import io.papermc.paper.world.damagesource.PaperCombatTrackerWrapper;
|
||||
import net.minecraft.Optionull;
|
||||
import net.minecraft.world.damagesource.FallLocation;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.craftbukkit.block.CraftBiome;
|
||||
import org.bukkit.craftbukkit.damage.CraftDamageEffect;
|
||||
import org.bukkit.craftbukkit.damage.CraftDamageSource;
|
||||
import org.bukkit.craftbukkit.entity.CraftLivingEntity;
|
||||
import org.bukkit.damage.DamageEffect;
|
||||
import org.bukkit.damage.DamageSource;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public class PaperServerInternalAPIBridge implements InternalAPIBridge {
|
||||
@@ -22,4 +33,42 @@ public class PaperServerInternalAPIBridge implements InternalAPIBridge {
|
||||
}
|
||||
return Holder.LEGACY_CUSTOM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CombatEntry createCombatEntry(final LivingEntity entity, final DamageSource damageSource, final float damage) {
|
||||
final net.minecraft.world.entity.LivingEntity mob = ((CraftLivingEntity) entity).getHandle();
|
||||
final FallLocation fallLocation = FallLocation.getCurrentFallLocation(mob);
|
||||
return createCombatEntry(
|
||||
((CraftDamageSource) damageSource).getHandle(),
|
||||
damage,
|
||||
fallLocation,
|
||||
(float) mob.fallDistance
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CombatEntry createCombatEntry(
|
||||
final DamageSource damageSource,
|
||||
final float damage,
|
||||
@Nullable final FallLocationType fallLocationType,
|
||||
final float fallDistance
|
||||
) {
|
||||
return createCombatEntry(
|
||||
((CraftDamageSource) damageSource).getHandle(),
|
||||
damage,
|
||||
Optionull.map(fallLocationType, PaperCombatTrackerWrapper::paperToMinecraft),
|
||||
fallDistance
|
||||
);
|
||||
}
|
||||
|
||||
private CombatEntry createCombatEntry(
|
||||
final net.minecraft.world.damagesource.DamageSource damageSource,
|
||||
final float damage,
|
||||
final net.minecraft.world.damagesource.@Nullable FallLocation fallLocation,
|
||||
final float fallDistance
|
||||
) {
|
||||
return new PaperCombatEntryWrapper(new net.minecraft.world.damagesource.CombatEntry(
|
||||
damageSource, damage, fallLocation, fallDistance
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
package io.papermc.paper.command;
|
||||
|
||||
import io.papermc.paper.FeatureHooks;
|
||||
import io.papermc.paper.command.subcommands.*;
|
||||
import io.papermc.paper.command.subcommands.DumpItemCommand;
|
||||
import io.papermc.paper.command.subcommands.DumpListenersCommand;
|
||||
import io.papermc.paper.command.subcommands.DumpPluginsCommand;
|
||||
import io.papermc.paper.command.subcommands.EntityCommand;
|
||||
import io.papermc.paper.command.subcommands.HeapDumpCommand;
|
||||
import io.papermc.paper.command.subcommands.MobcapsCommand;
|
||||
import io.papermc.paper.command.subcommands.ReloadCommand;
|
||||
import io.papermc.paper.command.subcommands.SyncLoadInfoCommand;
|
||||
import io.papermc.paper.command.subcommands.VersionCommand;
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
package io.papermc.paper.command;
|
||||
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import io.papermc.paper.command.brigadier.CommandRegistrationFlag;
|
||||
import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.command.Command;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
|
||||
@@ -15,16 +20,32 @@ public final class PaperCommands {
|
||||
}
|
||||
|
||||
private static final Map<String, Command> COMMANDS = new HashMap<>();
|
||||
static {
|
||||
|
||||
public static void registerCommands(final MinecraftServer server) {
|
||||
COMMANDS.put("paper", new PaperCommand("paper"));
|
||||
COMMANDS.put("callback", new CallbackCommand("callback"));
|
||||
COMMANDS.put("mspt", new MSPTCommand("mspt"));
|
||||
}
|
||||
|
||||
public static void registerCommands(final MinecraftServer server) {
|
||||
COMMANDS.forEach((s, command) -> {
|
||||
server.server.getCommandMap().register(s, "Paper", command);
|
||||
});
|
||||
server.server.getCommandMap().register("bukkit", new PaperPluginsCommand());
|
||||
}
|
||||
|
||||
public static void registerCommands() {
|
||||
// Paper commands go here
|
||||
registerInternalCommand(PaperVersionCommand.create(), "bukkit", PaperVersionCommand.DESCRIPTION, List.of("ver", "about"), Set.of());
|
||||
}
|
||||
|
||||
private static void registerInternalCommand(final LiteralCommandNode<CommandSourceStack> node, final String namespace, final String description, final List<String> aliases, final Set<CommandRegistrationFlag> flags) {
|
||||
io.papermc.paper.command.brigadier.PaperCommands.INSTANCE.registerWithFlagsInternal(
|
||||
null,
|
||||
namespace,
|
||||
"Paper",
|
||||
node,
|
||||
description,
|
||||
aliases,
|
||||
flags
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
package io.papermc.paper.command;
|
||||
|
||||
import com.destroystokyo.paper.PaperVersionFetcher;
|
||||
import com.destroystokyo.paper.util.VersionFetcher;
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||
import io.papermc.paper.command.brigadier.Commands;
|
||||
import io.papermc.paper.plugin.configuration.PluginMeta;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.util.StringUtil;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@NullMarked
|
||||
public class PaperVersionCommand {
|
||||
public static final String DESCRIPTION = "Gets the version of this server including any plugins in use";
|
||||
|
||||
private static final Component NOT_RUNNING = Component.text()
|
||||
.append(Component.text("This server is not running any plugin by that name."))
|
||||
.appendNewline()
|
||||
.append(Component.text("Use /plugins to get a list of plugins.").clickEvent(ClickEvent.suggestCommand("/plugins")))
|
||||
.build();
|
||||
private static final JoinConfiguration PLAYER_JOIN_CONFIGURATION = JoinConfiguration.separators(
|
||||
Component.text(", ", NamedTextColor.WHITE),
|
||||
Component.text(", and ", NamedTextColor.WHITE)
|
||||
);
|
||||
private static final Component FAILED_TO_FETCH = Component.text("Could not fetch version information!", NamedTextColor.RED);
|
||||
private static final Component FETCHING = Component.text("Checking version, please wait...", NamedTextColor.WHITE, TextDecoration.ITALIC);
|
||||
|
||||
private final VersionFetcher versionFetcher = new PaperVersionFetcher();
|
||||
private CompletableFuture<ComputedVersion> computedVersion = CompletableFuture.completedFuture(new ComputedVersion(Component.empty(), -1)); // Precompute-- someday move that stuff out of bukkit
|
||||
|
||||
public static LiteralCommandNode<CommandSourceStack> create() {
|
||||
final PaperVersionCommand command = new PaperVersionCommand();
|
||||
|
||||
return Commands.literal("version")
|
||||
.requires(source -> source.getSender().hasPermission("bukkit.command.version"))
|
||||
.then(Commands.argument("plugin", StringArgumentType.word())
|
||||
.suggests(command::suggestPlugins)
|
||||
.executes(command::pluginVersion))
|
||||
.executes(command::serverVersion)
|
||||
.build();
|
||||
}
|
||||
|
||||
private int pluginVersion(final CommandContext<CommandSourceStack> context) {
|
||||
final CommandSender sender = context.getSource().getSender();
|
||||
final String pluginName = context.getArgument("plugin", String.class).toLowerCase(Locale.ROOT);
|
||||
|
||||
Plugin plugin = Bukkit.getPluginManager().getPlugin(pluginName);
|
||||
if (plugin == null) {
|
||||
plugin = Arrays.stream(Bukkit.getPluginManager().getPlugins())
|
||||
.filter(checkPlugin -> checkPlugin.getName().toLowerCase(Locale.ROOT).contains(pluginName))
|
||||
.findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
if (plugin != null) {
|
||||
this.sendPluginInfo(plugin, sender);
|
||||
} else {
|
||||
sender.sendMessage(NOT_RUNNING);
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
private CompletableFuture<Suggestions> suggestPlugins(final CommandContext<CommandSourceStack> context, final SuggestionsBuilder builder) {
|
||||
for (final Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
|
||||
final String name = plugin.getName();
|
||||
if (StringUtil.startsWithIgnoreCase(name, builder.getRemainingLowerCase())) {
|
||||
builder.suggest(name);
|
||||
}
|
||||
}
|
||||
|
||||
return CompletableFuture.completedFuture(builder.build());
|
||||
}
|
||||
|
||||
private void sendPluginInfo(final Plugin plugin, final CommandSender sender) {
|
||||
final PluginMeta meta = plugin.getPluginMeta();
|
||||
|
||||
final TextComponent.Builder builder = Component.text()
|
||||
.append(Component.text(meta.getName()))
|
||||
.append(Component.text(" version "))
|
||||
.append(Component.text(meta.getVersion(), NamedTextColor.GREEN)
|
||||
.hoverEvent(Component.translatable("chat.copy.click"))
|
||||
.clickEvent(ClickEvent.copyToClipboard(meta.getVersion()))
|
||||
);
|
||||
|
||||
if (meta.getDescription() != null) {
|
||||
builder
|
||||
.appendNewline()
|
||||
.append(Component.text(meta.getDescription()));
|
||||
}
|
||||
|
||||
if (meta.getWebsite() != null) {
|
||||
Component websiteComponent = Component.text(meta.getWebsite(), NamedTextColor.GREEN).clickEvent(ClickEvent.openUrl(meta.getWebsite()));
|
||||
builder.appendNewline().append(Component.text("Website: ").append(websiteComponent));
|
||||
}
|
||||
|
||||
if (!meta.getAuthors().isEmpty()) {
|
||||
String prefix = meta.getAuthors().size() == 1 ? "Author: " : "Authors: ";
|
||||
builder.appendNewline().append(Component.text(prefix).append(formatNameList(meta.getAuthors())));
|
||||
}
|
||||
|
||||
if (!meta.getContributors().isEmpty()) {
|
||||
builder.appendNewline().append(Component.text("Contributors: ").append(formatNameList(meta.getContributors())));
|
||||
}
|
||||
sender.sendMessage(builder.build());
|
||||
}
|
||||
|
||||
private static Component formatNameList(final List<String> names) {
|
||||
return Component.join(PLAYER_JOIN_CONFIGURATION, names.stream().map(Component::text).toList()).color(NamedTextColor.GREEN);
|
||||
}
|
||||
|
||||
private int serverVersion(CommandContext<CommandSourceStack> context) {
|
||||
sendVersion(context.getSource().getSender());
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
|
||||
private void sendVersion(final CommandSender sender) {
|
||||
final CompletableFuture<ComputedVersion> version = getVersionOrFetch();
|
||||
if (!version.isDone()) {
|
||||
sender.sendMessage(FETCHING);
|
||||
}
|
||||
|
||||
version.whenComplete((computedVersion, throwable) -> {
|
||||
if (computedVersion != null) {
|
||||
sender.sendMessage(computedVersion.message);
|
||||
} else if (throwable != null) {
|
||||
sender.sendMessage(FAILED_TO_FETCH);
|
||||
MinecraftServer.LOGGER.warn("Could not fetch version information!", throwable);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private CompletableFuture<ComputedVersion> getVersionOrFetch() {
|
||||
if (!this.computedVersion.isDone()) {
|
||||
return this.computedVersion;
|
||||
}
|
||||
|
||||
if (this.computedVersion.isCompletedExceptionally() || System.currentTimeMillis() - this.computedVersion.resultNow().computedTime() > this.versionFetcher.getCacheTime()) {
|
||||
this.computedVersion = this.fetchVersionMessage();
|
||||
}
|
||||
|
||||
return this.computedVersion;
|
||||
}
|
||||
|
||||
private CompletableFuture<ComputedVersion> fetchVersionMessage() {
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
final Component message = Component.textOfChildren(
|
||||
Component.text(Bukkit.getVersionMessage(), NamedTextColor.WHITE),
|
||||
Component.newline(),
|
||||
this.versionFetcher.getVersionMessage()
|
||||
);
|
||||
|
||||
return new ComputedVersion(
|
||||
message.hoverEvent(Component.translatable("chat.copy.click", NamedTextColor.WHITE))
|
||||
.clickEvent(ClickEvent.copyToClipboard(PlainTextComponentSerializer.plainText().serialize(message))),
|
||||
System.currentTimeMillis()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
record ComputedVersion(Component message, long computedTime) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package io.papermc.paper.command.brigadier;
|
||||
|
||||
import io.papermc.paper.plugin.configuration.PluginMeta;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public record APICommandMeta(@Nullable PluginMeta pluginMeta, @Nullable String description, List<String> aliases, @Nullable String helpCommandNamespace, boolean serverSideOnly) {
|
||||
|
||||
public APICommandMeta(final @Nullable PluginMeta pluginMeta, final @Nullable String description) {
|
||||
this(pluginMeta, description, Collections.emptyList(), null, false);
|
||||
}
|
||||
|
||||
public APICommandMeta {
|
||||
aliases = List.copyOf(aliases);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Plugin plugin() {
|
||||
return this.pluginMeta == null ? null : Objects.requireNonNull(Bukkit.getPluginManager().getPlugin(this.pluginMeta.getName()));
|
||||
}
|
||||
|
||||
public APICommandMeta withAliases(List<String> registeredAliases) {
|
||||
return new APICommandMeta(this.pluginMeta, this.description, List.copyOf(registeredAliases), this.helpCommandNamespace, this.serverSideOnly);
|
||||
}
|
||||
}
|
||||
@@ -35,8 +35,8 @@ public final class PaperBrigadier {
|
||||
throw new IllegalArgumentException("Unsure how to wrap a " + node);
|
||||
}
|
||||
|
||||
final PluginCommandMeta meta;
|
||||
if ((meta = node.pluginCommandMeta) == null) {
|
||||
final APICommandMeta meta;
|
||||
if ((meta = node.apiCommandMeta) == null) {
|
||||
return new VanillaCommandWrapper(node);
|
||||
}
|
||||
CommandNode<CommandSourceStack> argumentCommandNode = node;
|
||||
@@ -46,6 +46,12 @@ public final class PaperBrigadier {
|
||||
|
||||
Map<CommandNode<CommandSourceStack>, String> map = PaperCommands.INSTANCE.getDispatcherInternal().getSmartUsage(argumentCommandNode, DUMMY);
|
||||
String usage = map.isEmpty() ? node.getUsageText() : node.getUsageText() + " " + String.join("\n" + node.getUsageText() + " ", map.values());
|
||||
|
||||
// Internal command
|
||||
if (meta.pluginMeta() == null) {
|
||||
return new VanillaCommandWrapper(node.getName(), meta.description(), usage, meta.aliases(), node, meta.helpCommandNamespace());
|
||||
}
|
||||
|
||||
return new PluginVanillaCommandWrapper(node.getName(), meta.description(), usage, meta.aliases(), node, meta.plugin());
|
||||
}
|
||||
|
||||
|
||||
@@ -91,10 +91,13 @@ public class PaperCommands implements Commands, PaperRegistrar<LifecycleEventOwn
|
||||
|
||||
@Override
|
||||
public @Unmodifiable Set<String> registerWithFlags(final PluginMeta pluginMeta, final LiteralCommandNode<CommandSourceStack> node, final @Nullable String description, final Collection<String> aliases, final Set<CommandRegistrationFlag> flags) {
|
||||
final PluginCommandMeta meta = new PluginCommandMeta(pluginMeta, description);
|
||||
final String identifier = pluginMeta.getName().toLowerCase(Locale.ROOT);
|
||||
return registerWithFlagsInternal(pluginMeta, pluginMeta.getName().toLowerCase(Locale.ROOT), null, node, description, aliases, flags);
|
||||
}
|
||||
|
||||
public @Unmodifiable Set<String> registerWithFlagsInternal(final @Nullable PluginMeta pluginMeta, final String namespace, final @Nullable String helpNamespaceOverride, final LiteralCommandNode<CommandSourceStack> node, final @Nullable String description, final Collection<String> aliases, final Set<CommandRegistrationFlag> flags) {
|
||||
final APICommandMeta meta = new APICommandMeta(pluginMeta, description, List.of(), helpNamespaceOverride, flags.contains(CommandRegistrationFlag.SERVER_ONLY));
|
||||
final String literal = node.getLiteral();
|
||||
final LiteralCommandNode<CommandSourceStack> pluginLiteral = PaperBrigadier.copyLiteral(identifier + ":" + literal, node);
|
||||
final LiteralCommandNode<CommandSourceStack> pluginLiteral = PaperBrigadier.copyLiteral(namespace + ":" + literal, node);
|
||||
|
||||
final Set<String> registeredLabels = new HashSet<>(aliases.size() * 2 + 2);
|
||||
|
||||
@@ -111,27 +114,27 @@ public class PaperCommands implements Commands, PaperRegistrar<LifecycleEventOwn
|
||||
if (this.registerCopy(alias, pluginLiteral, meta)) {
|
||||
registeredAliases.add(alias);
|
||||
}
|
||||
if (this.registerCopy(identifier + ":" + alias, pluginLiteral, meta)) {
|
||||
registeredAliases.add(identifier + ":" + alias);
|
||||
if (this.registerCopy(namespace + ":" + alias, pluginLiteral, meta)) {
|
||||
registeredAliases.add(namespace + ":" + alias);
|
||||
}
|
||||
}
|
||||
|
||||
pluginLiteral.pluginCommandMeta = new PluginCommandMeta(pluginMeta, description, registeredAliases);
|
||||
node.pluginCommandMeta = pluginLiteral.pluginCommandMeta;
|
||||
pluginLiteral.apiCommandMeta = meta.withAliases(registeredAliases);
|
||||
node.apiCommandMeta = pluginLiteral.apiCommandMeta;
|
||||
|
||||
registeredLabels.addAll(registeredAliases);
|
||||
return registeredLabels.isEmpty() ? Collections.emptySet() : Collections.unmodifiableSet(registeredLabels);
|
||||
}
|
||||
|
||||
private boolean registerCopy(final String aliasLiteral, final LiteralCommandNode<CommandSourceStack> redirectTo, final PluginCommandMeta meta) {
|
||||
private boolean registerCopy(final String aliasLiteral, final LiteralCommandNode<CommandSourceStack> redirectTo, final APICommandMeta meta) {
|
||||
final LiteralCommandNode<CommandSourceStack> node = PaperBrigadier.copyLiteral(aliasLiteral, redirectTo);
|
||||
node.pluginCommandMeta = meta;
|
||||
node.apiCommandMeta = meta;
|
||||
return this.registerIntoDispatcher(node, false);
|
||||
}
|
||||
|
||||
private boolean registerIntoDispatcher(final LiteralCommandNode<CommandSourceStack> node, boolean override) {
|
||||
final CommandNode<CommandSourceStack> existingChild = this.getDispatcher().getRoot().getChild(node.getLiteral());
|
||||
if (existingChild != null && existingChild.pluginCommandMeta == null && !(existingChild instanceof BukkitCommandNode)) {
|
||||
if (existingChild != null && existingChild.apiCommandMeta == null && !(existingChild instanceof BukkitCommandNode)) {
|
||||
override = true; // override vanilla commands
|
||||
}
|
||||
if (existingChild == null || override) { // Avoid merging behavior. Maybe something to look into in the future
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package io.papermc.paper.command.brigadier;
|
||||
|
||||
import io.papermc.paper.plugin.configuration.PluginMeta;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public record PluginCommandMeta(PluginMeta pluginMeta, @Nullable String description, List<String> aliases) {
|
||||
|
||||
public PluginCommandMeta(final PluginMeta pluginMeta, final @Nullable String description) {
|
||||
this(pluginMeta, description, Collections.emptyList());
|
||||
}
|
||||
|
||||
public PluginCommandMeta {
|
||||
aliases = List.copyOf(aliases);
|
||||
}
|
||||
|
||||
public Plugin plugin() {
|
||||
return Objects.requireNonNull(Bukkit.getPluginManager().getPlugin(this.pluginMeta.getName()));
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ public class PluginVanillaCommandWrapper extends VanillaCommandWrapper implement
|
||||
private final List<String> aliases;
|
||||
|
||||
public PluginVanillaCommandWrapper(String name, String description, String usageMessage, List<String> aliases, CommandNode<CommandSourceStack> vanillaCommand, Plugin plugin) {
|
||||
super(name, description, usageMessage, aliases, vanillaCommand);
|
||||
super(name, description, usageMessage, aliases, vanillaCommand, null);
|
||||
this.plugin = plugin;
|
||||
this.aliases = aliases;
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ import org.bukkit.block.structure.Mirror;
|
||||
import org.bukkit.block.structure.StructureRotation;
|
||||
import org.bukkit.craftbukkit.CraftHeightMap;
|
||||
import org.bukkit.craftbukkit.CraftRegistry;
|
||||
import org.bukkit.craftbukkit.block.CraftBlockEntityState;
|
||||
import org.bukkit.craftbukkit.block.CraftBlockStates;
|
||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.scoreboard.CraftCriteria;
|
||||
@@ -172,7 +173,11 @@ public class VanillaArgumentProviderImpl implements VanillaArgumentProvider {
|
||||
@Override
|
||||
public ArgumentType<BlockState> blockState() {
|
||||
return this.wrap(BlockStateArgument.block(PaperCommands.INSTANCE.getBuildContext()), (result) -> {
|
||||
return CraftBlockStates.getBlockState(CraftRegistry.getMinecraftRegistry(), BlockPos.ZERO, result.getState(), result.tag);
|
||||
final BlockState snapshot = CraftBlockStates.getBlockState(CraftRegistry.getMinecraftRegistry(), BlockPos.ZERO, result.getState(), null);
|
||||
if (result.tag != null && snapshot instanceof final CraftBlockEntityState<?> blockEntitySnapshot) {
|
||||
blockEntitySnapshot.loadData(result.tag);
|
||||
}
|
||||
return snapshot;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public class BukkitBrigForwardingMap extends HashMap<String, Command> {
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.size() != 0;
|
||||
return this.size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -10,9 +10,10 @@ import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||
import java.util.ArrayList;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minecraft.commands.CommandSource;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandException;
|
||||
@@ -107,7 +108,7 @@ public class BukkitCommandNode extends LiteralCommandNode<CommandSourceStack> {
|
||||
try {
|
||||
results = this.command.tabComplete(sender, this.literal, args, pos.clone());
|
||||
} catch (CommandException ex) {
|
||||
sender.sendMessage(ChatColor.RED + "An internal error occurred while attempting to tab-complete this command");
|
||||
sender.sendMessage(Component.text("An internal error occurred while attempting to tab-complete this command", NamedTextColor.RED));
|
||||
Bukkit.getServer().getLogger().log(Level.SEVERE, "Exception when " + sender.getName() + " attempted to tab complete " + builder.getRemaining(), ex);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@ package io.papermc.paper.command.subcommands;
|
||||
|
||||
import com.destroystokyo.paper.util.SneakyThrow;
|
||||
import io.papermc.paper.command.PaperSubcommand;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
@@ -16,6 +17,7 @@ import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@@ -23,6 +25,7 @@ import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.RegisteredListener;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
|
||||
import static net.kyori.adventure.text.Component.newline;
|
||||
@@ -35,6 +38,8 @@ import static net.kyori.adventure.text.format.NamedTextColor.WHITE;
|
||||
|
||||
@DefaultQualifier(NonNull.class)
|
||||
public final class DumpListenersCommand implements PaperSubcommand {
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss");
|
||||
private static final String COMMAND_ARGUMENT_TO_FILE = "tofile";
|
||||
private static final MethodHandle EVENT_TYPES_HANDLE;
|
||||
|
||||
static {
|
||||
@@ -49,7 +54,7 @@ public final class DumpListenersCommand implements PaperSubcommand {
|
||||
|
||||
@Override
|
||||
public boolean execute(final CommandSender sender, final String subCommand, final String[] args) {
|
||||
if (args.length >= 1 && args[0].equals("tofile")) {
|
||||
if (args.length >= 1 && args[0].equals(COMMAND_ARGUMENT_TO_FILE)) {
|
||||
this.dumpToFile(sender);
|
||||
return true;
|
||||
}
|
||||
@@ -58,45 +63,69 @@ public final class DumpListenersCommand implements PaperSubcommand {
|
||||
}
|
||||
|
||||
private void dumpToFile(final CommandSender sender) {
|
||||
final File file = new File("debug/listeners-"
|
||||
+ DateTimeFormatter.ofPattern("yyyy-MM-dd_HH.mm.ss").format(LocalDateTime.now()) + ".txt");
|
||||
file.getParentFile().mkdirs();
|
||||
try (final PrintWriter writer = new PrintWriter(file)) {
|
||||
for (final String eventClass : eventClassNames()) {
|
||||
final HandlerList handlers;
|
||||
try {
|
||||
handlers = (HandlerList) findClass(eventClass).getMethod("getHandlerList").invoke(null);
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
continue;
|
||||
}
|
||||
if (handlers.getRegisteredListeners().length != 0) {
|
||||
writer.println(eventClass);
|
||||
}
|
||||
for (final RegisteredListener registeredListener : handlers.getRegisteredListeners()) {
|
||||
writer.println(" - " + registeredListener);
|
||||
Path parent = Path.of("debug");
|
||||
Path path = parent.resolve("listeners-" + FORMATTER.format(LocalDateTime.now()) + ".txt");
|
||||
sender.sendMessage(
|
||||
text("Writing listeners into directory", GREEN)
|
||||
.appendSpace()
|
||||
.append(
|
||||
text(parent.toString(), WHITE)
|
||||
.hoverEvent(text("Click to copy the full path of debug directory", WHITE))
|
||||
.clickEvent(ClickEvent.copyToClipboard(parent.toAbsolutePath().toString()))
|
||||
)
|
||||
);
|
||||
try {
|
||||
Files.createDirectories(parent);
|
||||
Files.createFile(path);
|
||||
try (final PrintWriter writer = new PrintWriter(path.toFile())){
|
||||
for (final String eventClass : eventClassNames()) {
|
||||
final HandlerList handlers;
|
||||
try {
|
||||
handlers = (HandlerList) findClass(eventClass).getMethod("getHandlerList").invoke(null);
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
continue;
|
||||
}
|
||||
if (handlers.getRegisteredListeners().length != 0) {
|
||||
writer.println(eventClass);
|
||||
}
|
||||
for (final RegisteredListener registeredListener : handlers.getRegisteredListeners()) {
|
||||
writer.println(" - " + registeredListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
sender.sendMessage(text("Failed to write dumped listener! See the console for more info.", RED));
|
||||
MinecraftServer.LOGGER.warn("Error occurred while dumping listeners", ex);
|
||||
return;
|
||||
}
|
||||
sender.sendMessage(text("Dumped listeners to " + file, GREEN));
|
||||
sender.sendMessage(
|
||||
text("Successfully written listeners into", GREEN)
|
||||
.appendSpace()
|
||||
.append(
|
||||
text(path.toString(), WHITE)
|
||||
.hoverEvent(text("Click to copy the full path of the file", WHITE))
|
||||
.clickEvent(ClickEvent.copyToClipboard(path.toAbsolutePath().toString()))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private void doDumpListeners(final CommandSender sender, final String[] args) {
|
||||
if (args.length == 0) {
|
||||
sender.sendMessage(text("Usage: /paper dumplisteners tofile|<className>", RED));
|
||||
sender.sendMessage(text("Usage: /paper dumplisteners " + COMMAND_ARGUMENT_TO_FILE + "|<className>", RED));
|
||||
return;
|
||||
}
|
||||
|
||||
final String className = args[0];
|
||||
|
||||
try {
|
||||
final HandlerList handlers = (HandlerList) findClass(args[0]).getMethod("getHandlerList").invoke(null);
|
||||
final HandlerList handlers = (HandlerList) findClass(className).getMethod("getHandlerList").invoke(null);
|
||||
|
||||
if (handlers.getRegisteredListeners().length == 0) {
|
||||
sender.sendMessage(text(args[0] + " does not have any registered listeners."));
|
||||
sender.sendMessage(text(className + " does not have any registered listeners."));
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendMessage(text("Listeners for " + args[0] + ":"));
|
||||
sender.sendMessage(text("Listeners for " + className + ":"));
|
||||
|
||||
for (final RegisteredListener listener : handlers.getRegisteredListeners()) {
|
||||
final Component hoverText = text("Priority: " + listener.getPriority().name() + " (" + listener.getPriority().getSlot() + ")", WHITE)
|
||||
@@ -115,12 +144,12 @@ public final class DumpListenersCommand implements PaperSubcommand {
|
||||
sender.sendMessage(text("Total listeners: " + handlers.getRegisteredListeners().length));
|
||||
|
||||
} catch (final ClassNotFoundException e) {
|
||||
sender.sendMessage(text("Unable to find a class named '" + args[0] + "'. Make sure to use the fully qualified name.", RED));
|
||||
sender.sendMessage(text("Unable to find a class named '" + className + "'. Make sure to use the fully qualified name.", RED));
|
||||
} catch (final NoSuchMethodException e) {
|
||||
sender.sendMessage(text("Class '" + args[0] + "' does not have a valid getHandlerList method.", RED));
|
||||
sender.sendMessage(text("Class '" + className + "' does not have a valid getHandlerList method.", RED));
|
||||
} catch (final ReflectiveOperationException e) {
|
||||
sender.sendMessage(text("Something went wrong, see the console for more details.", RED));
|
||||
MinecraftServer.LOGGER.warn("Error occurred while dumping listeners for class " + args[0], e);
|
||||
MinecraftServer.LOGGER.warn("Error occurred while dumping listeners for class {}", className, e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +166,7 @@ public final class DumpListenersCommand implements PaperSubcommand {
|
||||
|
||||
private static List<String> suggestions() {
|
||||
final List<String> ret = new ArrayList<>();
|
||||
ret.add("tofile");
|
||||
ret.add(COMMAND_ARGUMENT_TO_FILE);
|
||||
ret.addAll(eventClassNames());
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.Strictness;
|
||||
import com.google.gson.internal.Streams;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import io.papermc.paper.command.PaperSubcommand;
|
||||
@@ -15,7 +16,6 @@ import io.papermc.paper.plugin.entrypoint.classloader.group.PaperPluginClassLoad
|
||||
import io.papermc.paper.plugin.entrypoint.classloader.group.SimpleListPluginClassLoaderGroup;
|
||||
import io.papermc.paper.plugin.entrypoint.classloader.group.SpigotPluginClassLoaderGroup;
|
||||
import io.papermc.paper.plugin.entrypoint.classloader.group.StaticPluginClassLoaderGroup;
|
||||
import io.papermc.paper.plugin.entrypoint.dependency.GraphDependencyContext;
|
||||
import io.papermc.paper.plugin.entrypoint.dependency.SimpleMetaDependencyTree;
|
||||
import io.papermc.paper.plugin.provider.entrypoint.DependencyContext;
|
||||
import io.papermc.paper.plugin.entrypoint.strategy.modern.ModernPluginLoadingStrategy;
|
||||
@@ -27,12 +27,14 @@ import io.papermc.paper.plugin.provider.classloader.PaperClassLoaderStorage;
|
||||
import io.papermc.paper.plugin.provider.classloader.PluginClassLoaderGroup;
|
||||
import io.papermc.paper.plugin.storage.ConfiguredProviderStorage;
|
||||
import io.papermc.paper.plugin.storage.ProviderStorage;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.framework.qual.DefaultQualifier;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -47,6 +49,7 @@ import java.util.Map;
|
||||
import static net.kyori.adventure.text.Component.text;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.GREEN;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.RED;
|
||||
import static net.kyori.adventure.text.format.NamedTextColor.WHITE;
|
||||
|
||||
@DefaultQualifier(NonNull.class)
|
||||
public final class DumpPluginsCommand implements PaperSubcommand {
|
||||
@@ -60,24 +63,40 @@ public final class DumpPluginsCommand implements PaperSubcommand {
|
||||
|
||||
private void dumpPlugins(final CommandSender sender, final String[] args) {
|
||||
Path parent = Path.of("debug");
|
||||
Path path = parent.resolve("plugin-info-" + FORMATTER.format(LocalDateTime.now()) + ".txt");
|
||||
Path path = parent.resolve("plugin-info-" + FORMATTER.format(LocalDateTime.now()) + ".json");
|
||||
try {
|
||||
Files.createDirectories(parent);
|
||||
Files.createFile(path);
|
||||
sender.sendMessage(text("Writing plugin information to " + path, GREEN));
|
||||
sender.sendMessage(
|
||||
text("Writing plugin information into directory", GREEN)
|
||||
.appendSpace()
|
||||
.append(
|
||||
text(parent.toString(), WHITE)
|
||||
.hoverEvent(text("Click to copy the full path of debug directory", WHITE))
|
||||
.clickEvent(ClickEvent.copyToClipboard(parent.toAbsolutePath().toString()))
|
||||
)
|
||||
);
|
||||
|
||||
final JsonObject data = this.writeDebug();
|
||||
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
JsonWriter jsonWriter = new JsonWriter(stringWriter);
|
||||
jsonWriter.setIndent(" ");
|
||||
jsonWriter.setLenient(false);
|
||||
jsonWriter.setStrictness(Strictness.STRICT);
|
||||
Streams.write(data, jsonWriter);
|
||||
|
||||
try (PrintStream out = new PrintStream(Files.newOutputStream(path), false, StandardCharsets.UTF_8)) {
|
||||
out.print(stringWriter);
|
||||
}
|
||||
sender.sendMessage(text("Successfully written plugin debug information!", GREEN));
|
||||
sender.sendMessage(
|
||||
text("Successfully written plugin debug information into", GREEN)
|
||||
.appendSpace()
|
||||
.append(
|
||||
text(path.toString(), WHITE)
|
||||
.hoverEvent(text("Click to copy the full path of the file", WHITE))
|
||||
.clickEvent(ClickEvent.copyToClipboard(path.toAbsolutePath().toString()))
|
||||
)
|
||||
);
|
||||
} catch (Throwable e) {
|
||||
sender.sendMessage(text("Failed to write plugin information! See the console for more info.", RED));
|
||||
MinecraftServer.LOGGER.warn("Error occurred while dumping plugin info", e);
|
||||
@@ -97,6 +116,7 @@ public final class DumpPluginsCommand implements PaperSubcommand {
|
||||
return root;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void writeProviders(JsonObject root) {
|
||||
JsonObject rootProviders = new JsonObject();
|
||||
root.add("providers", rootProviders);
|
||||
@@ -116,7 +136,6 @@ public final class DumpPluginsCommand implements PaperSubcommand {
|
||||
providerObj.addProperty("soft-dependencies", provider.getMeta().getPluginSoftDependencies().toString());
|
||||
providerObj.addProperty("load-before", provider.getMeta().getLoadBeforePlugins().toString());
|
||||
|
||||
|
||||
providers.add(providerObj);
|
||||
pluginProviders.add((PluginProvider<Object>) provider);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,8 @@ public abstract class Configurations<G, W> {
|
||||
protected ObjectMapper.Factory.Builder createObjectMapper() {
|
||||
return ObjectMapper.factoryBuilder()
|
||||
.addConstraint(Constraint.class, new Constraint.Factory())
|
||||
.addConstraint(Constraints.Min.class, Number.class, new Constraints.Min.Factory());
|
||||
.addConstraint(Constraints.Min.class, Number.class, new Constraints.Min.Factory())
|
||||
.addConstraint(Constraints.Max.class, Number.class, new Constraints.Max.Factory());
|
||||
}
|
||||
|
||||
protected YamlConfigurationLoader.Builder createLoaderBuilder() {
|
||||
|
||||
@@ -185,8 +185,6 @@ public class GlobalConfiguration extends ConfigurationPart {
|
||||
public CompressionFormat compressionFormat = CompressionFormat.ZLIB;
|
||||
@Comment("This setting controls if equipment should be updated when handling certain player actions.")
|
||||
public boolean updateEquipmentOnPlayerActions = true;
|
||||
@Comment("Only checks an item's amount and type instead of its full data during inventory desync checks.")
|
||||
public boolean simplifyRemoteItemMatching = false;
|
||||
|
||||
public enum CompressionFormat {
|
||||
GZIP,
|
||||
@@ -356,6 +354,9 @@ public class GlobalConfiguration extends ConfigurationPart {
|
||||
public IntOr.Default compressionLevel = IntOr.Default.USE_DEFAULT;
|
||||
@Comment("Defines the leniency distance added on the server to the interaction range of a player when validating interact packets.")
|
||||
public DoubleOr.Default clientInteractionLeniencyDistance = DoubleOr.Default.USE_DEFAULT;
|
||||
@Comment("Defines how many orbs groups can exist in an area.")
|
||||
@Constraints.Min(1)
|
||||
public IntOr.Default xpOrbGroupsPerArea = IntOr.Default.USE_DEFAULT;
|
||||
}
|
||||
|
||||
public BlockUpdates blockUpdates;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package io.papermc.paper.configuration;
|
||||
|
||||
public class PaperServerConfiguration implements ServerConfiguration {
|
||||
|
||||
@Override
|
||||
public boolean isProxyOnlineMode() {
|
||||
return GlobalConfiguration.get().proxies.isProxyOnlineMode();
|
||||
}
|
||||
}
|
||||
@@ -40,4 +40,22 @@ public final class Constraints {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
public @interface Max {
|
||||
int value();
|
||||
|
||||
final class Factory implements Constraint.Factory<Max, Number> {
|
||||
@Override
|
||||
public Constraint<Number> make(Max data, Type type) {
|
||||
return value -> {
|
||||
if (value != null && value.intValue() > data.value()) {
|
||||
throw new SerializationException(value + " is greater than the max " + data.value());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,13 @@ package io.papermc.paper.datacomponent.item;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.datacomponent.item.blocksattacks.DamageReduction;
|
||||
import io.papermc.paper.datacomponent.item.blocksattacks.ItemDamageFunction;
|
||||
import io.papermc.paper.datacomponent.item.blocksattacks.PaperDamageReduction;
|
||||
import io.papermc.paper.datacomponent.item.blocksattacks.PaperItemDamageFunction;
|
||||
import io.papermc.paper.registry.PaperRegistries;
|
||||
import io.papermc.paper.registry.tag.TagKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import net.kyori.adventure.key.Key;
|
||||
@@ -30,6 +35,16 @@ public record PaperBlocksAttacks(
|
||||
return this.impl.disableCooldownScale();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DamageReduction> damageReductions() {
|
||||
return this.impl.damageReductions().stream().map(PaperDamageReduction::new).map(paperDamageReduction -> ((DamageReduction) paperDamageReduction)).toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDamageFunction itemDamage() {
|
||||
return new PaperItemDamageFunction(this.impl.itemDamage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable TagKey<DamageType> bypassedBy() {
|
||||
final Optional<TagKey<DamageType>> tagKey = this.impl.bypassedBy().map(PaperRegistries::fromNms);
|
||||
@@ -50,8 +65,8 @@ public record PaperBlocksAttacks(
|
||||
|
||||
private float blockDelaySeconds;
|
||||
private float disableCooldownScale = 1.0F;
|
||||
//private List<DamageReduction> damageReductions = List.of();
|
||||
//private ItemDamageFunction itemDamage = ItemDamageFunction.DEFAULT;
|
||||
private List<DamageReduction> damageReductions = new ArrayList<>();
|
||||
private ItemDamageFunction itemDamage = new PaperItemDamageFunction(net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction.DEFAULT);
|
||||
private @Nullable TagKey<DamageType> bypassedBy;
|
||||
private @Nullable Key blockSound;
|
||||
private @Nullable Key disableSound;
|
||||
@@ -70,15 +85,18 @@ public record PaperBlocksAttacks(
|
||||
return this;
|
||||
}
|
||||
|
||||
//@Override
|
||||
//public Builder addDamageReduction(final DamageReduction reduction) {
|
||||
// return null;
|
||||
//}
|
||||
@Override
|
||||
public Builder addDamageReduction(final DamageReduction reduction) {
|
||||
Preconditions.checkArgument(reduction.horizontalBlockingAngle() >= 0, "horizontalBlockingAngle must be non-negative, was %s", reduction.horizontalBlockingAngle());
|
||||
this.damageReductions.add(reduction);
|
||||
return this;
|
||||
}
|
||||
|
||||
//@Override
|
||||
//public Builder itemDamage(final ItemDamageFunction function) {
|
||||
// return null;
|
||||
//}
|
||||
@Override
|
||||
public Builder itemDamage(final ItemDamageFunction function) {
|
||||
this.itemDamage = function;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder bypassedBy(@Nullable final TagKey<DamageType> bypassedBy) {
|
||||
@@ -98,18 +116,19 @@ public record PaperBlocksAttacks(
|
||||
return this;
|
||||
}
|
||||
|
||||
//@Override
|
||||
//public Builder damageReductions(final List<DamageReduction> reductions) {
|
||||
// return null;
|
||||
//}
|
||||
@Override
|
||||
public Builder damageReductions(final List<DamageReduction> reductions) {
|
||||
this.damageReductions = new ArrayList<>(reductions);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlocksAttacks build() {
|
||||
return new PaperBlocksAttacks(new net.minecraft.world.item.component.BlocksAttacks(
|
||||
this.blockDelaySeconds,
|
||||
this.disableCooldownScale,
|
||||
List.of(), // TODO
|
||||
net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction.DEFAULT, // TODO
|
||||
this.damageReductions.stream().map(damageReduction -> ((PaperDamageReduction) damageReduction).getHandle()).toList(),
|
||||
((PaperItemDamageFunction) itemDamage).getHandle(),
|
||||
Optional.ofNullable(this.bypassedBy).map(PaperRegistries::toNms),
|
||||
Optional.ofNullable(this.blockSound).map(PaperAdventure::resolveSound),
|
||||
Optional.ofNullable(this.disableSound).map(PaperAdventure::resolveSound)
|
||||
|
||||
@@ -5,6 +5,8 @@ import io.papermc.paper.util.MCUtil;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.craftbukkit.potion.CraftPotionType;
|
||||
@@ -48,6 +50,19 @@ public record PaperPotionContents(
|
||||
return this.impl.customName().orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Unmodifiable List<PotionEffect> allEffects() {
|
||||
//noinspection SimplifyStreamApiCallChains - explicity want it unmodifiable, as toList() api doesnt guarantee this.
|
||||
return StreamSupport.stream(this.impl.getAllEffects().spliterator(), false)
|
||||
.map(CraftPotionUtil::toBukkit)
|
||||
.collect(Collectors.toUnmodifiableList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color computeEffectiveColor() {
|
||||
return Color.fromARGB(this.impl.getColor());
|
||||
}
|
||||
|
||||
static final class BuilderImpl implements PotionContents.Builder {
|
||||
|
||||
private final List<MobEffectInstance> customEffects = new ObjectArrayList<>();
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package io.papermc.paper.datacomponent.item.blocksattacks;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
@ApiStatus.Internal
|
||||
@NullMarked
|
||||
public class BlocksAttacksBridgeImpl implements BlocksAttacksBridge {
|
||||
|
||||
@Override
|
||||
public DamageReduction.Builder blocksAttacksDamageReduction() {
|
||||
return new PaperDamageReduction.BuilderImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDamageFunction.Builder blocksAttacksItemDamageFunction() {
|
||||
return new PaperItemDamageFunction.BuilderImpl();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package io.papermc.paper.datacomponent.item.blocksattacks;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import io.papermc.paper.registry.RegistryKey;
|
||||
import io.papermc.paper.registry.set.PaperRegistrySets;
|
||||
import io.papermc.paper.registry.set.RegistryKeySet;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import org.bukkit.craftbukkit.util.Handleable;
|
||||
import org.bukkit.damage.DamageType;
|
||||
import org.checkerframework.checker.index.qual.Positive;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import java.util.Optional;
|
||||
|
||||
public record PaperDamageReduction(
|
||||
net.minecraft.world.item.component.BlocksAttacks.DamageReduction impl
|
||||
) implements DamageReduction, Handleable<net.minecraft.world.item.component.BlocksAttacks.DamageReduction> {
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.item.component.BlocksAttacks.DamageReduction getHandle() {
|
||||
return this.impl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable RegistryKeySet<DamageType> type() {
|
||||
return this.impl.type().map((set) -> PaperRegistrySets.convertToApi(RegistryKey.DAMAGE_TYPE, set)).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Positive float horizontalBlockingAngle() {
|
||||
return this.impl.horizontalBlockingAngle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float base() {
|
||||
return this.impl.base();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float factor() {
|
||||
return this.impl.factor();
|
||||
}
|
||||
|
||||
static final class BuilderImpl implements Builder {
|
||||
|
||||
private Optional<HolderSet<net.minecraft.world.damagesource.DamageType>> type = Optional.empty();
|
||||
private float horizontalBlockingAngle = 90f;
|
||||
private float base = 0;
|
||||
private float factor = 0;
|
||||
|
||||
@Override
|
||||
public Builder type(final @Nullable RegistryKeySet<DamageType> type) {
|
||||
this.type = Optional.ofNullable(type)
|
||||
.map((set) -> PaperRegistrySets.convertToNms(Registries.DAMAGE_TYPE, net.minecraft.server.MinecraftServer.getServer().registryAccess().createSerializationContext(net.minecraft.nbt.NbtOps.INSTANCE).lookupProvider, set));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder horizontalBlockingAngle(@Positive final float horizontalBlockingAngle) {
|
||||
Preconditions.checkArgument(horizontalBlockingAngle > 0, "horizontalBlockingAngle must be positive and not zero, was %s", horizontalBlockingAngle);
|
||||
this.horizontalBlockingAngle = horizontalBlockingAngle;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder base(final float base) {
|
||||
this.base = base;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder factor(final float factor) {
|
||||
this.factor = factor;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DamageReduction build() {
|
||||
return new PaperDamageReduction(new net.minecraft.world.item.component.BlocksAttacks.DamageReduction(
|
||||
this.horizontalBlockingAngle,
|
||||
this.type,
|
||||
this.base,
|
||||
this.factor
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package io.papermc.paper.datacomponent.item.blocksattacks;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.bukkit.craftbukkit.util.Handleable;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
|
||||
public record PaperItemDamageFunction(
|
||||
net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction impl
|
||||
) implements ItemDamageFunction, Handleable<net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction> {
|
||||
|
||||
@Override
|
||||
public net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction getHandle() {
|
||||
return this.impl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNegative float threshold() {
|
||||
return this.impl.threshold();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float base() {
|
||||
return this.impl.base();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float factor() {
|
||||
return this.impl.factor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int damageToApply(final float damage) {
|
||||
return this.impl.apply(damage);
|
||||
}
|
||||
|
||||
static final class BuilderImpl implements Builder {
|
||||
|
||||
private float threshold;
|
||||
private float base;
|
||||
private float factor;
|
||||
|
||||
@Override
|
||||
public Builder threshold(@NonNegative final float threshold) {
|
||||
Preconditions.checkArgument(threshold >= 0, "threshold must be non-negative, was %s", threshold);
|
||||
this.threshold = threshold;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder base(final float base) {
|
||||
this.base = base;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder factor(final float factor) {
|
||||
this.factor = factor;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemDamageFunction build() {
|
||||
return new PaperItemDamageFunction(new net.minecraft.world.item.component.BlocksAttacks.ItemDamageFunction(
|
||||
this.threshold,
|
||||
this.base,
|
||||
this.factor
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Relating to block attacks for components.
|
||||
*/
|
||||
@NullMarked
|
||||
package io.papermc.paper.datacomponent.item.blocksattacks;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
@@ -13,7 +13,7 @@ public class PaperSchoolableFish extends CraftFish implements SchoolableFish {
|
||||
|
||||
@Override
|
||||
public AbstractSchoolingFish getHandle() {
|
||||
return (AbstractSchoolingFish) super.getHandle();
|
||||
return (AbstractSchoolingFish) this.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -75,7 +75,11 @@ public final class PluginRemapper {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new PluginRemapper(pluginsDir);
|
||||
try {
|
||||
return new PluginRemapper(pluginsDir);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException("Failed to create PluginRemapper, try deleting the '" + pluginsDir.resolve(PAPER_REMAPPED) + "' directory", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
|
||||
@@ -8,6 +8,7 @@ import io.papermc.paper.util.MappingEnvironment;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@@ -52,32 +53,35 @@ class RemappedPluginIndex {
|
||||
try {
|
||||
Files.createDirectories(this.dir);
|
||||
} catch (final IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
this.indexFile = dir.resolve(INDEX_FILE_NAME);
|
||||
if (Files.isRegularFile(this.indexFile)) {
|
||||
try {
|
||||
this.state = this.readIndex();
|
||||
} catch (final IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.state = this.readIndex();
|
||||
} else {
|
||||
this.state = new State();
|
||||
}
|
||||
}
|
||||
|
||||
private State readIndex() throws IOException {
|
||||
private State readIndex() {
|
||||
final State state;
|
||||
try (final BufferedReader reader = Files.newBufferedReader(this.indexFile)) {
|
||||
state = GSON.fromJson(reader, State.class);
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException("Failed to read index file '" + this.indexFile + "'", ex);
|
||||
}
|
||||
|
||||
// If mappings have changed, delete all cached files and create a new index
|
||||
if (!state.mappingsHash.equals(MappingEnvironment.mappingsHash())) {
|
||||
for (final String fileName : state.hashes.values()) {
|
||||
Files.deleteIfExists(this.dir.resolve(fileName));
|
||||
final Path path = this.dir.resolve(fileName);
|
||||
try {
|
||||
Files.deleteIfExists(path);
|
||||
} catch (final IOException ex) {
|
||||
throw new UncheckedIOException("Failed to delete no longer needed file '" + path + "'", ex);
|
||||
}
|
||||
}
|
||||
return new State();
|
||||
}
|
||||
@@ -111,10 +115,11 @@ class RemappedPluginIndex {
|
||||
}
|
||||
|
||||
iterator.remove();
|
||||
final Path filePath = this.dir.resolve(fileName);
|
||||
try {
|
||||
Files.deleteIfExists(this.dir.resolve(fileName));
|
||||
Files.deleteIfExists(filePath);
|
||||
} catch (final IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
throw new UncheckedIOException("Failed to delete no longer needed file '" + filePath + "'", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,16 @@ import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.datacomponent.DataComponentTypes;
|
||||
import io.papermc.paper.datacomponent.PaperDataComponentType;
|
||||
import io.papermc.paper.registry.data.PaperBannerPatternRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperCatTypeRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperChickenVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperCowVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperDamageTypeRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperEnchantmentRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperFrogVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperGameEventRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperPaintingVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperPigVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.data.PaperWolfVariantRegistryEntry;
|
||||
import io.papermc.paper.registry.entry.RegistryEntry;
|
||||
import io.papermc.paper.registry.entry.RegistryEntryMeta;
|
||||
import io.papermc.paper.registry.tag.TagKey;
|
||||
@@ -111,18 +117,18 @@ public final class PaperRegistries {
|
||||
start(Registries.TRIM_MATERIAL, RegistryKey.TRIM_MATERIAL).craft(TrimMaterial.class, CraftTrimMaterial::new, true).build().delayed(),
|
||||
start(Registries.TRIM_PATTERN, RegistryKey.TRIM_PATTERN).craft(TrimPattern.class, CraftTrimPattern::new, true).build().delayed(),
|
||||
start(Registries.DAMAGE_TYPE, RegistryKey.DAMAGE_TYPE).craft(DamageType.class, CraftDamageType::new).writable(PaperDamageTypeRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT).craft(Wolf.Variant.class, CraftWolf.CraftVariant::new).build().delayed(),
|
||||
start(Registries.WOLF_VARIANT, RegistryKey.WOLF_VARIANT).craft(Wolf.Variant.class, CraftWolf.CraftVariant::new).writable(PaperWolfVariantRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.WOLF_SOUND_VARIANT, RegistryKey.WOLF_SOUND_VARIANT).craft(Wolf.SoundVariant.class, CraftWolf.CraftSoundVariant::new).build(),
|
||||
start(Registries.ENCHANTMENT, RegistryKey.ENCHANTMENT).craft(Enchantment.class, CraftEnchantment::new).serializationUpdater(FieldRename.ENCHANTMENT_RENAME).writable(PaperEnchantmentRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.JUKEBOX_SONG, RegistryKey.JUKEBOX_SONG).craft(JukeboxSong.class, CraftJukeboxSong::new).build().delayed(),
|
||||
start(Registries.BANNER_PATTERN, RegistryKey.BANNER_PATTERN).craft(PatternType.class, CraftPatternType::new, true).writable(PaperBannerPatternRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.PAINTING_VARIANT, RegistryKey.PAINTING_VARIANT).craft(Art.class, CraftArt::new, true).writable(PaperPaintingVariantRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.INSTRUMENT, RegistryKey.INSTRUMENT).craft(MusicInstrument.class, CraftMusicInstrument::new, true).build().delayed(),
|
||||
start(Registries.CAT_VARIANT, RegistryKey.CAT_VARIANT).craft(Cat.Type.class, CraftCat.CraftType::new).build().delayed(),
|
||||
start(Registries.FROG_VARIANT, RegistryKey.FROG_VARIANT).craft(Frog.Variant.class, CraftFrog.CraftVariant::new).build().delayed(),
|
||||
start(Registries.CHICKEN_VARIANT, RegistryKey.CHICKEN_VARIANT).craft(Chicken.Variant.class, CraftChicken.CraftVariant::new).build(),
|
||||
start(Registries.COW_VARIANT, RegistryKey.COW_VARIANT).craft(Cow.Variant.class, CraftCow.CraftVariant::new).build(),
|
||||
start(Registries.PIG_VARIANT, RegistryKey.PIG_VARIANT).craft(Pig.Variant.class, CraftPig.CraftVariant::new).build(),
|
||||
start(Registries.CAT_VARIANT, RegistryKey.CAT_VARIANT).craft(Cat.Type.class, CraftCat.CraftType::new).writable(PaperCatTypeRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.FROG_VARIANT, RegistryKey.FROG_VARIANT).craft(Frog.Variant.class, CraftFrog.CraftVariant::new).writable(PaperFrogVariantRegistryEntry.PaperBuilder::new).delayed(),
|
||||
start(Registries.CHICKEN_VARIANT, RegistryKey.CHICKEN_VARIANT).craft(Chicken.Variant.class, CraftChicken.CraftVariant::new).writable(PaperChickenVariantRegistryEntry.PaperBuilder::new),
|
||||
start(Registries.COW_VARIANT, RegistryKey.COW_VARIANT).craft(Cow.Variant.class, CraftCow.CraftVariant::new).writable(PaperCowVariantRegistryEntry.PaperBuilder::new),
|
||||
start(Registries.PIG_VARIANT, RegistryKey.PIG_VARIANT).craft(Pig.Variant.class, CraftPig.CraftVariant::new).writable(PaperPigVariantRegistryEntry.PaperBuilder::new),
|
||||
|
||||
// api-only
|
||||
start(Registries.ENTITY_TYPE, RegistryKey.ENTITY_TYPE).apiOnly(PaperSimpleRegistry::entityType),
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import net.minecraft.world.entity.animal.CatVariant;
|
||||
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
|
||||
import org.bukkit.entity.Cat;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.asArgument;
|
||||
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
|
||||
public class PaperCatTypeRegistryEntry implements CatTypeRegistryEntry {
|
||||
|
||||
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset;
|
||||
protected SpawnPrioritySelectors spawnConditions;
|
||||
|
||||
protected final Conversions conversions;
|
||||
|
||||
public PaperCatTypeRegistryEntry(
|
||||
final Conversions conversions,
|
||||
final @Nullable CatVariant internal
|
||||
) {
|
||||
this.conversions = conversions;
|
||||
if (internal == null) {
|
||||
this.spawnConditions = SpawnPrioritySelectors.EMPTY;
|
||||
return;
|
||||
}
|
||||
|
||||
this.clientTextureAsset = internal.assetInfo();
|
||||
this.spawnConditions = internal.spawnConditions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset clientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperCatTypeRegistryEntry implements Builder, PaperRegistryBuilder<CatVariant, Cat.Type> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable CatVariant internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
|
||||
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CatVariant build() {
|
||||
return new CatVariant(
|
||||
asConfigured(this.clientTextureAsset, "clientTextureAsset"),
|
||||
asConfigured(this.spawnConditions, "spawnConditions")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import net.minecraft.world.entity.animal.ChickenVariant;
|
||||
import net.minecraft.world.entity.variant.ModelAndTexture;
|
||||
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
|
||||
import org.bukkit.entity.Chicken;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.asArgument;
|
||||
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
|
||||
public class PaperChickenVariantRegistryEntry implements ChickenVariantRegistryEntry {
|
||||
|
||||
protected ChickenVariant.@Nullable ModelType model;
|
||||
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset;
|
||||
protected SpawnPrioritySelectors spawnConditions;
|
||||
|
||||
protected final Conversions conversions;
|
||||
|
||||
public PaperChickenVariantRegistryEntry(
|
||||
final Conversions conversions,
|
||||
final @Nullable ChickenVariant internal
|
||||
) {
|
||||
this.conversions = conversions;
|
||||
if (internal == null) {
|
||||
this.spawnConditions = SpawnPrioritySelectors.EMPTY;
|
||||
return;
|
||||
}
|
||||
|
||||
this.clientTextureAsset = internal.modelAndTexture().asset();
|
||||
this.model = internal.modelAndTexture().model();
|
||||
this.spawnConditions = internal.spawnConditions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset clientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Model model() {
|
||||
return switch (asConfigured(this.model, "model")) {
|
||||
case NORMAL -> Model.NORMAL;
|
||||
case COLD -> Model.COLD;
|
||||
};
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperChickenVariantRegistryEntry implements Builder, PaperRegistryBuilder<ChickenVariant, Chicken.Variant> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable ChickenVariant internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
|
||||
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder model(final Model model) {
|
||||
this.model = switch (asArgument(model, "model")) {
|
||||
case NORMAL -> ChickenVariant.ModelType.NORMAL;
|
||||
case COLD -> ChickenVariant.ModelType.COLD;
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChickenVariant build() {
|
||||
return new ChickenVariant(
|
||||
new ModelAndTexture<>(asConfigured(this.model, "model"), asConfigured(this.clientTextureAsset, "clientTextureAsset")),
|
||||
asConfigured(this.spawnConditions, "spawnConditions")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import net.minecraft.world.entity.animal.CowVariant;
|
||||
import net.minecraft.world.entity.variant.ModelAndTexture;
|
||||
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
|
||||
import org.bukkit.entity.Cow;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.asArgument;
|
||||
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
|
||||
public class PaperCowVariantRegistryEntry implements CowVariantRegistryEntry {
|
||||
|
||||
protected CowVariant.@Nullable ModelType model = null;
|
||||
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset = null;
|
||||
protected SpawnPrioritySelectors spawnConditions;
|
||||
|
||||
protected final Conversions conversions;
|
||||
|
||||
public PaperCowVariantRegistryEntry(
|
||||
final Conversions conversions,
|
||||
final @Nullable CowVariant internal
|
||||
) {
|
||||
this.conversions = conversions;
|
||||
if (internal == null) {
|
||||
this.spawnConditions = SpawnPrioritySelectors.EMPTY;
|
||||
return;
|
||||
}
|
||||
|
||||
this.clientTextureAsset = internal.modelAndTexture().asset();
|
||||
this.model = internal.modelAndTexture().model();
|
||||
this.spawnConditions = internal.spawnConditions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset clientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Model model() {
|
||||
return switch (asConfigured(this.model, "model")) {
|
||||
case NORMAL -> Model.NORMAL;
|
||||
case COLD -> Model.COLD;
|
||||
case WARM -> Model.WARM;
|
||||
};
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperCowVariantRegistryEntry implements Builder, PaperRegistryBuilder<CowVariant, Cow.Variant> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable CowVariant internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
|
||||
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder model(final Model model) {
|
||||
this.model = switch (asArgument(model, "model")) {
|
||||
case NORMAL -> CowVariant.ModelType.NORMAL;
|
||||
case COLD -> CowVariant.ModelType.COLD;
|
||||
case WARM -> CowVariant.ModelType.WARM;
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CowVariant build() {
|
||||
return new CowVariant(
|
||||
new ModelAndTexture<>(asConfigured(this.model, "model"), asConfigured(this.clientTextureAsset, "clientTextureAsset")),
|
||||
this.spawnConditions
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import net.minecraft.world.entity.animal.frog.FrogVariant;
|
||||
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
|
||||
import org.bukkit.entity.Frog;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.asArgument;
|
||||
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
|
||||
public class PaperFrogVariantRegistryEntry implements FrogVariantRegistryEntry {
|
||||
|
||||
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset;
|
||||
protected SpawnPrioritySelectors spawnConditions;
|
||||
|
||||
protected final Conversions conversions;
|
||||
|
||||
public PaperFrogVariantRegistryEntry(
|
||||
final Conversions conversions,
|
||||
final @Nullable FrogVariant internal
|
||||
) {
|
||||
this.conversions = conversions;
|
||||
if (internal == null) {
|
||||
spawnConditions = SpawnPrioritySelectors.EMPTY;
|
||||
return;
|
||||
}
|
||||
|
||||
this.clientTextureAsset = internal.assetInfo();
|
||||
this.spawnConditions = internal.spawnConditions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset clientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperFrogVariantRegistryEntry implements Builder, PaperRegistryBuilder<FrogVariant, Frog.Variant> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable FrogVariant internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
|
||||
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FrogVariant build() {
|
||||
return new FrogVariant(
|
||||
asConfigured(this.clientTextureAsset, "clientTextureAsset"),
|
||||
asConfigured(this.spawnConditions, "spawnConditions")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import net.minecraft.world.entity.animal.PigVariant;
|
||||
import net.minecraft.world.entity.variant.ModelAndTexture;
|
||||
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
|
||||
import org.bukkit.entity.Pig;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.asArgument;
|
||||
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
|
||||
public class PaperPigVariantRegistryEntry implements PigVariantRegistryEntry {
|
||||
|
||||
protected PigVariant.@Nullable ModelType model;
|
||||
protected net.minecraft.core.@Nullable ClientAsset clientTextureAsset;
|
||||
protected SpawnPrioritySelectors spawnConditions;
|
||||
|
||||
protected final Conversions conversions;
|
||||
|
||||
public PaperPigVariantRegistryEntry(
|
||||
final Conversions conversions,
|
||||
final @Nullable PigVariant internal
|
||||
) {
|
||||
this.conversions = conversions;
|
||||
if (internal == null) {
|
||||
spawnConditions = SpawnPrioritySelectors.EMPTY;
|
||||
return;
|
||||
}
|
||||
|
||||
this.clientTextureAsset = internal.modelAndTexture().asset();
|
||||
this.model = internal.modelAndTexture().model();
|
||||
this.spawnConditions = internal.spawnConditions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset clientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.clientTextureAsset, "clientTextureAsset"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Model model() {
|
||||
return switch (asConfigured(this.model, "model")) {
|
||||
case NORMAL -> Model.NORMAL;
|
||||
case COLD -> Model.COLD;
|
||||
};
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperPigVariantRegistryEntry implements Builder, PaperRegistryBuilder<PigVariant, Pig.Variant> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable PigVariant internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder clientTextureAsset(final ClientTextureAsset clientTextureAsset) {
|
||||
this.clientTextureAsset = this.conversions.asVanilla(asArgument(clientTextureAsset, "clientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder model(final Model model) {
|
||||
this.model = switch (asArgument(model, "model")) {
|
||||
case NORMAL -> PigVariant.ModelType.NORMAL;
|
||||
case COLD -> PigVariant.ModelType.COLD;
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PigVariant build() {
|
||||
return new PigVariant(
|
||||
new ModelAndTexture<>(asConfigured(this.model, "model"), asConfigured(this.clientTextureAsset, "clientTextureAsset")),
|
||||
asConfigured(this.spawnConditions, "spawnConditions")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package io.papermc.paper.registry.data;
|
||||
|
||||
import io.papermc.paper.registry.PaperRegistryBuilder;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import io.papermc.paper.registry.data.util.Conversions;
|
||||
import net.minecraft.world.entity.animal.wolf.WolfVariant;
|
||||
import net.minecraft.world.entity.variant.SpawnPrioritySelectors;
|
||||
import org.bukkit.entity.Wolf;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import static io.papermc.paper.registry.data.util.Checks.asArgument;
|
||||
import static io.papermc.paper.registry.data.util.Checks.asConfigured;
|
||||
|
||||
public class PaperWolfVariantRegistryEntry implements WolfVariantRegistryEntry {
|
||||
|
||||
protected net.minecraft.core.@Nullable ClientAsset angryClientTextureAsset;
|
||||
protected net.minecraft.core.@Nullable ClientAsset wildClientTextureAsset;
|
||||
protected net.minecraft.core.@Nullable ClientAsset tameClientTextureAsset;
|
||||
protected SpawnPrioritySelectors spawnConditions;
|
||||
|
||||
protected final Conversions conversions;
|
||||
|
||||
public PaperWolfVariantRegistryEntry(
|
||||
final Conversions conversions,
|
||||
final @Nullable WolfVariant internal
|
||||
) {
|
||||
this.conversions = conversions;
|
||||
if (internal == null) {
|
||||
this.spawnConditions = SpawnPrioritySelectors.EMPTY;
|
||||
return;
|
||||
}
|
||||
|
||||
this.angryClientTextureAsset = internal.assetInfo().angry();
|
||||
this.wildClientTextureAsset = internal.assetInfo().wild();
|
||||
this.tameClientTextureAsset = internal.assetInfo().tame();
|
||||
this.spawnConditions = internal.spawnConditions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset angryClientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.angryClientTextureAsset, "angryClientTextureAsset"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset wildClientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.wildClientTextureAsset, "wildClientTextureAsset"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientTextureAsset tameClientTextureAsset() {
|
||||
return this.conversions.asBukkit(asConfigured(this.tameClientTextureAsset, "tameClientTextureAsset"));
|
||||
}
|
||||
|
||||
public static final class PaperBuilder extends PaperWolfVariantRegistryEntry implements Builder, PaperRegistryBuilder<WolfVariant, Wolf.Variant> {
|
||||
|
||||
public PaperBuilder(final Conversions conversions, final @Nullable WolfVariant internal) {
|
||||
super(conversions, internal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder angryClientTextureAsset(final ClientTextureAsset angryClientTextureAsset) {
|
||||
this.angryClientTextureAsset = this.conversions.asVanilla(asArgument(angryClientTextureAsset, "angryClientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder wildClientTextureAsset(final ClientTextureAsset wildClientTextureAsset) {
|
||||
this.wildClientTextureAsset = this.conversions.asVanilla(asArgument(wildClientTextureAsset, "wildClientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Builder tameClientTextureAsset(final ClientTextureAsset tameClientTextureAsset) {
|
||||
this.tameClientTextureAsset = this.conversions.asVanilla(asArgument(tameClientTextureAsset, "tameClientTextureAsset"));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WolfVariant build() {
|
||||
return new WolfVariant(
|
||||
new WolfVariant.AssetInfo(
|
||||
asConfigured(this.wildClientTextureAsset, "wildClientTextureAsset"),
|
||||
asConfigured(this.tameClientTextureAsset, "tameClientTextureAsset"),
|
||||
asConfigured(this.angryClientTextureAsset, "angryClientTextureAsset")
|
||||
),
|
||||
asConfigured(this.spawnConditions, "spawnConditions")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,10 @@ package io.papermc.paper.registry.data.util;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.mojang.serialization.JavaOps;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import io.papermc.paper.adventure.WrapperAwareSerializer;
|
||||
import java.util.Optional;
|
||||
import io.papermc.paper.registry.data.client.ClientTextureAsset;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
@@ -33,7 +35,6 @@ public class Conversions {
|
||||
return globalInstance;
|
||||
}
|
||||
|
||||
|
||||
private final RegistryOps.RegistryInfoLookup lookup;
|
||||
private final WrapperAwareSerializer serializer;
|
||||
|
||||
@@ -55,4 +56,18 @@ public class Conversions {
|
||||
public Component asAdventure(final net.minecraft.network.chat.@Nullable Component vanilla) {
|
||||
return vanilla == null ? Component.empty() : this.serializer.deserialize(vanilla);
|
||||
}
|
||||
|
||||
public ClientTextureAsset asBukkit(final net.minecraft.core.@Nullable ClientAsset clientTextureAsset) {
|
||||
return clientTextureAsset == null ? null : ClientTextureAsset.clientTextureAsset(
|
||||
PaperAdventure.asAdventure(clientTextureAsset.id()),
|
||||
PaperAdventure.asAdventure(clientTextureAsset.texturePath())
|
||||
);
|
||||
}
|
||||
|
||||
public net.minecraft.core.ClientAsset asVanilla(final @Nullable ClientTextureAsset clientTextureAsset) {
|
||||
return clientTextureAsset == null ? null : new net.minecraft.core.ClientAsset(
|
||||
PaperAdventure.asVanilla(clientTextureAsset.identifier()),
|
||||
PaperAdventure.asVanilla(clientTextureAsset.texturePath())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,18 @@ public final class MCUtil {
|
||||
run.run();
|
||||
}
|
||||
|
||||
public static double sanitizeNanInf(final double value, final double defaultValue) {
|
||||
return Double.isNaN(value) || Double.isInfinite(value) ? defaultValue : value;
|
||||
}
|
||||
|
||||
public static Vec3 sanitizeNanInf(final Vec3 vec3, final double defaultValue) {
|
||||
return new Vec3(
|
||||
sanitizeNanInf(vec3.x, defaultValue),
|
||||
sanitizeNanInf(vec3.y, defaultValue),
|
||||
sanitizeNanInf(vec3.z, defaultValue)
|
||||
);
|
||||
}
|
||||
|
||||
public static <T> T ensureMain(Supplier<T> run) {
|
||||
return ensureMain(null, run);
|
||||
}
|
||||
@@ -140,6 +152,20 @@ public final class MCUtil {
|
||||
return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a NMS World/Vector to Bukkit Location
|
||||
*/
|
||||
public static Location toLocation(Level world, Vec3 pos) {
|
||||
return new Location(world.getWorld(), pos.x(), pos.y(), pos.z());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a NMS World/Vector to Bukkit Location
|
||||
*/
|
||||
public static Location toLocation(Level world, Vec3 pos, float yaw, float pitch) {
|
||||
return new Location(world.getWorld(), pos.x(), pos.y(), pos.z(), yaw, pitch);
|
||||
}
|
||||
|
||||
public static BlockPos toBlockPos(Position pos) {
|
||||
return new BlockPos(pos.blockX(), pos.blockY(), pos.blockZ());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package io.papermc.paper.world.damagesource;
|
||||
|
||||
import net.minecraft.Optionull;
|
||||
import org.bukkit.craftbukkit.damage.CraftDamageSource;
|
||||
import org.bukkit.damage.DamageSource;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public record PaperCombatEntryWrapper(net.minecraft.world.damagesource.CombatEntry handle) implements CombatEntry {
|
||||
|
||||
@Override
|
||||
public DamageSource getDamageSource() {
|
||||
return new CraftDamageSource(this.handle.source());
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDamage() {
|
||||
return this.handle.damage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable FallLocationType getFallLocationType() {
|
||||
return Optionull.map(this.handle.fallLocation(), PaperCombatTrackerWrapper::minecraftToPaper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFallDistance() {
|
||||
return this.handle.fallDistance();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package io.papermc.paper.world.damagesource;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.Optionull;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.world.damagesource.FallLocation;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@NullMarked
|
||||
public record PaperCombatTrackerWrapper(
|
||||
net.minecraft.world.damagesource.CombatTracker handle
|
||||
) implements CombatTracker {
|
||||
|
||||
@Override
|
||||
public LivingEntity getEntity() {
|
||||
return this.handle.mob.getBukkitLivingEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CombatEntry> getCombatEntries() {
|
||||
final List<CombatEntry> combatEntries = new ArrayList<>(this.handle.entries.size());
|
||||
this.handle.entries.forEach(combatEntry -> combatEntries.add(new PaperCombatEntryWrapper(combatEntry)));
|
||||
return combatEntries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCombatEntries(final List<CombatEntry> combatEntries) {
|
||||
this.handle.entries.clear();
|
||||
combatEntries.forEach(combatEntry -> this.handle.entries.add(((PaperCombatEntryWrapper) combatEntry).handle()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable CombatEntry computeMostSignificantFall() {
|
||||
final net.minecraft.world.damagesource.CombatEntry combatEntry = this.handle.getMostSignificantFall();
|
||||
return combatEntry == null ? null : new PaperCombatEntryWrapper(combatEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInCombat() {
|
||||
return this.handle.inCombat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTakingDamage() {
|
||||
return this.handle.takingDamage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCombatDuration() {
|
||||
return this.handle.getCombatDuration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCombatEntry(final CombatEntry combatEntry) {
|
||||
final net.minecraft.world.damagesource.CombatEntry entry = ((PaperCombatEntryWrapper) combatEntry).handle();
|
||||
this.handle.recordDamageAndCheckCombatState(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getDeathMessage() {
|
||||
return PaperAdventure.asAdventure(this.handle.getDeathMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetCombatState() {
|
||||
this.handle.resetCombatState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FallLocationType calculateFallLocationType() {
|
||||
final FallLocation fallLocation = FallLocation.getCurrentFallLocation(this.handle().mob);
|
||||
return Optionull.map(fallLocation, PaperCombatTrackerWrapper::minecraftToPaper);
|
||||
}
|
||||
|
||||
private static final BiMap<FallLocation, FallLocationType> FALL_LOCATION_MAPPING = Util.make(() -> {
|
||||
final BiMap<FallLocation, FallLocationType> map = HashBiMap.create(8);
|
||||
map.put(FallLocation.GENERIC, FallLocationType.GENERIC);
|
||||
map.put(FallLocation.LADDER, FallLocationType.LADDER);
|
||||
map.put(FallLocation.VINES, FallLocationType.VINES);
|
||||
map.put(FallLocation.WEEPING_VINES, FallLocationType.WEEPING_VINES);
|
||||
map.put(FallLocation.TWISTING_VINES, FallLocationType.TWISTING_VINES);
|
||||
map.put(FallLocation.SCAFFOLDING, FallLocationType.SCAFFOLDING);
|
||||
map.put(FallLocation.OTHER_CLIMBABLE, FallLocationType.OTHER_CLIMBABLE);
|
||||
map.put(FallLocation.WATER, FallLocationType.WATER);
|
||||
return map;
|
||||
});
|
||||
|
||||
public static FallLocation paperToMinecraft(final FallLocationType fallLocationType) {
|
||||
final FallLocation fallLocation = FALL_LOCATION_MAPPING.inverse().get(fallLocationType);
|
||||
if (fallLocation == null) {
|
||||
throw new IllegalArgumentException("Unknown fall location type: " + fallLocationType.id());
|
||||
}
|
||||
return fallLocation;
|
||||
}
|
||||
|
||||
public static FallLocationType minecraftToPaper(final FallLocation fallLocation) {
|
||||
final FallLocationType fallLocationType = FALL_LOCATION_MAPPING.get(fallLocation);
|
||||
if (fallLocationType == null) {
|
||||
throw new IllegalArgumentException("Unknown fall location: " + fallLocation.id());
|
||||
}
|
||||
return fallLocationType;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user